_declspec(align(16))没有将指针对齐到16个字节

时间:2017-10-06 05:39:27

标签: c++ sse

所以我试图使用SSE函数__mm_load_128,如果我在某处犯了一些愚蠢的错误,我对SSE很新,请原谅我。

这是代码

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);
}

我在visual studio上收到错误 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

1 个答案:

答案 0 :(得分:8)

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

  1. 这段代码严格来说是C,而不是C ++。这本身并不是问题,但问题被标记为C ++。
  2. 您不区分指针的对齐指针指向的对齐
  3. 当代码流在one内时,无法更改arrtemp的对齐方式。
  4. 让我们专注于第2点的第2点 - 有一个指针,指针指向的是什么。我猜你已经知道了这两者之间的区别。

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

      

    当您在堆栈上分配指针tmp时,请确保tmp的第一个字节分配在一个地址(堆栈上)上,该地址可以被16分割。

    太棒了,tmp本身与16对齐,它根本不影响 tmp指向。您需要temp指向已对齐数据。

    可以做到这一点
    1. 使用正确的alignas关键字(alignas(16) char my_buffer[16*100];
    2. 在堆栈上分配数据
    3. 使用能够分配对齐数据的内存分配函数来分配动态数据,例如aligned_alloc或需要_aligned_malloc的MSVC _aligned_free。请参阅How to solve the 32-byte-alignment issue for AVX load/store operations?
    4. 您无法追溯对齐内存,必须首先对其进行对齐。确保temp传递的数据已经对齐,或者如果您不需要调用者传递对齐的数据,请使用未对齐的加载/存储。