For this project, you will implement four related optimizations using LLVM:
Each optimization should be written as a pass, in a fashion similar to
Stroll
from Project 2. Keep all of your code for this project in a
single subdirectory of llvm/lib/
, both for the sake of the grader
and to simplify your build/test cycle. The makefile from the Stroll
directory, copied to your directory and suitably edited, will build
your passes into a single dynamic library. As before, to invoke a pass
named pass701
in library lib.so
on the bytecode file foo.bc
, do:
opt -load lib.so -pass701 foo.bc -f -o foo-opt.bc
Passing the -stats
flag to opt
instructs the pass manager to print
any statistics that you have defined with the STATISTIC
macro. Using
these macros in your programs should help you track your progress and
catch errors.
Each of the passes in this assignment is already an optimization pass in LLVM. So, do not call LLVM's pass for an optimization while implementing your own version of that optimization, and do not copy LLVM's code from those passes.
For this part of the project you will identify loop-invariant expressions, and move their computations out of those loops. Instead of manually finding natural loops, you should probably build your analysis as a LoopPass.
The computations of loop-invariant expressions should be moved to the loop's preheader. The preheader of a loop is a CFG node that is the (unique) immediate predecessor of the loop header from outside the loop.
You do not need to worry about profitability (is moving the invariant
a guaranteed improvement), but you do need to worry about safety, so,
you should not move any computation that might cause a run-time error,
undefined behavior, or other uncontrolled side effects. In particular,
you should not move instructions in which the opcode is *div
or
*rem
. (You can move them if you can guarantee that the denominator
is non-zero, but such movement is not required in this assignment.)
Also, instructions that involve memory (malloc
, load
, store
,
etc.) should not be considered loop invariant.
Think carefully about phi
nodes.
Register this pass with the name licm701
, through the same mechanism
that Stroll.cpp
from Project 2 used to register itself as an opt
pass.
This pass should keep track of how many instructions have been
moved, using the STATISTIC
macro discussed in Project 2.
For this part of the project you will look for values computed as pure functions of constants (e.g. 1+2), and replace those values with the evaluated constant value (e.g. 3). Any of the instructions listed in constant expressions is a pure function.
Register this pass with the name cp701
. This pass should maintain as
a STATISTIC
how many instructions have been removed.
Recall that an assignment is dead if it is not live immediately after the assignment. For this part of the project you will identify and remove all instructions that correspond to useless assignments. That is, remove any values that have no uses.
Register this pass with the name die701
. This pass should maintain
as a STATISTIC
how many instructions have been removed.
If the compiler can determine that the predicate of a conditional br
or
switch
instruction is a constant, then it can replace that instruction with an
unconditional branch and possibly remove entire blocks of dead code.
For this part of the project:
cp701
pass.br
and switch
instructions that have constant conditions with
unconditional br
instructions.Register this pass with the name ccp701
. This pass should maintain
as a STATISTIC
the number of instructions turned into unconditional
br
instructions.
Each of the optimizations you've now coded may benefit from being run
after the other optimizations you've coded. To demonstrate this, try
optimizing your code with the iter-opt
script, available on the CSL
machines at ~cs701-1/public/llvm/scripts/
.
To ready iter-opt
for use, you'll need to change a few settings in
the script itself. In particular, you must modify llvm_bin
to
reflect your LLVM binary, and dynlib
to reflect the location of the
dynamic library that contains your optimizations.
To use iter-opt
, run iter-opt <file>
. If <file>
is LLVM bitcode
of a stand-alone C file, iter-opt
will repeatedly run your
optimizations. It runs each pass repeatedly, until they report only
STATISTIC
s of 0, i.e. until they can no longer collectively further
optimize the program. (The script will also stop after it runs every
program eight times, to guard against sequences of optimizations that
don't converge.) If you have not implemented STATISTIC
s in your
passes, this behavior will be hidden; add them to observe this
behavior.
As was the case for project 2, this project may be done individually or in two person teams. Your grade will be based on the correctness of your implementation, a subjective evaluation of the quality of your code, and on the features you implement.
Please copy the following files to your subdirectory of the handin directory (~cs701-1/public/proj3/handin):
llvm-2.3/lib
where you put your code, and
all of its contents.Be sure not to copy any object files or binary libraries, as they take up a lot of space and may cause the directory to exceed its quota.
This project is due by midnight on November 20. The project may be handed in as late as midnight on Tuesday, December 2, with a late penalty of 2% per day.