【问题标题】:Can I substitute a MOV operation with an OR operation?我可以用 OR 操作代替 MOV 操作吗?
【发布时间】:2020-11-06 13:14:20
【问题描述】:

首先,我想说我是 ASM 新手,如果这是一个愚蠢的问题,请原谅。

我在Agner Fog's microarchitecture manual 中读到了有关部分寄存器停顿的信息(这似乎有点先进,但我很好奇为什么 64 位模式下的 32 位指令将寄存器的上半部分归零)。例 6.13 给出了如何避免寄存器停顿的解决方案。我对此仍然有些困惑,为什么不使用 OR 操作而不是 MOV,例如:

xor eax, eax
mov al, byte [mem8]
; or  al, byte [mem8] ; why not this?

我认为效果是一样的。它们每秒都使用相同数量的周期吗?一个比另一个更有效吗?有没有什么“幕后”让我更喜欢其中一个?

【问题讨论】:

  • 是的。你可以这样做。但为什么呢?
  • 在线查找代码以确定,但我相信它们的速度相同。如果您可以加载整个寄存器而不是仅加载 8 位,则可以删除 xor,但这也可能很容易通过管道传输。
  • 在这种特殊情况下,当目标寄存器为al 时,mov 指令短一个字节,参见godbolt.org/z/v114od
  • 如果可以避免的话,通常最好不要让指令依赖于寄存器以前的内容,因为它限制了处理器乱序执行的能力,所以通常你会更喜欢@987654326 @。不过,我不知道这在这种特定情况下是否重要。
  • 请注意效果并不完全相同; or 将设置标志,mov 不会。不过,这在大多数应用程序中可能并不重要。

标签: assembly x86 intel-syntax


【解决方案1】:

64 位模式下的部分寄存器访问

在 64 位模式下,访问小于 64 位的寄存器时适用以下规则:

  • 如果访问 32 位寄存器,则相关 64 位寄存器的高 32 位被清除
  • 如果访问 16 位或 8 位寄存器,则相关 64 位寄存器的高 48 位或 56 位将保留。

如果只访问一个 8 位寄存器,则必须先获取关联的 64 位寄存器的旧值,更改 8 位子寄存器,然后保存新值。

Agner Fog 的微体系结构手册中的示例 6.13 与此无关,它只是movzx 的替代品,因为此指令在较旧的奔腾处理器上速度较慢。

movor?

两行

31 C0                   xor eax, eax
8A 05 ## ## ## ##       mov al, byte [mem8]

(左侧的操作码)可能比用

替换第二行更快
0A 05 ## ## ## ##       or  al, byte [mem8]

因为与上一行存在依赖关系:只有在计算出xor eax, eax 时, eax 中的新值才能传递给or。此外,就像mov 的变体一样,可能会因为只访问部分寄存器而变慢。相反,我建议将这两行替换为

0F B6 05 ## ## ## ##    movzx eax, byte [mem8]

这比以前的方法短一个字节,而且只是一条访问完整 32 位寄存器的指令。正如 Agner Fog 所说的

避免部分寄存器停顿的最简单方法是始终使用完整寄存器并在从较小的内存操作数读取时使用MOVZXMOVSX

【讨论】:

  • 这不是竞争条件,它是一个简单的数据依赖。 x86 的执行模型是串行的,即机器给出每条指令在下一条指令开始之前完全完成的错觉。因此没有种族。请注意,在 Sandybridge-family(至少 Haswell 和更高版本)上,xor-zeroing 从发布/重命名时起的延迟为零,因此这无关紧要,并且 mov al, [mem] 在该arch 系列上是 also a merge so also has a dependency on the full register。 (这也是对 AMD 的合并;只有旧的 P6 系列单独重命名 AL)。正在寻找答案......
猜你喜欢
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 2020-12-12
  • 1970-01-01
  • 2022-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多