I'm trying to write a simple "modern" LLVM pass and use it with Clang. I want it to be able to be run with a command like:
clang -Xclang -load -Xclang libMyPass.so file.cpp
There are a lot of manuals on how to integrate legacy pass into Clang. However, there is not so much info on the new pass manager. I came across a series of articles called 'Writing LLVM Pass in 2018'. But it only mentions a case when your pass code is placed inside the LLVM code tree. And I need the module to be built out-of-tree.
class MyPass : public llvm::PassInfoMixin<MyPass> {
public:
llvm::PreservedAnalyses run(
llvm::Function &F,
llvm::FunctionAnalysisManager &FAM
) {
// Pass code here
}
};
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
return {
LLVM_PLUGIN_API_VERSION, "MyPass", "v0.1",
[](llvm::PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](
llvm::StringRef Name, llvm::FunctionPassManager &FPM,
llvm::ArrayRef <llvm::PassBuilder::PipelineElement>
) {
if (Name == "my-pass") {
FPM.addPass(MyPass());
return true;
}
return false;
}
);
}
};
}
At the moment, the pass is not being executed. I tried to look at -print-after-all option output and using std::cout
to detect whether it has run. I cannot see my pass in logs. Neither I can see my debug output in the console window.
It's possible now.
Sample plugin registration code:
PassPluginLibraryInfo getPassPluginInfo() {
const auto callback = [](PassBuilder &PB) {
PB.registerPipelineEarlySimplificationEPCallback([&](ModulePassManager &MPM, auto) {
MPM.addPass(MyPass());
return true;
});
};
return {LLVM_PLUGIN_API_VERSION, "name", "0.0.1", callback};
};
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
return getPassPluginInfo();
}
Sample clang invocation code (assuming you built your plugin as a shared library):
clang++ -O0 -g -fpass-plugin=pass.so ...