LLVM Running your first pass simplified.

After so much of struggle of many hours finally I found some step guide which can be useful for writing the pass successfully. I hope it will save your time. Dont know why no one make this simple for novice. I assume your llvm build environment is ready and installed with llvm, cmake and ninja. I dont want to mix it up here to make this more complex.

Step1: Create a directory to host your LLVM pass

mkdir ~/llvm-project/llvm/lib/Transforms/test

Step2: Update the CMake file in the Transforms directory

~/llvm/llvm/lib/Transforms/CMakeLists.txt

vim CMakeLists.txt 

Add this line add_subdirectory(test)

Now goto your folder test

cd test

Now we will work inside test folder.

Step3 Create a CMake file for your LLVM pass

vim CMakeLists.txt

Add the following to the CMakeLists.txt file

add_llvm_library(LLVMtest MODULE test.cpp

PLUGIN_TOOL opt )

**Step4 **create CPP file for your LLVM pass

vim test.cpp

with following code

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

using namespace llvm;

namespace {
struct test : public FunctionPass {
  static char ID;
  test() : FunctionPass(ID) {}

  bool runOnFunction(Function &F) override {
    errs() << "Hello: ";
    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct Hello
}  // end of anonymous namespace

char test::ID = 0;
static RegisterPass<test> X("test", "Hello World Pass",
                             false /* Only looks at CFG */,
                             false /* Analysis Pass */);

static RegisterStandardPasses Y(
    PassManagerBuilder::EP_EarlyAsPossible,
    [](const PassManagerBuilder &Builder,
       legacy::PassManagerBase &PM) { PM.add(new test()); });

Step5: Generate the IR file clang++ -O0 -g -S -emit-llvm -o test.ll -c test.cpp

Step6: Now we will move to build folder

cd ~/llvm-project/build

(There is some problem in CMakeCache.txt regarding user name. Find and replace cpen400 with cpen)

vim CMakeCache.txt

:s/cpen400/cpen/g :wr and quit

Step7: Now run the cmake with path as .. will not work

~/llvm-project/build$ cmake ../llvm/lib/Transforms/test

Step8: Now run Ninja

~/llvm-project/build$ninja -j4

Step9: Now it will build full llvm project in 2 hours. Wait for it and move to lib directory to check .so file.

cd lib
ls -l

Step 10: Now to test this pass create a dummy program hello.c in your test directory:

void a(){
  int c = 5;
}

int main()
{
  int d = 1;
  a();
  return 5;
}

Step 11: Now create the IR file using

clang++ -O0 -g -S -emit-llvm -o fun.ll -c fun.c

Step12: Go back to ~/llvm-project/build directory and load the pass using "opt"

cd..
opt -enable-new-pm=0 -load lib/LLVMtest.so -test < ../llvm/lib/Transforms/test/fun.ll > /dev/null

You may see output like

Hello: _Z1av 
Hello: main 


Written By

Vinod Kotiya



Comments