gpt4 book ai didi

x86 - 在这种情况下 _mm_movehdup_ps 和 _mm_shuffle_ps 有什么区别?

转载 作者:行者123 更新时间:2023-12-01 11:13:39 27 4
gpt4 key购买 nike

如果我的理解正确的话
_mm_movehdup_ps(a)
给出相同的结果
_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 3, 3)) ?

两者有性能差异吗?

最佳答案

_MM_SHUFFLE首先取高元素,所以 _MM_SHUFFLE(3,3, 1,1)会做 movshdup 洗牌。

主要区别在于装配级别; movshdup是复制和洗牌,避免 movaps如果输入 a,则复制输入稍后仍然需要(例如,作为水平总和的一部分:参见 Fastest way to do horizontal float vector sum on x86 以了解它如何在没有 movaps 的情况下与使用 shufps 的 SSE1 版本进行编译的示例。
movshdup/movsldup也可以是带有内存源操作数的 load+shuffle。 ( shufps 显然不能,因为它需要两次相同的输入。)在现代 Intel CPU(Sandybridge 系列)上, movshdup xmm0, [rdi]解码为纯负载 uop,未与 ALU uop 微融合 .因此,它不会与其他 shuffle 竞争 ALU shuffle 吞吐量(端口 5)。加载端口包含执行广播加载的逻辑(包括 movddup 64 位广播)和 movs[lh]dup元素对的重复。更复杂的加载+随机播放,如 vpermilps xmm0, [rdi], 0x12pshufd xmm, [rdi], 0x12仍然解码为多个 uops,可能会根据 uarch 微融合为负载 + ALU。

两条指令的长度相同:movshdup避免立即字节,但 shufps是一条 SSE1 指令,所以它只有一个 2 字节的操作码,比 SSE2 和 SSE3 指令短 1 个字节。 但是启用了 AVX,vmovshdup确实节省了一个字节 ,因为操作码大小的优势消失了。

在只有 64 位 shuffle 单元的旧 CPU(如 Pentium-M 和第一代 Core 2 (Merom))上,有更大的性能优势 . movshdup仅在向量的 64 位一半内进行洗牌。在 Core 2 Merom 上,movshdup xmm, xmm解码为 1 uop,但 shufps xmm, xmm, i解码为 3 uop。 (有关说明表和微架构指南,请参阅 https://agner.org/optimize/)。另请参阅我的水平求和答案(之前链接),了解有关 Merom 和 K8 等 SlowShuffle CPU 的更多信息。

在带有内在函数的 C++ 中

如果启用了 SSE3,如果您的编译器没有优化,那么这是一个错过的优化 _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 1, 1))放入与 _mm_movehdup_ps(a) 相同的组件中.

但是,一些编译器(如 MSVC)通常不会优化内在函数,因此程序员需要了解避免 movaps 的 asm 含义。通过将内部函数用于复制和洗牌指令(例如 pshufdmovshdup )而不是必须破坏其目标寄存器的洗牌(例如 shufpspsrldq 字节移位。)

此外,MSVC 不允许您启用 SSE3 的编译器使用,如果您对它们使用内在函数,则只能获得超出基线 SSE2(或没有 SIMD)的指令。或者,如果您启用 AVX,这将允许编译器也使用 SSE4.2 及更早版本,但它仍然选择不优化。再次,由人类程序员来寻找优化。 ICC 类似。有时,如果您确切地知道自己在做什么并且正在检查编译器的 asm 输出,那么这可能是一件好事,因为有时 gcc 或 clang 的优化会使您的代码变得悲观。

使用 clang 进行编译并查看它是否使用与源代码中的内在函数相同的指令,这可能是一个好主意;在支持 Intel 内在函数的 4 个主要编译器中,它拥有迄今为止最好的 shuffle 优化器,基本上优化您的内在函数代码的方式与编译器通常优化纯 C 的方式相同,即只需遵循 as-if 规则即可产生相同的结果。

最简单的例子:

#include <immintrin.h>

__m128 shuf1(__m128 a) {
return _mm_shuffle_ps(a,a, _MM_SHUFFLE(3,3, 1,1));
}

compiled with gcc/clang/MSVC/ICC on Godbolt

GCC 和 clang 与 -O3 -march=core2两者都发现优化:
shuf1:
movshdup xmm0, xmm0
ret

国际商会 -O3 -march=haswell和 MSVC -O2 -arch:AVX -Gv (启用 vectorcall 调用约定,而不是通过引用传递 SIMD 向量。)
shuf1:
vshufps xmm0, xmm0, xmm0, 245 #4.12
ret #4.12

关于x86 - 在这种情况下 _mm_movehdup_ps 和 _mm_shuffle_ps 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56238197/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com