用途
LLVM Passes 技能用于指导代理编写 LLVM 优化 Pass,基于新 Pass Manager(New Pass Manager)。它覆盖 FunctionPass 与 ModulePass 的结构、PassPluginLibraryInfo 注册、通过 opt -load-pass-plugin 运行、常用分析工具(DominatorTree、LoopInfo、AliasAnalysis)、IR 修改模式、llvm-lit 测试,以及使用 opt -print-after-all 进行调试。
适用场景
- 为基于 LLVM 的编译器添加自定义优化
- 编写 IR 变换 Pass(内联、死代码消除、自定义 lowering)
- 使用支配树或循环信息分析控制流
- 使用 FileCheck 和 llvm-lit 测试 Pass
- 调试 Pass 顺序与 IR 损坏
- 通过插件将 Pass 集成到 Clang
工作流程
1. 新 Pass Manager 架构
opt / clang
├── ModulePassManager
│ └── FunctionPassManager (per function)
│ └── FunctionPass instances
└── AnalysisManager (cached analyses)
Pass 声明其分析使用;IR 变更时分析会失效。
2. 最小 FunctionPass(C++ 插件)
// MyPass.cpp
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct MyPass : PassInfoMixin<MyPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
bool changed = false;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (auto *Call = dyn_cast<CallInst>(&I)) {
if (Call->getCalledFunction() &&
Call->getCalledFunction()->getName() == "dead_func") {
Call->eraseFromParent();
changed = true;
}
}
}
}
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
}
};
} // namespace
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
return {
LLVM_PLUGIN_API_VERSION, "MyPass", "v0.1",
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "my-pass") {
FPM.addPass(MyPass());
return true;
}
return false;
});
}
};
}
# CMakeLists.txt
find_package(LLVM REQUIRED CONFIG)
add_library(MyPass MODULE MyPass.cpp)
target_include_directories(MyPass SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS})
target_compile_definitions(MyPass PRIVATE ${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs core passes support)
target_link_libraries(MyPass PRIVATE ${llvm_libs})
cmake -B build -DLLVM_DIR=$(llvm-config --cmakedir)
cmake --build build
3. 使用 opt 运行
# Run pass on IR file
opt -load-pass-plugin ./build/MyPass.so -passes=my-pass -S input.ll -o output.ll
# Print IR after each pass
opt -load-pass-plugin ./build/MyPass.so -passes=my-pass -print-after-all input.ll -o /dev/null
# Pass pipeline string
opt -passes="function(instcombine),my-pass,function(dce)" input.ll -S -o out.ll
4. ModulePass 示例
struct MyModulePass : PassInfoMixin<MyModulePass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
for (Function &F : M) {
if (F.isDeclaration()) continue;
// module-level transformation
}
return PreservedAnalyses::none();
}
};
在插件回调中注册到 ModulePassManager。
5. 分析工具
#include "llvm/Analysis/DominatorTree.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/AliasAnalysis.h"
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &AA = AM.getResult<AAManager>(F);
for (Loop *L : LI) {
BasicBlock *Header = L->getHeader();
// Loop invariant code motion, etc.
}
DominatorTreeNode *IDom = DT.getNode(&F.getEntryBlock());
(void)IDom;
return PreservedAnalyses::all();
}
声明使用的分析:
AnalysisUsage MyLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
return AU;
}
(新 PM:通过 AM.getResult<> 请求分析——依赖自动跟踪。)
6. IR 修改模式
// Insert instruction before iterator
IRBuilder<> Builder(&*I.getIterator());
Value *NewVal = Builder.CreateAdd(I.getOperand(0), ConstantInt::get(I.getType(), 1));
I.replaceAllUsesWith(NewVal);
I.eraseFromParent();
// Clone basic block
BasicBlock *Clone = CloneBasicBlock(OrigBB, VMap, ".clone", &F);
// Create function
FunctionCallee Fn = M.getOrInsertFunction("my_fn",
FunctionType::get(Builder.getVoidTy(), false));
结构变更后始终更新 SSA 并使分析失效。
7. llvm-lit 测试
test/
├── lit.cfg.py
└── my-pass.test
# my-pass.test
# RUN: opt -load-pass-plugin %shlibdir/MyPass.so -passes=my-pass -S %s | FileCheck %s
define void @test() {
call void @dead_func()
ret void
}
; CHECK-NOT: dead_func
llvm-lit test/my-pass.test -v
8. 调试 Pass
# Verify IR after pass
opt -load-pass-plugin ./MyPass.so -passes=my-pass input.ll -o out.ll
opt -verify-each out.ll
# Time passes
opt -passes=my-pass -time-passes input.ll -o /dev/null
# Debug pass manager
OPT_DEBUG=1 opt -passes=my-pass input.ll -o /dev/null
常见问题
| 症状 | 原因 | 修复 |
|---|---|---|
| Pass not found: my-pass | 插件未加载或名称不匹配 | 检查 registerPipelineParsingCallback 名称 |
| Verify module failed | 变换后 SSA 损坏 | 运行 -verify-each;检查 use-def 链 |
| Analysis stale | 修改 IR 但未失效分析 | 返回 PreservedAnalyses::none() |
| Plugin load error | LLVM 版本不匹配 | 使用与 opt 相同的 LLVM 构建 |
| Empty opt output | 忘记 -S | 添加 -S 输出文本 IR |
| lit test FAIL | CHECK 行不匹配 | 用 opt -S 手动对比 |
相关技能
- skills/compilers/llvm — 以用户身份检查 LLVM IR 与 opt 流水线
- skills/compiler-internals/compiler-frontend — 为 Pass 提供输入的 IR 生成
- skills/compiler-internals/jit-compilation — 运行优化后 IR 的 ORC JIT
- skills/compiler-internals/mlir — MLIR Pass(概念类似)
- skills/compilers/clang — Clang 优化标志
- skills/build-systems/cmake — 构建 Pass 插件