The purpose of this project is to get you acquainted with LLVM. In particular, it will give you familiarity with the data structures, types, and code organization you will need to understand to implement program analyses. All code will be written in C++, as that is the language in which LLVM is written.
Your task is to write a function pass that counts the number of each unique instruction in a function statically. After processing a function, the pass should output the counts to stderr in the following format:
[instruction name]\t[count]\n
For example, if the pass processes a function that consists of 2 load
and 3 add
instructions, the output should be:
load 2
add 3
Directions
Passes
directory you pulled from github in part 0, called part1
. Implement your pass in that directory (.../Passes/part1/CountStaticInstructions.cpp)
. This pass will be implemented as a function pass.part1
directory. Name the module submission_pt1
. You can name it anything you want, but you'll have to use this name before submitting to gradescope. See the provided test pass for an example on how to do this.(Passes)
to include the new pass. opt -load submission_pt1.so -cse231-csi < input.ll > /dev/null
where input.ll
is the IR code file to be analyzed.Instruction::getOpcodeName
.STATISTIC
convenience macro provided by LLVM.Hints
std::map
or LLVM’s DenseMap
to store instruction counts.The analysis you wrote in Section 1 was a static analysis because it did not actually execute the program to analyze it. In this section, we are going to write a dynamic analysis that executes the program and collects runtime information. In particular, you will write a pass that instruments the original program by inserting code to count the number times each instruction executes. Each instrumented function should output the analysis results before function termination.
The general strategy you should follow:
/lib231/lib231.cpp
that contains helper functions and global data structures.Directions
.../Passes/part1/CountDynamicInstructions.cpp
as a function pass. opt -load submission_pt1.so -cse231-cdi < input.ll -o input-instrumented.bc
where input.ll
is the original IR file and input-instrumented.bc
is the instrumented version.input-instrumented.bc
is the instrumented code and lib231.bc
is the library, then you should link them by running clang++ lib231.bc input-instrumented.bc -o mytest
We recently updated the provided lib231.cpp file. Due to this change, compiling it requires some extra flags. Read below for further information. You can also take a look at the provided run.sh scripts, found under /tests/conditionalSum
and /tests/test-example
llvm-config
tool that generates the approriate flags given some arguments. Specifically for our case, the shell command $ llvm-config --system-libs --cppflags --ldflags --libs core
returns
-I/LLVM_ROOT/llvm/include -I/LLVM_ROOT/build/include -D_GNU_SOURCE
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-L/LLVM_ROOT/build/lib
-lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle
-lrt -ldl -lpthread -lm
In fact, these flags are more than what we need, so we can also pass the -Wno-unused-command-line-argument
flag, simply to avoid getting warnings about this.
Putting it all together, whenever lib231.cpp (or lib231.bc, or lib231.ll) is involved in a clang/clang++ command, this is how it should look like (note the backticks (`) ):
$ clang++ /lib231/lib231.cpp -emit-llvm -S `llvm-config --system-libs --cppflags --ldflags --libs core` -Wno-unused-command-line-argument -o /tmp/lib231.ll
To make things a little more organized, we can assign a flags variable like this:
FLAGS=`llvm-config --system-libs --cppflags --ldflags --libs core`
FLAGS="$FLAGS -Wno-unused-command-line-argument"
clang++ /lib231/lib231.cpp -emit-llvm -S $FLAGS -o /tmp/lib231.ll
Hints
IRBuilder
class, which is a convenience class for adding instructions. IRBuilder::SetInsertPoint
sets the insertion point, and various create...
methods on the IRBuilder
instance insert instructions at the specified point.FunctionType::get
Module::getOrInsertFunction
IRBuilder::CreateCall
Now, write a dynamic analysis that computes the branch bias on a per-function basis: count the number of times conditional branch instructions are executed and the number of times conditional branch instructions are taken. Note that we only consider conditional branches. A conditional branch is considered taken if its condition evaluates to true. Each instrumented function should output these two counts before function termination. The output should be in the following format:
taken\t[count of taken]\n
total\t[count of total]\n
The general strategy you should follow:
/lib231/lib231.cpp
that contains helper functions and global data structures. Directions
.../Passes/part1/BranchBias.cpp
as a function pass. opt -load submission_pt1.so -cse231-bb < input.ll -o input-instrumented.bc
where input.ll
is the original bitcode file and input-instrumented.bc
is the instrumented version.input-instrumented.bc
is the instrumented code and lib231.bc
is the library, then you should link them by running clang++ lib231.bc input-instrumented.bc -o mytest
To help you test your code, we provide our solution contained in the docker image. All the three passes have been compiled in a module named "231_solution.so". Our passes are registered with the same names (cse231-csi, cse231-cdi, cse231-bb). For example, to run the
cse231-csi
pass from Section 1, type
opt -load 231_solution.so -cse231-csi < input.ll > /dev/null
Note that the cse231-cdi
and cse231-bb
passes assume the use of our runtime library. That is, you have to link the bitcode that is instrumented by the solution opt
with the runtime library we provide.
Use the provided test cases or write your own to try out your passes. In addition, take a look at the /tests/test-example/run.sh
bash script. This script is now outdated and won't work as is, but it will show you the process you need to use (You should be able to easily update the script and make it work - try to fix the paths in it).
Directions
/tests/test-example/run.sh
are correct/tests/test-example/run.sh
runs all three passes. If you have not implemented them all, you need to comment out the lines for the pass(es) you have not implemented;cse231-csi
, cse231-cdi
, and cse231-bb
are saved in /tmp/csi.result
, /tmp/csi.result
, and /tmp/bb.result
, respectively.part1
directory (not the one under Passes
).submission_pt1
and the passes need to be named cse231-csi, cse231-cdi, cse231-bb
/lib231/lib231.cpp