c - 在一个 _mm_load_si128 上使用两个 _mm_loadl_epi64

标签 c intel sse 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()); 

或者我可以这样做,
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()); 

我应该选择哪种方法?使用第二种方法比第一种方法有任何性能改进吗?请注意,我已经更换了 _mm_loadu_si128带两个 _mm_loadl_epi64 .

最佳答案

大多数情况下,您需要上下文来说明某些事情是更快还是更慢。延迟、执行端口或 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 内存操作数。

关于c - 在一个 _mm_load_si128 上使用两个 _mm_loadl_epi64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28829951/

相关文章:

assembly - 英特尔开发人员手册中的 "store-buffer forwarding"是什么意思?

c - SSE Intrinsics 算术错误

c - 链接列表 C 程序错误

c++ - 无法设置 key ,因为 'redisClusterCommand()' 正在返回空指针

c - <stdatomic.h> 中的 atomic_store/load 是否适用于 Intel 上未对齐的跨缓存行数据?

intel - _mm512_storenr_pd 和 _mm512_storenrngo_pd

c - 使用 Streaming Simd Extensions (SSE) 的按位运算

c++ - 在 gdb 调试器中打印 __m128 数据类型的值

c - 使用Fatfs写入uint32_t数组

c - 为什么我的结果中会出现随机数?