CS 701, Project 3
Global Code Optimizations

Due: Thursday, November 20, 2008 (midnight)
Not accepted after: Thursday, December 4, 2008 (midnight)

Overview

For this project, you will implement four related optimizations using LLVM:

  1. Move loop-invariant computations out of loops.
  2. Fold and propagate constants.
  3. Eliminate dead instructions.
  4. Propagate constants through conditionals.

Configuration

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.

Loop-Invariant Code Motion

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.

Constant Folding and Propagation

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.

Dead Instruction Elimination

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.

Conditional Constant Propagation

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:

  1. Perform constant propagation, by requiring the cp701 pass.
  2. Replace br and switch instructions that have constant conditions with unconditional br instructions.
  3. Perform a data flow analysis to determine which basic blocks are now reachable.
  4. Remove unreachable basic blocks.

Register this pass with the name ccp701. This pass should maintain as a STATISTIC the number of instructions turned into unconditional br instructions.

Repeating Your Optimizations

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.

Grading Criteria

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.

What to Hand In

Please copy the following files to your subdirectory of the handin directory (~cs701-1/public/proj3/handin):

  1. The subdirectory of llvm-2.3/lib where you put your code, and all of its contents.
  2. A file named README that tells which features you implemented.

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.

Late Policy

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.