用Clang将C++转LLVM IR:clang++ -S -emit-llvm -O2 input.cpp -o input.ll(文本)或clang++ -c -emit-llvm -O0 input.cpp -o input.bc(二进制);再用opt调用内置Pass优化,如opt -simplifycfg -dce input.bc -o output.bc。

直接用 opt 工具跑内置 Pass 就行,不需要写代码;想定制逻辑才需要开发自定义 Pass。
怎么把 C++ 代码转成 LLVM IR 并喂给 opt
Clang 是最顺手的前端,它能把 C++ 源码一步生成可读或不可读的 IR:
- 生成人类可读的文本 IR:
clang++ -S -emit-llvm -O2 input.cpp -o input.ll - 生成二进制 bitcode(
.bc,opt更倾向处理这个):clang++ -c -emit-llvm -O0 input.cpp -o input.bc - 注意:
-O0避免前端自带优化干扰你后续对 IR 的控制;真要对比优化效果,建议统一用-O0生成原始 IR,再用opt显式加 Pass
怎么用 opt 命令行调用常见优化 Pass
opt 是 LLVM 的 IR 优化器,不编译、不生成机器码,只改 IR。常用组合有:
- 做一次死代码消除:
opt -simplifycfg -dce input.bc -o output.bc - 模拟
-O2中端流程(精简版):opt -passes='default' input.bc -o output.bc - 展开循环 + 向量化(需 IR 已含足够元信息):
opt -loop-unroll -slp-vectorizer input.bc -o output.bc - 查看某个 Pass 是否真的修改了 IR:加
-debug-pass=Structure或用-print-after-all(输出巨大,建议配合grep过滤)
为什么自己写的 Pass 加不进 opt 或没生效
这是最常卡住的地方,核心问题不在逻辑,而在加载和触发时机:
- Pass 必须编译成动态库(
.so/.dylib),且导出符号要匹配;CMake 中add_library(... MODULE ...)不能写成SHARED - 注册名(如
"my-pass")必须和opt -load ./libMyPass.so -my-pass里的名字完全一致,大小写、连字符都不能错 -
runOnFunction返回true才算“IR 被修改”,否则opt可能跳过后续依赖该修改的 Pass - 如果 IR 来自 Clang 的
-O2,它可能已经内联/去虚拟化/折叠完毕,你的 Pass 想找虚函数调用点或未优化分支,大概率找不到——先用-O0生成干净 IR
真正难的不是写 Pass,而是让 IR 处于你期望的形态:变量是否还在 SSA 形式、CallInst 是否还保留原始符号、Metadata(如 !prof)有没有被 strip 掉。这些细节不显眼,但一错就整段失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











