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

时间:2017-12-15 21:17:23

标签: c assembly sse

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

3 个答案:

答案 0 :(得分:7)

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

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

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

在C ++中,您可以像alignof运算符一样使用sizeof运算符来获取类型的对齐方式。在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)));

Example.

(此属性__attribute__((align(N)))混淆,__declspec(align(N))设置变量的对齐方式。)

在我的脑海中,我不确定Visual Studio,according to SoronelHaetir,那将是__m128。不知道它在结构声明中的位置。

在向量指令的上下文中,对齐非常重要,因为人们倾向于创建浮点值数组并对其进行操作,而不是使用已知对齐的类型。但是,__m256__m512_m128i(及其所有变体,如<emmintrin.h>等)来自malloc,如果您的编译器环境具有它,则是aligned_alloc保证在对齐的内在函数上使用适当的边界。

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

  • Apple:不支持aligned_alloc; malloc返回平台支持的最紧急对齐的对象;
  • Windows:不支持malloc; aligned_alloc返回在最大对齐上对齐的对象,VC ++自然会将对象放在没有对齐规范的情况下;将_aligned_malloc用于矢量类型
  • Linux:free返回对象aligned on an 8- or 16-byte boundary;使用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; }

一般情况下,可以请求稍微更多的内存,并以最小的惩罚执行对齐(除了你自己编写一个2,3,4,5,6,7,8,9,11,12,... - 类似的函数,它将接受一个这个函数返回的指针):

10

纯粹主义者可能会认为将指针视为整数是邪恶的,但在撰写本文时,他们可能无法获得实用的跨平台解决方案来提供交换。

答案 1 :(得分:2)

xx-byte alignment意味着变量的存储器地址模xx为0。

确保这是一个特定于编译器的操作,例如visual c ++有__declspec(align(...)),这将适用于编译器分配的变量(例如在文件或函数范围),对齐有点困难对于动态内存,你可以使用aligned_malloc,虽然你的库可能已经保证了malloc的16字节对齐,但通常需要这样调用的是更大的对齐。

答案 2 :(得分:-9)

新修改以改进并集中我对特定查询的回答

为了确保内存中的数据对齐,C中有特定的功能强制执行此操作(假设您的数据兼容 - 您的数据匹配或离散地适合您所需的对齐)

要使用的功能是[_aligned_malloc][1]而不是香草malloc

// Using _aligned_malloc  
// Note alignment should be 2^N where N is any positive int.  
int alignment = 16;
ptr = _aligned_malloc('required_size', alignment);  
if (ptr == NULL)  
{  
    printf_s( "Error allocation aligned memory.");  
    return -1;  
}  

这将(如果成功)强制您的数据在16字节边界上对齐,并且应满足SSE的要求。

旧答案,我对结构成员对齐感到困惑,这很重要 - 但不是直接回答查询

要确保结构成员字节对齐,您可以小心如何在结构中排列成员(最大的第一个),或者可以在编译器设置,成员属性或结构属性中设置此(在某种程度上)。

假设32位机器,4字节整数:这仍然是4字节在内存中对齐(第一个最大成员是4个字节),但填充为16字节大小。

struct s_Stuff {
   int var1;  /* 4 bytes */
   short  var2;  /* 2 bytes */
   char padding[10];  /* ensure totals struct size is 16 */
}

编译器通常会填充每个成员以协助自然对齐,但填充也可能位于结构的末尾。这是 struct member data alignment

较旧的编译器结构成员对齐设置可能类似于下面的这两个图像...但这与数据对齐不同,后者与内存分配和数据存储有关。

From MS Visual Studio 6 C/C++

From Borland 5 C/C++ compiler

当Borland使用短语(来自图像)数据对齐时,它会让我感到困惑,而MS则使用Struct成员对齐。 (虽然它们都是指具体的结构成员对齐)

为了最大限度地提高效率,您需要为硬件编写代码(或者在这种情况下使用矢量处理),因此我们假设32位,4字节整数等。然后您希望使用紧结构来节省空间,但填充结构可能提高速度。

struct s_Stuff {
   float f1;   /* 4 bytes */
   float f2;   /* 4 bytes */
   float f3;   /* 4 bytes */
   short  var2;  /* 2 bytes */
}

这个struct 可能被填充以使结构成员对齐到4字节倍数....编译器将执行此操作,除非您指定它保持单字节 struct member alignment - 所以大小ON FILE可能是14个字节,但仍然在MEMORY中这个结构的数组大小为16个字节(浪费2个字节),未知数据对齐(默认情况下可能是8个字节{{1但是不能保证。如上所述,您可以在某些平台上强制使用malloc在内存中进行数据对齐。

同样关于结构中的_aligned_malloc,编译器将使用最大成员的倍数来设置对齐。或者更具体地说:

  

结构始终与最大类型的对齐方式对齐   要求

...来自here

如果您正在使用UNION,那么您被迫使用最大可能的结构是正确的,请参阅here

检查您的编译器设置是否与您想要的struct member alignment / padding不相矛盾,否则您的结构可能会与您期望的结构大小不同。

现在,为什么它更快?参见here,它解释了对齐如何允许硬件传输离散的数据块,并最大限度地利用传递数据的硬件。也就是说,不需要在每个阶段分割或重新安排数据 - 通过硬件处理

作为一项规则,最好将您的编译器设置为与您的硬件(和平台操作系统)产生共鸣,以便您的对齐(和填充)最适合您的硬件处理能力。 32位机器通常在4字节(32位)成员对齐时效果最佳,但是使用4字节成员对齐写入文件的数据可能会占用比预期更多的空间。

特别是关于SSE向量,作为这个link状态,4 * 4字节是确保16字节对齐的最佳方式,也许就像这样。 (他们在这里引用数据对齐)

member alignment

或只是一个struct s_data { float array[4]; } floats

的数组