2

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

PUNPCKLBW xmm1, xmm2/m128

现在这对于内在函数似乎根本不可能。看起来必须使用 _mm_load* 内在函数来读取内存中的任何内容。这是 PUNPCKLBW 的内在函数:

__m128i _mm_unpacklo_epi8 (__m128i a, __m128i b);

(据我所知,__m128i 类型总是指一个 XMM 寄存器。)

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

4

2 回答 2

7

内在函数相对直接对应于实际指令,但编译器没有义务发出相应的指令。将操作后的加载(即使以内部函数编写)优化到操作的内存形式是所有受人尊敬的编译器在有利时执行的常见优化。

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

看?优化器会对其进行排序。

于 2010-07-28T20:08:49.540 回答
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 

So the compiler is doing a bit of a poor job -- or perhaps this way is faster and/or playing with the options would fix that -- but it generates code that works, and the C++ code is stating what it wants fairly directly.

于 2010-08-01T17:06:04.933 回答