SSE向量是"16字节对齐"是什么意思,我该如何确保它?

zee*_*zee 0 c assembly sse

我现在正在使用向量和矩阵,有人建议我应该使用SSE而不是使用float数组.然而,在阅读C内在函数和汇编指令的定义时,看起来有一些函数的不同版本,其中向量必须是"16字节对齐",而较慢的版本,其中向量未对齐.矢量是16字节对齐的意思是什么?如何确保我的向量是16字节对齐的?

zne*_*eak 7

对齐可确保对象在地址上对齐,该地址是2的幂的倍数.16字节对齐意味着地址的数值是16的倍数.对齐很重要,因为CPU通常效率较低或者无法加载没有所需对齐的内存.

您的ABI确定类型的自然对齐.通常,整数类型和浮点类型与它们自己的大小或CPU可以一次处理的那种最大对象的大小对齐,以较小者为准.例如,在64位Intel机器上,32位整数在4个字节上对齐,64位整数在8个字节上对齐,128位整数也在 8个字节上对齐.

结构和联合的对齐与其最对齐的区域相同.这意味着如果您struct包含一个具有2字节对齐的字段和另一个具有8字节对齐的字段,则该结构将对齐到8个字节.

在C++中,您可以alignofsizeof操作符一样使用运算符来获取类型的对齐方式.在C中,当您包含时,相同的构造变为可用<stdalign.h>; 或者,你可以使用_Alignof而不包括任何东西.

AFAIK,没有标准的方法强制对齐成为C或C++中的特定值,但是有特定于编译器的扩展来执行它.在Clang和GCC上,您可以使用以下__attribute__((aligned(N)))属性:

struct s_Stuff {
   int var1;
   short  var2;
   char padding[10];
} __attribute__((aligned(16)));
Run Code Online (Sandbox Code Playgroud)

(例子.)

(此属性将与混淆__attribute__((align(N))),它设置一个的对准变量.)

在我的脑海中,我不确定Visual Studio,但据SoronelHaetir说,那就是__declspec(align(N)).不确定结构声明的位置.

在向量指令的上下文中,对齐很重要,因为人们倾向于创建浮点值数组并对它们进行操作,而不是使用已知对齐的类型.但是,如果您的编译器环境具有它__m128,__m256并且__m512(以及它们的所有变体,例如_m128i等)<emmintrin.h>保证在适当的边界上对齐以与对齐的内部函数一起使用.

根据您的平台,malloc可能会也可能不会返回在矢量对象的正确边界上对齐的内存.aligned_alloc在C11中引入以解决这些问题,但并非所有平台都支持它.

  • Apple:不支持aligned_alloc; malloc返回平台支持的最紧急对齐的对象;
  • Windows:不支持aligned_alloc; malloc返回VC++在没有对齐规范的情况下自然地放置对象的最大对齐上对齐的对象; 使用_aligned_malloc矢量类型
  • Linux:malloc返回在8或16字节边界上对齐的对象; 用aligned_alloc.

一般情况下,可以请求稍微更多的内存并自己执行对齐,只需最小的惩罚(除了您自己编写free类似于函数的函数,它将接受此函数返回的指针):

void* aligned_malloc(size_t size, size_t alignment) {
    intptr_t alignment_mask = alignment - 1;
    void* memory = malloc(size + alignment_mask);
    intptr_t unaligned_ptr = (intptr_t)memory;
    intptr_t aligned_ptr = (unaligned_ptr + alignment_mask) & ~alignment_mask;
    return (void*)aligned_ptr;
}
Run Code Online (Sandbox Code Playgroud)

纯粹主义者可能会认为将指针视为整数是邪恶的,但在撰写本文时,他们可能不会有一个实际的跨平台解决方案来提供交换.