【问题标题】:x86 addl vs sublx86 addl 与 subl
【发布时间】:2012-04-25 00:04:51
【问题描述】:

我只是注意到 Clang 编译了这个语句(当然没有任何优化):

--x; /* int x; */

进入:

addl    $4294967295, %ecx       ## imm = 0xFFFFFFFF

为什么?使用addl 而不是“显而易见的”subl 有什么好处吗?或者它只是一个实现事实?

让我着迷的是这个:

x -= 1;

变成:

subl    $1, %eax

Clang 信息:

Apple clang 3.0 版 (tags/Apple/clang-211.12) (基于 LLVM 3.0svn) 目标:x86_64-apple-darwin11.2.0 线程模型:posix

【问题讨论】:

  • 这可能只是实现,可能会随着优化级别而改变。更有趣的是它没有使用dec,这可能是一种优化,因为dec不会改变那么多的状态标志,所以它依赖于之前的指令。
  • gcc 使用sublx--x=-1 生成相同的代码。有趣的是,如果我启用-O3,它会使用xorl
  • 没有优势,也没有劣势。两者都是 3 个字节,具有相同的性能特征。
  • @ughoavgfhw:对于现代处理器,dec 的速度要么相同,要么比 add/sub 慢,因此将其用作优化实际上没有意义(对于速度至少,它可能会在可执行文件大小方面提供好处)
  • @ughoavgfhw 在许多处理器上,decinc 实际上速度较慢,因为它们只更改状态标志寄存器的 部分,因此在与其他算术运算一起使用。

标签: c assembly compiler-construction x86 clang


【解决方案1】:

这种行为与 clang 处理预减量的方式有关,而不是像 sub-and-assign 这样的二元运算符。请注意,我将尝试在 clang 级别解释为什么您会看到这种行为。我不知道为什么选择以这种方式实现它,但我想这只是为了便于实现。

我在这里引用的所有函数都可以在lib/CodeGen/CGExprScalar.cpp 内的ScalarExprEmitter 类中找到。

函数 EmitScalarPrePostIncDec 以相同的方式处理前/后减量/增量:发出 LLVM add 指令,使用 1-1 作为第二个参数,具体取决于表达式是增量或减量。

因此,

--x

最终会在 LLVM IR 中类似于

add i32 %x, -1

这很自然地转换为 x86 之类的东西

add $0xffffffff, %ecx

另一方面,二元运算符的处理方式都不同。在你的情况下,

x -= 1

将由EmitCompoundAssign 处理,后者又调用EmitSub。将发出类似于以下 LLVM IR 的内容:

sub i32 %x, 1

【讨论】:

  • 感谢您的解释和来源参考。这就是我一直在寻找的,它是有道理的,并证明它在实施结果中。
猜你喜欢
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
  • 2013-03-17
  • 1970-01-01
  • 2011-01-28
相关资源
最近更新 更多