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

Posted

技术标签:

【中文标题】为啥将 32 位寄存器移动到堆栈然后从堆栈移动到 xmm 寄存器?【英文标题】:Why move 32-bit register to stack then from stack to xmm register?为什么将 32 位寄存器移动到堆栈然后从堆栈移动到 xmm 寄存器? 【发布时间】:2015-04-17 14:20:53 【问题描述】:

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

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

# this
movd  %edx, %xmm0

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

【问题讨论】:

第一个不应该是movd %edx, %xmm0吗? 您忘记启用优化?不同之处在于第二个在堆栈上留下了一个副本,以后可能需要。不过,更好的方法是将堆栈写入添加到版本 #1。 @PascalCuoq 你是对的。让我编辑问题。 @lurker 哦,对不起。我假设使用 gcc 编译会默认提供 AT&T 语法。我应该明确表示。 那是我的错。你所拥有的显然是 AT&T 语法,但我习惯于思考英特尔,我完全过滤掉了线索。我收回我的评论... :) 【参考方案1】:

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

出于某种原因,GCC 的默认调整会在内存中反弹。 (最近的 GCC 可能已在某些情况下修复了此问题)。尽管 AMD 的优化手册确实推荐了它,但在大多数情况下,包括 AMD 在内的大多数 CPU 通常都会更糟。请参阅 GCC 错误 80820 和 80833 re: GCC 的整数 xmm 策略。

使用 movd 将花费 1 ALU uop,而存储和加载 uop,因此前端的 uop 较少,但后端的 uop 不同不同,因此取决于围绕代码存储/重新加载策略可以减少特定执行端口的压力。

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

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

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


脚注 1:如果您真的想要这样,单独的商店通常仍然是实现该状态的更好选择。相同的 uops 数和更低的延迟(尤其是在 Intel CPU 上。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

【讨论】:

以上是关于为啥将 32 位寄存器移动到堆栈然后从堆栈移动到 xmm 寄存器?的主要内容,如果未能解决你的问题,请参考以下文章

PUSHAD 和 PUSHFD

找出有多少字节将 esp 和程序堆栈上存储的返回地址分开

为啥 GCC 会产生奇怪的方式来移动堆栈指针

当我想将数据从堆栈移动到向量时如何避免复制?

将数据移动到 Rc/Arc 是不是总是将其从堆栈复制到堆?

将导航堆栈移动到更多选项卡