用 opt -print-before/-print-after 查看 ir 需严格匹配 new pm 下的 pass 全名(如 loop-vectorize 而非 loopvectorizepass),functionpass 才生效,modulepass 须用 -print-module-before,且必须通过 -passes 显式构造流水线才能触发打印。

直接用 opt 的 -print-before 和 -print-after 就能看,但必须注意 Pass 名称的写法和 IR 阶段匹配关系,否则什么也打不出来。
Pass 名称必须跟 opt -passes 列出来的完全一致
LLVM 15+ 默认启用新 Pass 管理器(New PM),opt -passes 输出的是实际注册名,不是类名或文件名。比如你想看 mem2reg,不能写 -print-before=mem2reg —— 它在 New PM 下叫 early-cse 或 instcombine 后才触发,真实名称得查:
- 先运行
opt -passes=help找到目标 Pass 的全名,例如loop-vectorize、gvn、simplifycfg - 有些 Pass 是 FunctionPass,有些是 ModulePass,
-print-before只对 FunctionPass 生效;ModulePass 要用-print-module-before - 名称区分大小写,且不带括号或参数,比如
loop-vectorize不是LoopVectorizePass
IR 打印位置受优化层级和 Pass 管理器影响
旧 Pass 管理器(Legacy PM)下用 -debug-pass=Structure 能看到执行顺序,但 New PM 下这套失效了。你得靠 -passes 显式构造流水线:
- 想只跑一个 Pass 并打印前后 IR:
opt -passes="print-before<instcombine>,instcombine,print-after<instcombine>" input.ll</instcombine></instcombine> - 如果用了
-O2,它背后是一整条流水线,-print-before只对紧邻的下一个 Pass 生效,不是对整个-O2生效 - 某些 Pass(如
loop-simplify)只在函数内有循环时才运行,空函数不会触发,也就没输出
输出内容默认是 LLVM IR,但可被重定向或过滤
opt 默认把 IR 打到 stderr,容易跟其他日志混在一起。建议加 -S 保证文本格式,并用 shell 重定向分离:
-
opt -passes="print-before<gvn>,gvn" -S input.ll 2> gvn-before.ll > /dev/null</gvn>—— 把 GVN 前的 IR 提取出来 - 若 IR 太长,可用
llvm-dis先转成可读格式,再用grep过滤关键函数:opt -passes="print-before<instcombine>" input.bc 2>&1 | llvm-dis | grep -A5 -B5 "define.*foo"</instcombine> - 注意:
print-before输出的是 Pass 运行前的 *当前* IR 状态,不是原始输入;多次打印时需确认中间是否已有其他 Pass 修改过 IR
最容易被忽略的一点:New PM 下,Pass 名称和执行时机高度依赖 -passes 流水线定义,而不是全局开关。不显式写流水线,-print-before 很可能根本没机会触发。











