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

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

作者: somedays | 来源:发表于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

报告分析

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

可以更好的做循环优化

相关文章

  • c++:模板

    编译器会根据代码自动生成函数。

  • 编译器前端和后端

    编译器粗略分为词法分析,语法分析,类型检查,中间代码生成,代码优化,目标代码生成,目标代码优化。把中间代码生成及之...

  • Mac下的Java:生成.java文件和.class文件

    生成.java文件 1:打开文本编译器 文本编译器打开是这个样子滴: 2:写入java代码 生成.class文件 ...

  • 探索C#之6.0语法糖剖析

    自动属性默认初始化 使用方法: 编译器生成代码: 从生成代码中可以看出编译器是在实例化构造函数时,初始化属性信息的...

  • Flutter 前端编译器编译流程分析

    1. 前端编译器和后端编译器的区别 编译流程粗略分为词法分析、语法分析、类型检查、中间代码生成、代码优化、目标代码...

  • 编译原理——寄存器

    •代码生成是编译器的最后阶段。代码生成器通过前端产生的中间表示法或者通过代码优化器在代码优化阶段,映射到目标程序中...

  • TypeScript Downleveling - 什么是 Ty

    下列 TypeScript 代码: 使用 tsc 编译器编译之后生成的 JavaScript 代码: 为什么字符串...

  • 知识点OC文件生成C++文件

    生成 使用clang编译器将Objective-C代码编译成C语言代码, 并生成在一个.cpp的 C++文件中: ...

  • 编译器的工作过程

    编译器的工作过程划分为:词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成。 词法分析器的任务是把...

  • CodeGenerator代码生成器

    CodeGenerator代码生成器 CodeGenerator是一个JavaEE代码生成器,它可以帮助我们生成一...

网友评论

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

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