我需要使用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());
或者我可以这样做,
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());
我应该去哪个approch?使用第二种方法比第一种方法有任何性能提升。请注意,我已将_mm_loadu_si128
替换为两个_mm_loadl_epi64
。
答案 0 :(得分:1)
大多数情况下,您需要上下文来说明某些事情是更快还是更慢。延迟,执行端口或uop吞吐量(前端)都是常见的瓶颈。
如果使用1寄存器寻址模式,punpcklo
可以与内存操作数微融合,使整个内存解包操作成为单个融合域uop。如果你的循环索引到一个数组,而不是递增指针,那么去加载2x128b然后解压缩,因为punpcklwd xmm0, [rsi + rax]
不能微融合。
实际上,抓一点。 punpcklo
仍然要求其内存操作数为16字节对齐。但是,如果源数据已对齐,您可以使用相同的地址执行一系列punpcklo
/ punpckhi
对。
如果你的内在函数最终编译为4x负载和4x解压缩,那么至少会比2x负载和4x解包更差。
如果您不限于SSE3,SSE4.1的PMOVZXWD xmm1, xmm2/m64
将是完美的,因为它没有128b内存操作数以及相应的对齐要求。