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

Why move 32-bit register to stack then from stack to xmm register?

我正在 64 位机器上使用 gcc -m32 进行编译。

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

# this
movd  %edx, %xmm0

# and this
movl  %edx, (%esp)
movd  (%esp), %xmm0

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

GCC 的默认调整由于某种原因在内存中反弹。 (最近的 GCC 可能已经在某些情况下修复了这个问题)。尽管 AMD 的优化手册确实推荐了它,但在大多数 CPU 上,包括 AMD 在内,大多数情况下它通常更差。请参阅 GCC 错误 80820 and 80833 回复:GCC 的整数 <-> xmm 一般策略。

使用 movd 将花费 1 个 ALU 微指令,而不是存储和加载微指令,因此前端的微指令较少,但 不同 微指令后端,因此根据周围的代码,store/reload 策略可以减少特定执行端口的压力。

在所有 CPU 上,ALU movd 的延迟均优于 store/reload,因此 store/reload 的唯一优势是可能的吞吐量。

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

The transport delays between the integer unit and the floating point/vector unit are much longer in my measurements than specified in AMD's Software Optimization Guide. Nevertheless, I cannot confirm that it is faster to move data from a general purpose register to a vector register through a memory intermediate, as recommended in that guide.


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

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