Search code examples
clangllvm

How to automatically register and load modern Pass in Clang?


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.


Solution

  • 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 ...