How to write a custom intermodular pass in LLVM?

后端 未结 3 525
遇见更好的自我
遇见更好的自我 2020-12-31 11:33

I\'ve written a standard Analysis pass in LLVM, by extending the FunctionPass class. Everything seems to make sense.

Now what I\'d like to do is write a couple of in

相关标签:
3条回答
  • 2020-12-31 11:58

    This can be done using a module pass. Below is my code, and if you need help running it you can look here.

    bar.c

    int your_fun(int arg2) {
        int x = arg2;
        return x+2;
    }
    

    Skeleton.cpp

    #include "llvm/Pass.h"
    #include "llvm/IR/Module.h"
    #include "llvm/Support/raw_ostream.h"
    #include "llvm/IR/LegacyPassManager.h"
    #include "llvm/Transforms/IPO/PassManagerBuilder.h"
    using namespace llvm;
    
    namespace {
      struct SkeletonPass : public ModulePass {
        static char ID;
        SkeletonPass() : ModulePass(ID) {}
    
        virtual bool runOnModule(Module &M) {
            for (auto& F : M) {
                errs() << "\tFunction: " << F.getName() << "\n";
    
                for (auto& BB : F) {
                    errs() << "\t\tBasic Block: " << BB.getName() << "\n";
    
                    for (auto& I : BB) {
                        errs() << "\t\t\tInstruction: " << I.getOpcodeName() << "\n";
                    }
                }
            }
    
            return false;
        }
      };
    }
    
    char SkeletonPass::ID = 0;
    
    // Automatically enable the pass.
    // http://adriansampson.net/blog/clangpass.html
    static void registerSkeletonPass(const PassManagerBuilder &,
                             legacy::PassManagerBase &PM) {
      PM.add(new SkeletonPass());
    }
    
    static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_ModuleOptimizerEarly,
                                                    registerSkeletonPass);
    
    static RegisterStandardPasses RegisterMyPass1(PassManagerBuilder::EP_EnabledOnOptLevel0,
                                                    registerSkeletonPass);
    

    Output:

    | => clang -Xclang -load -Xclang build/skeleton/libSkeletonPass.so foo.c bar.c
    Module: foo.c!
            Function: my_fun!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: load
                Instruction: store
                Instruction: load
                Instruction: add
                Instruction: ret
            Function: main!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: load
                Instruction: icmp
                Instruction: br
                Basicblock: if.then!
                Instruction: load
                Instruction: store
                Instruction: br
                Basicblock: if.else!
                Instruction: load
                Instruction: call
                Instruction: store
                Instruction: br
                Basicblock: if.end!
                Instruction: load
                Instruction: ret
    Module: bar.c!
            Function: your_fun!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: load
                Instruction: store
                Instruction: load
                Instruction: add
                Instruction: ret
    

    Output: If you include header file linking to bar.c

    Module: foo.c!
            Function: your_fun!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: load
                Instruction: store
                Instruction: load
                Instruction: add
                Instruction: ret
            Function: my_fun!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: load
                Instruction: store
                Instruction: load
                Instruction: add
                Instruction: ret
            Function: main!
                Basicblock: entry!
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: alloca
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: store
                Instruction: load
                Instruction: icmp
                Instruction: br
                Basicblock: if.then!
                Instruction: load
                Instruction: store
                Instruction: br
                Basicblock: if.else!
                Instruction: load
                Instruction: call
                Instruction: store
                Instruction: load
                Instruction: call
                Instruction: store
                Instruction: br
                Basicblock: if.end!
                Instruction: load
                Instruction: ret
    
    0 讨论(0)
  • 2020-12-31 12:07

    I found one way to achieve my goal: write a simple program that uses llvm::parseBitcodeFile() to read in a bitcode file and create a Module object that can be traversed and analyzed. It's not ideal, because it's not a Pass that can be run within the LLVM framework. However, it is a way to achieve my goal of analyzing multiple modules at once.

    For future readers, here's what I did.

    Create a simple tool to read in a bitcode file and produce a Module

    //ReadBitcode.cpp
    #include <iostream>
    #include "llvm/IR/Module.h"
    #include "llvm/Support/MemoryBuffer.h"
    #include "llvm/Support/SourceMgr.h"
    #include "llvm/IR/LLVMContext.h"
    #include "llvm/Bitcode/ReaderWriter.h"
    
    using namespace llvm;
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            std::cerr << "Usage: " << argv[0] << " bitcode_filename" << std::endl;
            return 1;
        }
        StringRef filename = argv[1];
        LLVMContext context;
    
        ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr = MemoryBuffer::getFileOrSTDIN(filename);
        if (std::error_code ec = fileOrErr.getError())
        {
            std::cerr << "Error opening input file: " + ec.message() << std::endl;
            return 2;
        }
    
        ErrorOr<llvm::Module *> moduleOrErr = parseBitcodeFile(fileOrErr.get()->getMemBufferRef(), context);
        if (std::error_code ec = fileOrErr.getError())
        {
            std::cerr << "Error reading Module: " + ec.message() << std::endl;
            return 3;
        }
    
        Module *m = moduleOrErr.get();
        std::cout << "Successfully read Module:" << std::endl;
        std::cout << " Name: " << m->getName().str() << std::endl;
        std::cout << " Target triple: " << m->getTargetTriple() << std::endl;
    
        for (auto iter1 = m->getFunctionList().begin(); iter1 != m->getFunctionList().end(); iter1++)
        {
            Function &f = *iter1;
            std::cout << "  Function: " << f.getName().str() << std::endl;
            for (auto iter2 = f.getBasicBlockList().begin(); iter2 != f.getBasicBlockList().end();
                 iter2++)
            {
                BasicBlock &bb = *iter2;
                std::cout << "    BasicBlock: " << bb.getName().str() << std::endl;
                for (auto iter3 = bb.begin(); iter3 != bb.end(); iter3++)
                {
                    Instruction &i = *iter3;
                    std::cout << "      Instruction: " << i.getOpcodeName() << std::endl;
                }
            }
        }
        return 0;
    }
    

    Compile the tool

    $ clang++ ReadBitcode.cpp -o reader `llvm-config --cxxflags --libs --ldflags --system-libs`
    

    Create a bitcode file to analyze

    $ cat foo.c 
    int my_fun(int arg1){
        int x = arg1;
        return x+1;
    }
    
    int main(){
        int a = 11;
        int b = 22;
        int c = 33;
        int d = 44;
        if (a > 10){
            b = c;
        } else {
            b = my_fun(d);
        }
        return b;
    }
    
    $ clang -emit-llvm -o foo.bc -c foo.c
    

    Run the reader tool on the bitcode

    $ ./reader foo.bc
    Successfully read Module:
     Name: foo.bc
     Target triple: x86_64-pc-linux-gnu
      Function: my_fun
        BasicBlock: 
          Instruction: alloca
          Instruction: alloca
          Instruction: store
          Instruction: load
          Instruction: store
          Instruction: load
          Instruction: add
          Instruction: ret
      Function: main
        BasicBlock: 
          Instruction: alloca
          Instruction: alloca
          Instruction: alloca
          Instruction: alloca
          Instruction: alloca
          Instruction: store
          Instruction: store
          Instruction: store
          Instruction: store
          Instruction: store
          Instruction: load
          Instruction: icmp
          Instruction: br
        BasicBlock: 
          Instruction: load
          Instruction: store
          Instruction: br
        BasicBlock: 
          Instruction: load
          Instruction: call
          Instruction: store
          Instruction: br
        BasicBlock: 
          Instruction: load
          Instruction: ret
    
    0 讨论(0)
  • 2020-12-31 12:17

    In LTO all the modules are combined and you can see the whole program IR in one module.

    You need to write a module pass like any module pass and add it to the list of LTO passes in populateLTOPassManager function in PassManagerBuilder.cpp. Here is the doc for PassManagerBuilder: http://llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html

    When you do this, your pass will be executed with other LTO passes.

    0 讨论(0)
提交回复
热议问题