Intel x86 汇编中执行以下操作的最有效方法是什么(a,b是 32 位浮点数):
从xmm1: [-, -, a, b]到xmm1: [a, a, b, b]
我找不到任何有用的说明。
我的想法是将a和b复制到其他寄存器,然后将xmm1寄存器移动 4 个字节并将a或b移动到最低的 4 个字节。
您正在寻找unpcklps xmm1, xmm1( https://www.felixcloutier.com/x86/unpcklps ) 将寄存器中的低元素与自身交错:
低元素 -> 底部 2,第二低到高 2。
您可以改为使用,shufps但在这种情况下不会更好,并且需要立即字节。要复制和洗牌,您可以使用pshufd,但在一些 CPU 上,整数指令在 FP 指令之间较慢(但它通常仍然比movaps+ 好unpcklps。要么没有旁路延迟,要么是 1 个周期,而 movaps 的成本相同延迟,但也有一些吞吐量资源。除了 Nehalem,其旁路延迟为 2 个周期。我认为任何具有 mov-elimination 的 CPU 都没有用于 shuffle 的旁路延迟,但也许有些 AMD 会这样做。)
如果您在找到正确的 shuffle 指令时遇到困难,请考虑用 C 编写它,看看 clang 是否可以将它变成一个 shuffle 指令。喜欢_mm_set_ps(v[1], v[1], v[0], v[0])。一般来说,它不会总是编译成好的 asm,但值得一试clang -O3(clang 有一个非常好的随机优化器)。在这种情况下,GCC 和 clang 都想出了如何用一个unpcklps xmm0,xmm0(https://godbolt.org/z/o6PTeP)来做到这一点,而不是可能发生的灾难。或者与shufps xmm0,xmm0, 5 (5 是0b00'00'01'01)相反。
(请注意,索引 a __m128asv[idx]是 GNU 扩展,但我只建议使用 clang 来找到一个好的 shuffle。如果您最终想要内在函数,请检查 clang 的 asm,然后在您的代码中使用内在函数,而不是 a _mm_set)
另请参阅 Agner Fog 的优化指南 ( https://agner.org/optimize/ ) 中的 SIMD 章节;他有一个很好的指令表,可以考虑不同类型的数据移动。另外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 与内在函数一起使用。当您想出一种效率较低的方法来进行 shuffle 时,编译器可以找到更好的方法。例如,编译器将有希望优化_mm_shuffle_ps(v,v, _MM_SHUFFLE(1,1,0,0))到unpcklps你。
手写 asm 是正确的选择是非常罕见的,尤其是对于 x86。 编译器通常在内部函数方面做得很好,尤其是 GCC 和 clang。如果您不知道它unpcklps存在,那么您可能离能够轻松/常规地击败编译器还有很长的路要走。
| 归档时间: |
|
| 查看次数: |
83 次 |
| 最近记录: |