最近 Compiler Explorer 支持了显示 LLVM Opt Pipeline Output 的能力,对于我们理解一个函数经历了哪些 pass 的细节非常有帮助。简单推荐一下这个工具。
1、Opt Pipeline
优化是可选的选项,默认是不进行优化,在 LLVM 当中会有各种不同级别的优化。可能会包含有不同的优化、不同顺序的优化或者不同阶段的优化。
Opt Pipeline 是一连串执行的 pass,第一个 pass 对某部分代码执行完,随后下一个 pass 对同样的部分执行;一个函数完成了 pass 流水线,下一个函数就开始执行。
理解优化操作,实际上就是理解 IR 如何在 pass 流水线中被修改,这需要知道每个 pass 执行的修改,还有各个 pass 是以什么顺序被执行。
2、查看
虽然目前只能看一个函数而无法看到整体的 IR 变化,从 MR 来看相信会支持到展示整个 module。
一些高亮的 pass 还支持点击查看具体的修改。
3、调试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# 输出 debug 信息,编译 LLVM 时需要开启 cmake -DLLVM_ENABLE_ASSERTIONS=ON
# 每个文件会存在 DEBUG_TYPE 的宏,其名字即为 debug id
opt -debug-only=<debug id>
opt -debug
opt -debug-pass-manager
# 输出统计信息,与 STATISTIC(<id>, <string>) 宏相关
opt -stats
# 用来查看一个 pass 前后的 IR 变化
opt -print-[before | after]-all
opt -print-changed
# 用 cfg 图来看
opt -print-changed=[dot-cfg | dot-cfg-quiet] -print-changed-dot-path=<path>
# 只查看特定的 pass
opt -filter-pass=<pass name>
# 只查看特定符号名的函数
opt -filter-print-funcs=<mangle symbol>
# 查看 module 视角
opt -print-module-scope
|
在 LLVM 中,优化级别的 pipeline 主要是在 PassBuilder 中指定。pass pipeline 是由 PassManager 来进行管理,包括它们的执行顺序。
1
2
3
4
5
6
7
8
9
10
|
// clang/lib/CodeGen/BackendUtil.cpp
if (CodeGenOpts.OptimizationLevel == 0) {
MPM = PB.buildO0DefaultPipeline(Level, IsLTO || IsThinLTO);
} else if (IsThinLTO) {
MPM = PB.buildThinLTOPreLinkDefaultPipeline(Level);
} else if (IsLTO) {
MPM = PB.buildLTOPreLinkDefaultPipeline(Level);
} else {
MPM = PB.buildPerModuleDefaultPipeline(Level);
}
|
参考