我正在使用 llvm clang Apple LLVM 版本 8.0.0 (clang-800.0.42.1) 对这段代码进行反汇编:
Translated text:Using llvm clang Apple LLVM version 8.0.0 (clang-800.0.42.1), I am disassembling this code:
int main() {
float a=0.151234;
float b=0.2;
float c=a+b;
printf("%f", c);
}
我没有使用-O规范进行编译,但我也尝试过使用-O0(得到相同的结果)和-O2(实际上计算了该值并将其预先计算存储)
生成的汇编代码如下(我删除了不相关的部分)
-> 0x100000f30 <+0>: pushq %rbp
0x100000f31 <+1>: movq %rsp, %rbp
0x100000f34 <+4>: subq $0x10, %rsp
0x100000f38 <+8>: leaq 0x6d(%rip), %rdi
0x100000f3f <+15>: movss 0x5d(%rip), %xmm0
0x100000f47 <+23>: movss 0x59(%rip), %xmm1
0x100000f4f <+31>: movss %xmm1, -0x4(%rbp)
0x100000f54 <+36>: movss %xmm0, -0x8(%rbp)
0x100000f59 <+41>: movss -0x4(%rbp), %xmm0
0x100000f5e <+46>: addss -0x8(%rbp), %xmm0
0x100000f63 <+51>: movss %xmm0, -0xc(%rbp)
...
显然它正在执行以下操作:
- 将两个浮点数加载到寄存器xmm0和xmm1中
- 把它们放入堆栈
- 从堆栈中加载一个值(不是xmm0之前拥有的值)到xmm0中
- 执行加法运算。
- 把结果存回堆栈。
我认为这样做效率低下,因为:
- 所有操作都可以在寄存器中完成。由于我后面不会再使用a和b,所以可以跳过涉及堆栈的任何操作。
- 即使想要使用堆栈,如果按不同的顺序执行操作,它也可以避免重新从堆栈加载xmm0。
既然编译器总是正确的,那么它为什么选择这种策略呢?