将xmm寄存器的低位两个32位浮点扩展到整个xmm寄存器



在Intel x86程序集中执行以下操作的最有效方法是什么(ab是32位浮点(:

xmm1: [-, -, a, b]xmm1: [a, a, b, b]

我找不到任何有用的说明
我的想法是将ab复制到其他寄存器,然后将xmm1寄存器移位4个字节,并将a移动到最低的4个字节。

您正在寻找unpcklps xmm1, xmm1(https://www.felixcloutier.com/x86/unpcklps)将寄存器中的低元素与其自身交错:
low element->底部2,从第二低到最高2。

您可以使用shufps,但在这种情况下不会更好,并且需要一个立即字节。要复制和混洗,可以使用pshufd,但在少数CPU上,整数指令在FP指令之间较慢(但它通常仍然比movaps+unpcklps更好。要么没有旁路延迟,要么是1个周期,移动将花费相同的延迟,但也需要一些吞吐量资源。除了Nehalem,旁路延迟为2个周期。我不认为任何具有mov消除功能的CPU都有旁路延迟用于洗牌,但可能有些AMD有。(


如果你很难找到正确的shuffle指令,可以考虑用C写它,看看clang是否能把它变成shuffle。像_mm_set_ps(v[1], v[1], v[0], v[0])。一般来说,这并不总是编译成好的asm,但值得尝试clang -O3(clang有一个非常好的shuffle优化器(。在这种情况下,GCC和clang都会想出如何使用一个unpcklps xmm0,xmm0来实现这一点(https://godbolt.org/z/o6PTeP)而不是可能发生的灾难。或者与shufps xmm0,xmm0, 5相反(5是0b00'00'01'01(。

(请注意,将__m128索引为v[idx]是GNU扩展,但我只是建议使用clang来找到一个好的shuffle。如果你最终想要内部函数,请检查clang的asm,然后在代码中使用内部函数,而不是_mm_set(

另请参阅Agner Fog优化指南中的SIMD章节(https://agner.org/optimize/);对于不同类型的数据移动,他有一个很好的说明表。而且https://www.officedaytime.com/simd512e/simd.html具有良好的视觉快速参考,并且https://software.intel.com/sites/landingpage/IntrinsicsGuide/允许您按类别(Swizzle=shuffles(和ISA级别进行筛选(因此您可以排除AVX512,它具有大量带有掩码的内部版本。(

另请参阅https://stackoverflow.com/tags/sse/info这些链接和更多。


如果您不太了解可用的指令(以及CPU架构/性能调整的详细信息(,您可能会更好地使用带有内部函数的C。当你想出一种效率较低的方法来进行洗牌时,编译器可以找到更好的方法。例如,编译器有望为您将_mm_shuffle_ps(v,v, _MM_SHUFFLE(1,1,0,0))优化为unpcklps

很少有手工编写的asm是正确的选择,尤其是对于x86。编译器通常能很好地处理内部函数,尤其是GCC和clang。如果您不知道unpcklps的存在,那么您可能离轻松/常规地击败编译器还有很长的路要走。

相关内容

  • 没有找到相关文章

最新更新