关于 llvm-passes
为编写 LLVM 优化与 IR 转换的开发者提供新 Pass Manager 指南,涵盖 Pass 插件、分析、测试和调试流程。
主要功能
- 01编写 FunctionPass 与 ModulePass
- 02注册并运行 Pass 插件
- 03使用控制流与别名分析
- 04修改 IR 并维护分析有效性
- 05通过 llvm-lit 和 FileCheck 测试
- 06检查、验证和调试 Pass
适用场景
- 01为 LLVM 编译器添加自定义优化
- 02实现内联、死代码消除或 lowering 转换
- 03分析循环与控制流结构
- 04定位 Pass 顺序或 IR 错误
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill llvm-passes安装后在 Claude Code 中输入/llvm-passes确认已加载。
详细介绍
LLVM Passes
用途
指导 Agent 使用 New Pass Manager 编写 LLVM 优化 Pass:FunctionPass 和 ModulePass 结构、PassPluginLibraryInfo 注册、通过 opt -load-pass-plugin 运行、常见分析工具(DominatorTree、LoopInfo、AliasAnalysis)、IR 修改模式、使用 llvm-lit 测试,以及通过 opt -print-after-all 调试。
适用场景
- 为基于 LLVM 的编译器添加自定义优化
- 编写 IR 转换 Pass(内联、DCE、自定义降级)
- 使用支配树或循环信息分析控制流
- 使用 FileCheck 和 llvm-lit 测试 Pass
- 调试 Pass 顺序和 IR 损坏问题
- 通过插件将 Pass 集成到 Clang
工作流
1. New 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;
}
(New 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 中的名称 |
| 模块验证失败 | 转换后 SSA 已损坏 | 运行 -verify-each;检查 use-def 链 |
| 分析结果过期 | 修改 IR 后未使分析失效 | 返回 PreservedAnalyses::none() |
| 插件加载错误 | LLVM 版本不匹配 | 使用与 opt 相同的 LLVM 版本构建 |
| opt 输出为空 | 忘记使用 -S | 添加 -S 以输出文本 IR |
| lit 测试 FAIL | CHECK 行不匹配 | 运行 opt -S 并手动比较 |
相关技能
skills/compilers/llvm— 以用户身份检查 LLVM IR 并使用 opt 流水线skills/compiler-internals/compiler-frontend— 为 Pass 提供 IR 的生成过程skills/compiler-internals/jit-compilation— 使用 ORC JIT 运行优化后的 IRskills/compiler-internals/mlir— MLIR Pass(概念相似)skills/compilers/clang— Clang 优化标志skills/build-systems/cmake— 构建 Pass 插件
评论
支持 Markdown