Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically register and load modern Pass in Clang?

Tags:

llvm

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.

like image 837
Alexander Batashev Avatar asked Jan 30 '19 19:01

Alexander Batashev


1 Answers

Two years later, there is still little information available on doing this. It took me a while to figure it out for my own pass.

First, to get clang to use your pass library:

clang -O1 -fexperimental-new-pass-manager -fpass-plugin=libMyPass.so file.cpp

Note that the -O1 flag is important (I'll come to that later).

As for your pass, there is no way I can find to force clang to use the "parsing pipeline", so we have to use one of the other optimizer extension points on llvm::PassBuilder (nearly all of these require an optimisation level of one or above, hence -O1). Since your pass's run method takes a Function, we need an extension point callback that takes a FunctionPassManger. We'll use registerVectorizerStartEPCallback.

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.registerVectorizerStartEPCallback(
                [](
                    llvm::FunctionPassManager &FPM,
                    llvm::OptimizationLevel &O
                ) {
                    FPM.addPass(MyPass());
                  }
            );
        }
    };
}

This code is only correct as of LLVM 11. Later versions have new PassBuilder extension points and have removed or renamed some of the older ones. registerVectorizerStartEPCallback is still there in LLVM 13 though.

I've spent a good while trying to figure out if I could force clang to use a custom pass by constructing a new FunctionPassMangager etc., but there seems to be no way to make clang use it. The optimizer extension points seem to be your only option if you want to stick with out-of-tree passes.

A tip - reading the LLVM header files or grepping through the clang source tree are very helpful when doing anything like this.

like image 136
Magnus Avatar answered Nov 19 '22 22:11

Magnus