为什么将 32 位寄存器移动到堆栈然后从堆栈移动到 xmm 寄存器?

Rus*_*ell 7 x86 assembly sse micro-optimization att

我正在gcc -m3264 位机器上编译。

以下有什么区别?请注意,这是 AT&T 语法。

# this
movd  %edx, %xmm0

# and this
movl  %edx, (%esp)
movd  (%esp), %xmm0
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 2

机器状态的唯一区别是第二个版本在堆栈1上留下了一个副本。

由于某种原因,GCC 的默认调优会在内存中反弹。(最近的 GCC 可能已经在某些情况下解决了这个问题)。大多数时候,在大多数 CPU 上,它的表现通常更差,包括 AMD,尽管 AMD 的优化手册确实推荐了它。请参阅 GCC bug 8082080833 re:GCC 的整数 <-> xmm 策略的一般情况。

与存储和加载 uop 相比,使用movd将花费 1 个 ALU uop,因此前端的 uop 较少,但后端的 uop不同,因此根据周围的代码,存储/重新加载策略可以减少特定的压力执行端口。

ALU 的延迟比所有 CPU 上的存储/重新加载要好movd,因此存储/重新加载的唯一优势是可能的吞吐量。

Agner Fog在他的 Bulldozer 微架构 pdf 中说道(最慢的 CPU movd %edx, %xmm0):

根据我的测量,整数单元和浮点/矢量单元之间的传输延迟比 AMD 软件优化指南中指定的要长得多。尽管如此,我无法确认按照该指南中的建议,通过内存中间体将数据从通用寄存器移动到向量寄存器会更快。


脚注 1:如果您确实想要这样,那么单独的商店通常仍然是实现该状态的更好选择。相同的 uops 数量和更低的延迟(尤其是在 Intel CPU 上。AMD Bulldozer / Steamrollermovd (x)mm, r32/r64在 Intel 上的 1 个周期有 10 / 5 个周期延迟。)

movd %edx, %xmm0         # ALU int -> xmm transfer
movl %edx, (%esp)        # and store a copy if you want it
Run Code Online (Sandbox Code Playgroud)