SSE2内在函数:直接访问内存

时间:2010-07-28 20:03:31

标签: optimization assembly sse simd intrinsics

许多SSE指令允许源操作数是16字节对齐的内存地址。例如,各种(非)包装说明。 PUNCKLBW有以下签名:

  

PUNPCKLBW xmm1,xmm2 / m128

现在看起来根本没有内在函数。看起来必须使用_mm_load * intrinsics来读取内存中的任何内容。这是PUNPCKLBW的固有内容:

  

__ m128i _mm_unpacklo_epi8(__ m128i a,__ m128i b);

(据我所知,__ m128i类型总是指XMM寄存器。)

现在,这是为什么?这是相当悲伤的,因为我通过直接寻址内存看到了一些优化潜力...

2 个答案:

答案 0 :(得分:6)

内在函数相对直接对应于实际指令,但编译器没有义务发出相应的指令。在操作的内存形式中优化操作后的操作(即使在内在函数中编写)是一个常见的优化,这是所有可敬的编译器执行时的优势。

TLDR:在内在函数中编写加载和操作,并让编译器对其进行优化。

编辑:简单示例:

#include <emmintrin.h>
__m128i foo(__m128i *addr) {
    __m128i a = _mm_load_si128(addr);
    __m128i b = _mm_load_si128(addr + 1);
    return _mm_unpacklo_epi8(a, b);
}

使用gcc -Os -fomit-frame-pointer进行编译得出:

_foo:
movdqa      (%rdi), %xmm0
punpcklbw 16(%rdi), %xmm0
retq

请参阅?优化器将对其进行排序。

答案 1 :(得分:3)

您可以直接使用您的记忆值。例如:

__m128i *p=static_cast<__m128i *>(_aligned_malloc(8*4,16));

for(int i=0;i<32;++i)
    reinterpret_cast<unsigned char *>(p)[i]=static_cast<unsigned char>(i);

__m128i xyz=_mm_unpackhi_epi8(p[0],p[1]);

结果的有趣部分:

; __m128i xyz=_mm_unpackhi_epi8(p[0],p[1]);
0040BC1B 66 0F 6F 00      movdqa      xmm0,xmmword ptr [eax] 
0040BC1F 66 0F 6F 48 10   movdqa      xmm1,xmmword ptr [eax+10h] 
0040BC24 66 0F 68 C1      punpckhbw   xmm0,xmm1 
0040BC28 66 0F 7F 04 24   movdqa      xmmword ptr [esp],xmm0 

所以编译器做得很差 - 或者这种方式更快和/或使用选项可以解决这个问题 - 但是它会生成有效的代码,并且C ++代码说明它想要什么相当直接。