2017-10-06 140 views
2

所以我尝试使用SSE函数__mm_load_128,我对SSE fo非常新,如果我在某处犯了一些愚蠢的错误,请原谅我。_declspec(align(16))不会将指针对齐到16字节

这里是Visual Studio中的代码

void one(__m128i *arr, char *temp) 
{ 
    // SSE needs 16 byte alignment. 
    _declspec (align(16)) __m128i *tmp = (__m128i*) temp; 

    if (((uintptr_t)tmp & 15) == 0) 
     printf("Aligned pointer"); 
    else 
     printf("%d", ((uintptr_t)tmp & 15)); // This prints as 12 

    arr[0] = _mm_load_si128(tmp); 
} 

我得到一个错误 0xC0000005: Access violation reading location 0xFFFFFFFF.

0xFFFFFFFF看起来不正确的,我在做什么错。

arr参数初始化为_m128i arr[5] = { 0 }

替代方法是使用_mm_loadu_128其工作正常,但据我所知,这应该产生movdqu指令但这是组件产生

arr[0] = _mm_loadu_si128(tmp); 
00D347F1 mov   eax,dword ptr [tmp] 
00D347F4 movups  xmm0,xmmword ptr [eax] 
00D347F7 movaps  xmmword ptr [ebp-100h],xmm0 
00D347FE mov   ecx,10h 
00D34803 imul  edx,ecx,0 
00D34806 add   edx,dword ptr [arr] 
00D34809 movups  xmm0,xmmword ptr [ebp-100h] 
00D34810 movups  xmmword ptr [edx],xmm0 

谢谢你们,从答案中我发现我犯了几个错误。

  1. 校准源使用_alinged_malloc

  2. 编译与优化。

  3. 使用C++蒙上不是C

+4

你没有做任何事情来对齐源地址。您正在尝试对齐指针而不更改存储的地址。你应该确保'temp'指向的缓冲区正确对齐。你也应该避免在C++代码中使用C风格的转换。 – VTT

+2

@VTT:'(__m128i *)'是内在函数的标准样式。 'reinterpret_cast <__m128i*>(temp)'通常太笨重了,英特尔的内部函数已经有足够长的名字了。 (另外,'__m128i'可以用来别名,所以它很特殊。) –

+1

如果你希望看起来像asm的输出,不要编译时禁用优化。发出'imul edx,ecx,0'只是一个让'edx'归零的好方法。它正在执行一个'movups'加载,但是之后又会溢出到临时堆栈上并重新加载(对齐加载),然后再次存储到实际需要结果的位置。就像我说的,如果你希望asm看起来像你在编写C++时想象的那样,那么启用优化。 –

回答

7

我可以在这里看到三个问题:

  1. 这段代码是严格的C,而不是C++。这本身不是问题,但问题被标记为C++。
  2. 你不指针的对准之间VS 的指针指向什么对齐时码流内one区分
  3. ,这是不可能改变的arrtemp对齐。

让我们关注第二点 - 第二点 - 有一个指针,指针指向什么。我想你已经知道这两者之间的区别了。

基本上,当你写_declspec (align(16)) __m128i *tmp你告诉程序:

当你在栈上分配的指针tmp,确保的tmp的第一个字节上的地址分配(在栈上),这是16

如此之大,tmp本身对准16整除,它不会在所有影响什么TMP点。您需要temp指向已经对齐数据。这可以通过

  1. 进行适当alignas关键字(alignas(16) char my_buffer[16*100];
  2. 分配动态数据与能够分配对准数据的存储器分配功能,如aligned_alloc,或MSVC的_aligned_malloc这需要_aligned_free分配堆栈上的数据。请参阅How to solve the 32-byte-alignment issue for AVX load/store operations?

您不能以追溯方式对齐内存,它必须首先分配对齐。确保temp传递的数据已经对齐,或者如果您不能要求调用者传递对齐的数据,请使用未对齐的加载/存储。

+3

如果你将它编译为C++,那就是C++。你可以说它是用类似C的风格写的,但这并不改变编译器如何解释它。 C和C++之间有细微的差别。也许这个代码来自一个C例子,并且OP在C++中使用它。 –

+2

您也可以编写'__asm {mov eax,8}'并在C++程序中编译它,但不会生成汇编语言C++。 –

+1

我基本同意这一点,但仍然认为你应该用不同的方式来表达你的观点1。如果你想批评在C++代码中使用C风格,当然。但这并不意味着它是C.联盟类型双关仍然是未定义的行为(除了我认为MSVC确实定义它,与GNU C++一样)。但是你可能会认为它在某些方面会使得MSVC++的asm成为一部分程序。 MSVC inline asm与MASM有细微差别(例如,它接受'0xdeadbeef'和'0deadbeefH'。) –