美文网首页
opt-viewer帮助编译器生成更好的代码

opt-viewer帮助编译器生成更好的代码

作者: 谭英智 | 来源:发表于2023-02-06 17:13 被阅读0次

    背景

    编译器会为代码做编译优化

    一般来说,编译器的工作会做得很好

    但是由于C++过于灵活,导致编译器不敢过度优化

    opt-viewer是llvm提供的一款显示编译优化的工具

    它可以清晰的标记出clang为c++做了什么优化,没有做哪些优化,没有优化的原因是什么

    通过阅读opt-viewer的报告,可以微调代码,让编译器编译出更优的代码

    opt-viewer用法

    clang++ -O3 -fsave-optimization-record -c foo.c
    opt-viewer.py foo.opt.yaml html -j 1
    

    用例分析

    Clobbered by store

    代码片段:

    void foo(int* p, const int& b) {
      for (int i = 0; i < 10; i++) {
        p[i] += b;
      }
    }
    

    opt-viewer报告:

    opt-viewer-store

    报告分析:

    看到绿色的为编译优化成功

    红色为编译优化失败

    看倒数第二行出现了Clobbered by store

    代表变量b,在每次循环中都要加载b的内容

    因为b有可能是p的引用

    在循环中b的值有可能发生变化

    优化代码

    void foo(int* __restrict__ p, const int& b) {
      for (int i = 0; i < 10; i++) {
        p[i] += b;
      }
    }
    

    再次查看报告

    opt-viewer-fix-store

    Clobbered by store 问题解决了

    Clobbered by call

    代码片段

    void somefunc(const int&);
    int whateva();
    
    void f(int i, int* res) {
      somefunc(i);
      i++;
      res[0] = whateva();
      i++;
      res[1] = whateva();
      i++;
      res[2] = whateva();
    }
    

    opt-viewer报告

    opt-viewer-call

    报告分析

    变量 i 必须在每次调用 whateva 函数前进行累加

    不能优化成 i += 3;

    因为 somefunc 获取了 i 的引用

    而 whateva 有可能对 i 的引用做任何事情

    这就出现了 Clobbered by call

    优化代码

    使用_attribute_((pure))

    void somefunc(const int&) __attribute__((pure));
    int whateva();
    
    void f(int i, int* res) {
      somefunc(i);
      i++;
      res[0] = whateva();
      i++;
      res[1] = whateva();
      i++;
      res[2] = whateva();
    }
    

    报告

    opt-viewer-fix-call1

    分析

    _attribute_((pure))函数代表somefunc的作用只会影响返回值,不会影响其他任何变量

    因此somefunc不会对变量 i 发生副作用

    优化代码

    使用_attribute_((const))

    void somefunc(const int&);
    int whateva() __attribute__((const));
    
    void f(int i, int* res) {
      somefunc(i);
      i++;
      res[0] = whateva();
      i++;
      res[1] = whateva();
      i++;
      res[2] = whateva();
    }
    

    查看报告

    opt-viewer-fix-call2

    报告分析

    看到出现了 tailcallelim

    函数的尾四行都没有了

    代表 i++ 被合并了, whateva 也只调用了一次

    这是因为_attribute_((const))修饰的函数,是常函数,它的输出只依赖函数的输入,不依赖任何全局变量

    Failed to move load with loop invariant address

    代码片段

    class C {
      bool m_cond;
    
      void method1();
    };
    void f();
    void g();
    void C::method1() {
      for (int i = 0; i < 5; ++i) {
        g();
        if (m_cond) f();
      }
    }
    

    opt-viewer报告

    opt-viewer-loop

    报告分析

    for循环不能把条件m_cond往外提

    因为变量m_cond有可能在循环的时候被其他函数修改

    优化代码

    class C {
      bool m_cond;
    
      void method1();
    };
    void f();
    void g();
    void C::method1() {
      bool cond = m_cond;
      for (int i = 0; i < 5; ++i) {
        g();
        if (cond) f();
      }
    }
    

    查看报告

    opt-viewer-loop-fix

    报告分析

    使用临时变量代替引用变量

    可以更好的做循环优化

    相关文章

      网友评论

          本文标题:opt-viewer帮助编译器生成更好的代码

          本文链接:https://www.haomeiwen.com/subject/kqvtkdtx.html