在一个 _mm_load_si128 上使用两个 _mm_loadl_epi64

Vik*_*ttu 5 c sse intel simd intrinsics

我需要使用 16 位值(正值)并将它们提升为 32 位。

使用 SIMD(我仅限于 SSE3),以下是我提出的两个选项:

reg_xmm0 = _mm_loadu_si128((const __m128i *)(Src));
reg_xmm2 = _mm_loadu_si128((const __m128i *)(Src+8));

reg_xmm1 = _mm_unpackhi_epi16(reg_xmm0,_mm_setzero_si128());
reg_xmm0 = _mm_unpacklo_epi16(reg_xmm0,_mm_setzero_si128());
reg_xmm3 = _mm_unpackhi_epi16(reg_xmm2,_mm_setzero_si128());
reg_xmm2 = _mm_unpacklo_epi16(reg_xmm2,_mm_setzero_si128()); 
Run Code Online (Sandbox Code Playgroud)

或者我可以这样做,

reg_xmm0 = _mm_loadl_epi64((const __m128i *)(Src));
reg_xmm1 = _mm_loadl_epi64((const __m128i *)(Src+4));
reg_xmm2 = _mm_loadl_epi64((const __m128i *)(Src+8));
reg_xmm3 = _mm_loadl_epi64((const __m128i *)(Src+12));

reg_xmm0 = _mm_unpacklo_epi16(reg_xmm0,_mm_setzero_si128());
reg_xmm1 = _mm_unpacklo_epi16(reg_xmm1,_mm_setzero_si128());
reg_xmm2 = _mm_unpacklo_epi16(reg_xmm2,_mm_setzero_si128());
reg_xmm3 = _mm_unpacklo_epi16(reg_xmm3,_mm_setzero_si128()); 
Run Code Online (Sandbox Code Playgroud)

我应该采用哪种方法?使用第二种方法比第一种方法会有任何性能改进吗?请注意,我已替换_mm_loadu_si128为两个_mm_loadl_epi64

Pet*_*des 3

大多数时候,您需要上下文来判断某件事是更快还是更慢。延迟、执行端口或 uop 吞吐量(前端)都是常见的瓶颈。

如果您使用 1 寄存器寻址模式,punpcklo则可以与内存操作数微融合,使整个从内存解包操作成为单个融合域微指令。如果您的循环正在对数组进行索引,而不是递增指针,则可以加载 2x128b 然后解包,因为punpcklwd xmm0, [rsi + rax]无法微熔丝。

事实上,从头开始。 punpcklo仍然要求其内存操作数是 16 字节对齐的。但是如果您的源数据是对齐的,您可以使用相同的地址执行一系列punpcklo/对。punpckhi

如果您的内在函数最终编译为 4x 加载和 4x 解包,那么这至少会比 2x 加载和 4x 解包稍差。

如果不限于 SSE3,SSE4.1PMOVZXWD xmm1, xmm2/m64将是完美的,因为它没有具有相应对齐要求的 128b 内存操作数。