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
STATISTICs 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 STATISTICs 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.