2

我试图了解 gcc 在设置 -O3 标志时执行了什么样的优化。我很困惑这两行是什么,

xor %esi, %esi
lea 0x0(%esi), %esi

在我看来这是多余的。在这里使用 lea 指令有什么意义?

4

2 回答 2

4

该指令用于填充空间以进行对齐。当循环从对齐的地址开始时会更快,因为处理器将内存以块的形式加载到解码器中。通过对齐循环和函数的开头,它们更有可能位于这些块之一的开头。这可以防止加载以前不会使用的指令,最大化未来指令的数量,并且可能最重要的是,确保第一条指令完全在第一个块中,因此执行它不需要两次加载.

编译器知道最好对齐循环,并且有两个选项可以这样做。它可以跳转到循环的开头,也可以用无操作来填补空白,让处理器通过它们。跳转指令会破坏指令流,并经常在现代处理器上造成周期浪费,因此不必要地添加它们是不可取的。对于这样的短距离,无操作更好。

x86 体系结构包含一条专门用于什么都不做的指令,nop. 但是,这是一个字节长,因此对齐循环需要不止一个字节。解码每个指令并决定它什么都不做需要时间,因此简单地插入另一个没有副作用的更长指令会更快。因此,编译器插入了lea您看到的指令。它绝对没有任何影响,并且由编译器选择以具有所需的确切长度。事实上,最近的处理器有标准的多字节无操作指令,所以这很可能在解码过程中被识别出来,甚至永远不会被执行。

于 2013-09-30T04:36:42.993 回答
1

正如 ughoavgfhw 所解释的 - 这些是用于更好地对齐代码的填充。您可以lea在以下链接中找到它 -

http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2010-September/003881.html

引用:

  1-byte: XCHG EAX, EAX
  2-byte: 66 NOP
  3-byte: LEA REG, 0 (REG) (8-bit displacement)
  4-byte: NOP DWORD PTR [EAX + 0] (8-bit displacement)
  5-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (8-bit displacement)
**6-byte: LEA REG, 0 (REG) (32-bit displacement)**
  7-byte: NOP DWORD PTR [EAX + 0] (32-bit displacement)
  8-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
  9-byte: NOP WORD  PTR [EAX + EAX*1 + 0] (32-bit displacement)

另请注意这个 SO 问题更详细地描述它 - NOPL 在 x86 系统中做了什么?

请注意,xor 本身不是 nop(它会更改 reg 的值),但执行起来也非常便宜,因为它是一个零习语 -将寄存器与自身进行异或的目的是什么?

于 2013-09-30T11:28:29.527 回答