【问题标题】:What does the compiler do in assembly when optimizing code? ie -O2 flag编译器在优化代码时在汇编中做了什么?即 -O2 标志
【发布时间】:2013-12-05 08:39:12
【问题描述】:

因此,当您在编译 C++ 时添加优化标志时,它会运行得更快,但这是如何工作的呢?有人能解释一下大会中到底发生了什么吗?

【问题讨论】:

    标签: c++ compiler-optimization


    【解决方案1】:

    这意味着您让编译器在编译时进行额外的工作/分析,因此您可以在运行时获得一些额外宝贵的 CPU 周期的回报。最好用一个例子来解释。

    考虑这样的循环:

    const int n = 5;
    for (int i = 0; i < n; ++i)
      cout << "bleh" << endl;
    

    如果你在没有优化的情况下编译它,编译器不会为你做任何额外的工作——为此代码生成的程序集 sn-p 很可能是比较和跳转指令的字面翻译。 (这不是最快的,只是最直接的)

    但是,如果您编译 WITH 优化,编译器可以轻松地 inline 这个循环,因为它知道上限永远不会改变,因为 n 是 const。 (即它可以直接复制重复的代码5次,而不是比较/检查终止循环条件)。

    这是另一个优化函数调用的例子。以下是我的整个程序:

    #include <stdio.h>
    static int foo(int a, int b) {
      return a * b;
    } 
    
    
    int main(int argc, char** argv) {
      fprintf(stderr, "%d\n", foo(10, 15));
      return 0;
    }
    

    如果我在 x86 机器上使用 gcc foo.c 编译此代码而不进行优化,我的程序集如下所示:

    movq    %rsi, %rax
    movl    %edi, -4(%rbp)
    movq    %rax, -16(%rbp)
    movl    $10, %eax      ; these are my parameters to
    movl    $15, %ecx      ; the foo function
    movl    %eax, %edi
    movl    %ecx, %esi
    callq   _foo
    ; .. about 20 other instructions ..
    callq   _fprintf
    

    在这里,它没有优化任何东西。它使用我的常量值加载寄存器并调用我的foo 函数。但是看看我是否使用-O2 标志重新编译:

    movq    (%rax), %rdi
    leaq    L_.str(%rip), %rsi
    movl    $150, %edx
    xorb    %al, %al
    callq   _fprintf
    

    编译器非常聪明,它甚至不再调用foo。它只是内联它的返回值。

    【讨论】:

    • 非常酷!当你也做调用函数之类的事情时有什么不同吗?
    • @TidusSmith 用更深入的例子更新了答案。希望你觉得它有用。
    【解决方案2】:

    大部分优化发生在编译器的中间表示中,然后才生成程序集。您绝对应该查看 Agner Fog 的 Software optimization resources。第 1 手册的第 8 章通过示例描述了编译器执行的优化。

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 2021-01-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2011-08-25
      • 2011-10-05
      • 2017-05-08
      相关资源
      最近更新 更多