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

2023-02-06  本文已影响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

报告分析

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

可以更好的做循环优化

上一篇下一篇

猜你喜欢

热点阅读