Write an LLVM Pass


In this post, I will show how I write an LLVM pass. I will also share how I solve some common problems which are not addressed in LLVM documents and tutorials. Note that this post is about how to write a new pass, not a Hello pass in most LLVM tutorials.


Part 0: Install LLVM

1
mkdir llvm-source

Version matters in LLVM. Make sure you download the same version of LLVM and Clang, and also read the tutorials and documents for that particular version. Do not download directly from the svn repository unless you are LLVM developers. If you are just using LLVM, download the stable releases will save you lots of effort. Download the LLVM and Clang from this link.

To install LLVM and Clang (I use 3.4.2 as an example, other versions should be similar):

1
2
3
4
tar xvzf llvm-3.4.2.src.tar.gz
mv llvm-3.4.2.src src
tar xvzf cfe-3.4.2.src.tar.gz
mv cfe-3.4.2.src src/tools/clang

Then install LLVM:

1
2
3
4
5
cd llvm-source
mkdir build
cd build
./../src/configure
make

Done!


Part 1: Write a New Pass

First, I will show you how to write a Candy pass.

1
2
3
cd llvm-source/build/lib/Transforms
mkdir Candy
vim Candy.cpp

Copy the following lines into Candy.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

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

        virtual bool runOnFunction(Function &F) {
            errs() << "Candy: ";
            errs().write_escaped(F.getName()) << '\n';
            return false;
        }
    };
}

char Candy::ID = 0;
static RegisterPass<Candy> X("candy", "Candy Pass", false, false);

Then copy the following lines into Makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Makefile for candy pass

# Path to top level of LLVM hierarchy
LEVEL = ../../..

# Name of the library to build
LIBRARYNAME = Candy

# Make the shared library become a loadable module so the tools can
# dlopen/dlsym on the resulting library.
LOADABLE_MODULE = 1

# Include the makefile implementation stuff
include $(LEVEL)/Makefile.common

If you write a new pass (instead of Hello), for example Candy, by following the tutorials above, you will probably run into the following error:

1
make: *** No rule to make target ‘/path/to/llvm-source/src/lib/Transforms/Candy/Makefile’, needed by ‘Makefile’. Stop.

This is because you write your new path in the build/ directory, and LLVM cannot find it in the src/ directory. Here is what you need to do to solve it.

1
2
3
4
5
6
7
cd llvm-source/src/lib/Transforms
mkdir Candy
cd Candy
vim Candy.cpp (save and exit, you don’t need to write anything in the file)
vim Makefile (copy the above Makefile into this one)
cd ..
vim CMakeLists.txt

Add the following line into llvm-source/src/lib/Transforms/CMakeLists.txt:

1
add_subdirectory(Candy)

Add one more file llvm-source/src/lib/Transforms/Candy/CMakeLists.txt with following lines:

1
2
3
add_llvm_loadable_module(LLVMCandy
    Candy.cpp
)

Then build LLVM again:

1
2
3
cd llvm-source/build
./../src/configure
make -j8

Then go to Candy and make again, the error message will disappear.

Write a program that you would like to run the candy analysis, and compile it into bitcode file:

1
2
3
4
5
cd llvm-source
mkdir projects
cd projects
vim test.cpp (write a program that you would like to run the analysis)
clang -O0 -emit-llvm -c test.cpp -o test.bc

Then run the following command to analyze it:

1
2
../../build/Release+Asserts/bin/opt -load 
../../build/Release+Asserts/bin/Candy.so -candy < test.bc > /dev/null


Part 2: Write a Pass with Multiple Files

In this part, I will show you how to include a Sweet.cpp and Sweet.h into your Candy pass.

1
2
3
4
5
6
7
8
9
10
cd llvm-source/build/lib/Transforms/Candy
mkdir include
mkdir src
cd include
vim Sweet.h (write your Sweet.h and save it)
cd ../src
mkdir Sweet
cd Sweet
vim Sweet.cpp (write your Sweet.cpp and save it)
vim Makefile

Copy the following into your /llvm-source/build/lib/Transforms/Candy/src/Sweet/Makefile

1
2
3
4
5
6
7
8
9
10
# Path to top level of LLVM hierarchy
LEVEL = ../../../../..

# Name of the library to build
LIBRARYNAME = Sweet

BUILD_ARCHIVE = 1

# Include the makefile implementation stuff
include $(LEVEL)/Makefile.common

Copy the following into your /llvm-source/build/lib/Transforms/Candy/src/Makefile

1
2
3
4
5
6
7
# Path to top level of LLVM hierarchy
LEVEL = ../../../..

DIRS = Sweet

# Include the makefile implementation stuff
include $(LEVEL)/Makefile.common

Modify your /llvm-source/build/lib/Transforms/Candy/Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Makefile for candy pass

# Path to top level of LLVM hierarchy
LEVEL = ../../..

# Name of the library to build
LIBRARYNAME = Candy

# Make the shared library become a loadable module so the tools can
# dlopen/dlsym on the resulting library.
LOADABLE_MODULE = 1
DIRS = src
EXTRA_DIST = include
# Include the makefile implementation stuff
include $(LEVEL)/Makefile.common

Add the corresponding files to your /llvm-source/src/lib/Transforms/Candy

1
2
3
4
5
6
7
8
9
cd llvm-source/src/lib/Transforms/Candy
mkdir include
mkdir src
cd include
vim Sweet.h (an empty file is okay)
cd ../src
mkdir Sweet
cd Sweet
vim Sweet.cpp (an empty file is okay)

Add the three Makefile above to the corresponding directory. Also modify the /llvm-source/src/lib/Transforms/Candy/CMakeLists.txt

1
2
3
4
add_llvm_loadable_module(LLVMCandy
    Candy.cpp
    src/Sweet/Sweet.cpp
)

Build LLVM again:

1
2
3
cd llvm-source/build
./../src/configure
make -j8

Then go to your Candy pass, you will be able to make your Candy pass with Sweet.cpp.

1
2
cd llvm-source/build/lib/Transforms/Candy
make

However, when you try to run your pass with your test files, you will probably run into the following error:

1
../../build/Release+Asserts/bin/opt: symbol lookup error: ../../build/Release+Asserts/lib/Candy.so: undefined symbol: _Z21runSweetRN4llvm8FunctionE

To solve this problem, you need to modify your /llvm-source/build/lib/Transforms/Candy/Makefile. Add the following line into your Makefile:

1
USEDLIBS = Sweet.a

Try to make and run the analysis again. You will not see the error!




Related Posts

Write an LLVM Pass

In this post, I will show how I write an...