【发布时间】:2018-09-21 13:08:49
【问题描述】:
我正在使用libsimdpp 编写矢量化代码。似乎我找不到将少于所有通道从内存或从寄存器移动到另一个寄存器的方法。
例如,使用 _mm_move_sd 或 _mm_move_ss 内在函数(movsd 或 movss 操作码)可以在寄存器之间复制最低的一或两条通道,而其他通道保持不变。
你如何对 libsimdpp 做同样的事情?
【问题讨论】:
标签: sse intrinsics
我正在使用libsimdpp 编写矢量化代码。似乎我找不到将少于所有通道从内存或从寄存器移动到另一个寄存器的方法。
例如,使用 _mm_move_sd 或 _mm_move_ss 内在函数(movsd 或 movss 操作码)可以在寄存器之间复制最低的一或两条通道,而其他通道保持不变。
你如何对 libsimdpp 做同样的事情?
【问题讨论】:
标签: sse intrinsics
我不熟悉 libsimdpp 库,但据我所知,您可以使用带有适当排列索引的 simdpp::shuffle2x2 来替代 _mm_move_sd。从文件https://github.com/p12tic/libsimdpp/blob/master/simdpp/detail/insn/shuffle2x2.h 中,我们可以看到以这种方式使用_mm_shuffle_pd 或_mm_blend_pd,这取决于所选择的排列索引。这些 Intel 内部函数可用作 _mm_move_sd 的替代品。
从manual page 看来,您似乎必须选择排列索引s0 = 2 和s1 = 1 来模拟_mm_move_sd。这对应于
shuffle2x2.h 的第 156 和 157 行,即:if (s0 == 2 && s1 == 1) {return _mm_blend_pd(b.native(), a.native(), 0x2);}。
_mm_move_ss 的替代品是 _mm_blend_ps,带有合适的掩码。对于 simdpp::shuffle4x2,libsimdpp 库在 x86 架构上选择 _mm_blend_ps,如果排列索引 (s0==0 || s0==4) && (s1==1 || s1==5) && (s2==2 || s2==6) && (s3==3 || s3==7) 满足以下条件,请参阅 sse_float32_4x2.h,第 40 行和第 155 行。
请注意,例如,GCC 可以将_mm_blend_ps(a, b, 1) 和_mm_move_ss 编译为movss 指令。见this Godbolt link。因此,使用 libsimdpp 和智能编译器,确实可以生成movss 操作码。
但请注意,GCC 只识别 _mm_blend_pd(a, b, 1);,而不是
_mm_blend_pd(a, b, 2);,由 libsimdpp 生成。
请注意,正如 Peter Cordes 在评论中所说,自 Intel Haswell 处理器以来,在 Intel CPU 上,带有寄存器操作数的 blendpd/ps 指令比 movsd/ss 具有更好的吞吐量。
【讨论】:
blendpd 具有比movss xmx,xmm 更好的吞吐量(HSW 上的任何端口)(端口 5 仅在 NHM 和更高版本上);这是 gcc 对-march=haswell 的愚蠢去优化。也许 gcc 在 Core2 的日子里就引入了代码大小,并且从未重新检查过它:/
blendps/ps 指令在现代 cpu 上的性能优于 movsd/ss 指令在现代 cpu 上的性能。
_mm_move_sd 不会在一条指令中执行此操作吗?
_mm_move_sd 似乎只能在寄存器之间移动,我的意思是 _mm_load_sd 然后。
movsd 是只有一个微操作,而带有内存操作数的blendps 是2 个微操作。这证实了movsd 指令更可取。在我看来,libsimdpp 的可移植性非常好,但英特尔内部函数为您提供了更多机会来编写最高效的代码。