如何通过LLVM API在程序中用新Pass Builder运行Pass优化IR
基于LLVM新Pass管理器在程序内优化内存IR模块的实现方案
一、核心步骤拆解
1. 加载本地Pass库
如果自定义Pass是编译为动态库的,用LLVM的llvm::sys::DynamicLibrary实现加载:
- 调用
llvm::sys::DynamicLibrary::LoadLibraryPermanently传入动态库路径完成加载 - 通过
sys::DynamicLibrary::SearchForAddressOfSymbol查找插件标准入口符号llvmGetPassPluginInfo - 将符号转换为函数指针并调用,获取
PassPluginInfo结构体,执行其中的注册回调,把Pass注册到全局PassBuilder中
如果是静态库,无需动态加载,编译时直接链接即可。
2. 构建顺序执行的Pass管线
用llvm::PassBuilder构建管线,有两种常用方式:
- 手动添加:创建
llvm::ModulePassManager对象,调用addPass依次添加自定义Pass或标准Pass - 管线字符串解析:用
PassBuilder::parsePipeline解析类似"my-custom-pass,instcombine"的字符串,自动按顺序添加Pass - 若需要标准优化级别(如-O2),可调用
PassBuilder::buildPerModuleDefaultPipeline生成对应管线,再追加自定义Pass
3. 应用管线优化IR模块
- 创建
llvm::AnalysisManager<llvm::Module>,用于管理Pass执行所需的分析结果 - 调用
ModulePassManager::run,传入内存中的Module对象和AnalysisManager完成优化 - 执行后原Module对象(或传入的拷贝)会被直接修改,可直接使用内存中的优化后IR
二、源码树外编译链接要点
编译时需要链接LLVM核心静态库,可通过llvm-config工具获取依赖:
- 编译参数:
$(llvm-config --cxxflags) - 链接参数:
$(llvm-config --libs core passes support demangle analysis transformutils passbuilder) - 自定义Pass动态库编译需加
-fPIC -shared参数
三、完整示例代码
主程序代码(内存IR优化)
#include "llvm/IR/Module.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; int main() { // 模拟内存中的IR模块(实际场景可从内存加载/生成) LLVMContext Context; std::unique_ptr<Module> M = std::make_unique<Module>("MyModule", Context); // 1. 加载自定义Pass动态库 StringRef PassLibPath = "./libMyCustomPass.so"; if (!sys::DynamicLibrary::LoadLibraryPermanently(PassLibPath.data())) { errs() << "加载Pass库失败: " << PassLibPath << "\n"; return 1; } // 获取插件入口函数 void *PluginEntry = sys::DynamicLibrary::SearchForAddressOfSymbol("llvmGetPassPluginInfo"); if (!PluginEntry) { errs() << "找不到插件入口符号\n"; return 1; } // 注册Pass到全局PassBuilder auto GetPluginInfo = reinterpret_cast<decltype(&llvmGetPassPluginInfo)>(PluginEntry); const PassPluginInfo &PluginInfo = GetPluginInfo(); PluginInfo.RegisterPassBuilderCallbacks(*PassBuilder::getGlobalPassBuilder()); // 2. 构建Pass管线 ModulePassManager MPM; AnalysisManager<Module> AM; // 示例:解析管线字符串,按顺序执行自定义Pass+instcombine StringRef PipelineStr = "my-custom-pass,instcombine"; if (Error E = PassBuilder().parsePipeline(MPM, PipelineStr, PassBuilder::PipelineParsingOptions{})) { errs() << "解析管线失败: " << toString(std::move(E)) << "\n"; return 1; } // 可选:替换为-O2标准管线+追加自定义Pass // PassBuilder PB; // MPM = PB.buildPerModuleDefaultPipeline(PassBuilder::OptimizationLevel::O2); // MPM.addPass(MyCustomPass()); // 3. 运行管线优化模块 MPM.run(*M, AM); // 输出优化后的IR(实际场景直接使用内存中的Module即可) M->print(outs(), nullptr); return 0; }
自定义Pass插件代码
#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/PassManager.h" using namespace llvm; struct MyCustomPass : public PassInfoMixin<MyCustomPass> { PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { // 这里写你的自定义Pass逻辑 errs() << "运行MyCustomPass处理模块: " << M.getName() << "\n"; return PreservedAnalyses::all(); } }; extern "C" LLVM_ATTRIBUTE_WEAK PassPluginInfo llvmGetPassPluginInfo() { return { LLVM_PLUGIN_API_VERSION, "MyCustomPass", "v0.1", [](PassBuilder &PB) { PB.registerPipelineParsingCallback( [](StringRef Name, ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement>) { if (Name == "my-custom-pass") { MPM.addPass(MyCustomPass()); return true; } return false; } ); } }; }
编译命令
- 编译自定义Pass动态库:
clang++ -fPIC -shared MyCustomPass.cpp -o libMyCustomPass.so $(llvm-config --cxxflags --libs core passes support analysis) - 编译主程序:
clang++ Main.cpp -o Main $(llvm-config --cxxflags --libs core passes support demangle analysis transformutils passbuilder)
四、关键API说明
llvm::sys::DynamicLibrary:动态库加载与符号查找工具llvm::PassBuilder:新Pass管理器的核心,负责管线构建、Pass注册、管线解析llvm::ModulePassManager:模块级Pass的容器,管理Pass执行顺序llvm::AnalysisManager<Module>:管理Pass依赖的分析结果,是Pass执行的必要参数PassPluginInfo:Pass插件的标准信息结构体,包含Pass注册逻辑
内容的提问来源于stack exchange,提问作者StudyingCui
相关产品推荐
相关产品推荐

