- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如果我的理解正确的话_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], 0x12
或 pshufd 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 含义。通过将内部函数用于复制和洗牌指令(例如 pshufd
和 movshdup
)而不是必须破坏其目标寄存器的洗牌(例如 shufps
和 psrldq
字节移位。)
此外,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));
}
-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/
SSE 内在函数包括 _mm_shuffle_ps xmm1 xmm2 immx允许从 xmm1 中选取 2 个元素与来自 xmm2 的 2 个元素连接.然而,这是针对浮点数,(由 _ps 暗示,打包
有时(不总是)当我在项目中包含我的数学头文件时,编译器会提示(尝试过 gcc 和 clang)_mm_shuffle_ps和 _mm_shuffle_pd即使设置了所有编译器标志 (-msse -ms
_mm_shuffle_ps() 内在函数允许将浮点输入交错为输出的低 2 float 和高 2 float 。 例如: R = _mm_shuffle_ps(L1, H1, _MM_SHUFFLE(
如果我的理解正确的话 _mm_movehdup_ps(a) 给出相同的结果 _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 3, 3)) ? 两者有性能差异吗? 最佳答案
我正在尝试将 SSE 编写的代码转换为 NEON SIMD,但由于 _mm_shuffle_ps SSE 内在函数而陷入困境。这是代码: b = _mm_shuffle_ps(a, b, 136);
我是一名优秀的程序员,十分优秀!