如何在单个文件中同时注册LLVM函数Pass与模块Pass?
如何在单个LLVM新Pass Manager插件中同时注册FunctionPass和ModulePass
你遇到的问题核心在于registerPipelineParsingCallback的回调签名需要匹配不同类型的PassManager(FunctionPassManager或ModulePassManager),不能直接把两者同时作为参数传入同一个lambda。下面是两种可行的解决方案:
方案1:注册多个独立的回调函数
最直观的方式是分别注册两个registerPipelineParsingCallback调用,每个回调对应一种PassManager类型,分别处理你的FunctionPass和ModulePass:
修正后的完整代码如下:
#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" namespace { struct HelloNewPMPass : public llvm::PassInfoMixin<HelloNewPMPass> { llvm::PreservedAnalyses run(llvm::Function &F, llvm::FunctionAnalysisManager &FAM) { llvm::errs() << "Running HelloNewPMPass on function: " << F.getName() << "\n"; return llvm::PreservedAnalyses::all(); } }; // 注意修正PassInfoMixin的模板参数为当前类名(你之前写的StringEncryptionPass是笔误) struct SecondPass : public llvm::PassInfoMixin<SecondPass> { llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM) { llvm::errs() << "Running SecondPass on module: " << M.getName() << "\n"; return llvm::PreservedAnalyses::all(); } }; } extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() { return { LLVM_PLUGIN_API_VERSION, "MultiPassPlugin", "v0.1", [](llvm::PassBuilder &PB) { // 注册处理FunctionPass的回调 PB.registerPipelineParsingCallback( [](llvm::StringRef PassName, llvm::FunctionPassManager &FPM, auto...) { if (PassName == "fiber") { FPM.addPass(HelloNewPMPass()); return true; } return false; } ); // 注册处理ModulePass的回调 PB.registerPipelineParsingCallback( [](llvm::StringRef PassName, llvm::ModulePassManager &MPM, auto...) { if (PassName == "second-pass") { MPM.addPass(SecondPass()); return true; } return false; } ); } }; }
方案2:使用泛型Lambda统一处理多种PassManager类型
如果你倾向于用单个回调覆盖两种场景,可以利用C++17的泛型Lambda和constexpr if来判断传入的PassManager类型:
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() { return { LLVM_PLUGIN_API_VERSION, "MultiPassPlugin", "v0.1", [](llvm::PassBuilder &PB) { PB.registerPipelineParsingCallback( [](llvm::StringRef PassName, auto &PM, auto...) { using PMType = std::decay_t<decltype(PM)>; // 编译时判断PassManager类型 if constexpr (std::is_same_v<PMType, llvm::FunctionPassManager>) { if (PassName == "fiber") { PM.addPass(HelloNewPMPass()); return true; } } else if constexpr (std::is_same_v<PMType, llvm::ModulePassManager>) { if (PassName == "second-pass") { PM.addPass(SecondPass()); return true; } } return false; } ); } }; }
关键注意事项
- 修正
SecondPass的PassInfoMixin模板参数:你之前写的StringEncryptionPass是笔误,必须改为当前类名SecondPass,否则会触发编译错误。 - 编译器版本要求:两种方案都需要编译器支持C17(LLVM本身也要求C17及以上版本)。
- 运行方式:使用
opt命令时可以分别或同时指定两个Pass,比如:- 单独运行FunctionPass:
opt -passes="fiber" -disable-output input.ll - 单独运行ModulePass:
opt -passes="second-pass" -disable-output input.ll - 同时运行两个Pass:
opt -passes="second-pass,fiber" -disable-output input.ll(ModulePass通常先于FunctionPass执行)
- 单独运行FunctionPass:
内容的提问来源于stack exchange,提问作者HAPPY
相关产品推荐
相关产品推荐

