为什么clang用-O0产生低效率的asm(对于这个简单的浮点数总和)?

为什么clang用-O0产生低效率的asm(对于这个简单的浮点数总和)?

我正在llvm clang Apple LLVM版本8.0.0(clang-800.0.42.1)上反汇编以下代码:

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)
    ...

显然,它正在执行以下操作:

  1. 将两个浮点数加载到寄存器xmm0和xmm1

  2. 将它们放在堆栈中

  3. 从堆栈中将一个值(不是xmm0之前的一个值)加载到xmm0

  4. 执行添加。

  5. 将结果存储回堆栈。

我发现效率低下是因为:

  1. 一切都可以在注册表中完成。我以后不会使用a和b,因此它可以跳过涉及堆栈的任何操作。

  2. 即使它想使用堆栈,如果以不同的顺序执行操作,也可以节省从堆栈中重新加载xmm0的时间。

考虑到编译器总是正确的,为什么选择这种策略?


慕慕森
浏览 764回答 2
2回答

ABOUTYOU

请注意,至少clang实际上是从每个变量开始的,每个变量在堆栈上为其分配了内存。-O0如果可能的话,第一个优化过程之一(我想省略了)可以将它们变成一堆SSA变量。因此,至少在clang上,没有进行“反优化”,只是关闭了正常的优化。
打开App,查看更多内容
随时随地看视频慕课网APP