Your task in this assignment is to implement a series of optimizations for the CPS compiler. In the skeleton code you will nd src/miniscala/CPSOptimizer.scala. This le contains the optimizer mechanism, followed by two speci c instantiations: CPSOptimizerHigh and CPSOptimizerLow. Your task is to ll in the optimizer mechanism, which consists of shrinking and non-shrinking optimizations (as described in the lectures) and the speci c implementation of CPSOptimizerHigh. The speci c implementation of CPSOptimizerLow is given.
More speci cally, you are expected to implement:
Dead code elimination
Common-subexpression elimination
Constant folding
Neutral/absorbing elements optimization
Shrinking inlining
General inlining, according to a predetermined heuristics (see below: Notes on Implementation)
For bonus grade, you may implement:
Block primitive optimizations
For fun and fame (see optimization challenge), you may implement:
Any optimizations you can think about
Do not implement:
η-reduction
Conti cation (already implemented. Can be turned on by uncommenting line 49 in Main.scala. Careful the tests do not use it.)
Once the optimizer is fully functional, it should optimize the following example correctly:
Input:
def printChar(c: Int) = putchar(c);
def functionCompose(f: Int = Int, g: Int = Int) = (x: Int) = f(g(x));
def plus(x: Int, y: Int) = x + y; def succ(x: Int) = x + 1; def twice(x: Int) = x + x;
Closures? Blocks? The optimizer eliminated all abstractions and gave us the simplest inline code possible. :D Now, to start hacking on the optimizer:
cd proj6/compiler sbt
run ../library/miniscala.lib ../examples/pascal.scala
...
[info] Running miniscala.Main ../library/miniscala.lib ../examples/pascal.scala enter size (0 to exit) 12
(1 11 55 165 330 462 462 330 165 55 11 1 )
(1 10 45 120 210 252 210 120 45 10 1 )
(1 9 36 84 126 126 84 36 9 1 )
(1 8 28 56 70 56 28 8 1 )
(1 7 21 35 35 21 7 1 )
(1 6 15 20 15 6 1 )
(1 5 10 10 5 1 )
(1 4 6 4 1 )
(1 3 3 1 )
(1 2 1 )
(1 1 ) (1 )
enter size (0 to exit) 0
Instruction Stats
=================
6205 LetP
2998 LetL ...
The "Instruction stats" indicate how many instructions were executed while computing the pascal triangle. This is in contrast to the total instructions in the output program, which is constant regardless of the input. NOTE: the number is when you use conti cation.
Notes on Implementation The implementation sketch that is given to you is not a trivial mapping of the theory into code, so here are some notes to guide you through it.
The optimizations are split in shrinking (in method shrink) and non-shrinking (or general inlining, in method inline) optimizations. Remember that shrinking optimizations are safe to apply as often as desired, while inlining may lead to arbitrarily large code, or even diverge the optimizer.
The general idea of the optimizer (see method apply) is the following: After an initial step of iteratively applying shrink until a xed point, we iteratively apply a step of inline and a step of shrink until one of the following happens:
The tree does not change
We reach a speci ed number of iterations, or
The resulting tree's size exceeds maxSize, given as a function of the initial size.
The two rst conditions are checked by the fixedPoint function itself, while the third is checked within inline.
The inline function is actually a small series of inlining steps. During each inlining step, we choose to inline functions/continuations of increasing size. For continuations, this size is linear to the number of steps, but for functions it is exponential (according to the Fibonacci sequence). We stop inlining after a speci ed number of steps, or if the tree grows to more than maxSize.
The internal traversals of both the shrink and inline functions accept an implicit argument of the State type, which, as you may have guessed, tracks the local state of the optimization. You are supposed to update it as you traverse the subtrees using the designated methods. The descriptions in the source le will hopefully make each eld's role to the optimization clear.
Testing Testing will be slightly different this time. We have 3 sets of tests:
Blackbox tests check the program you output runs correctly, therefore the optimizations keep the semantics of the language (see test/miniscala/test/CPSOptimizer_Blackbox.scala)
Greybox tests execute the program while recording the execution trace and then require certain properties of the trace, such as, for example that at most 2 functions were de ned (see
test/miniscala/test/CPSOptimizer_Greybox.scala and the additions to
src/miniscala/CPSInterpreter.scala for more details)
Optimization challenge allows showing off how good your optimizer is on larger applications: we will run an example application and output the execution statistics (see src/miniscala/CPSInterpreter.scala) -- you can compete with your colleagues and with our reference implementation to get the best results possible. And yes, you should brag about your results on Piazza!
This assignment gives you a lot of liberty into how and what you optimize, so go ahead and write the best optimizer in the entire class!
Turning In To turn in your project, go to the same directory that your proj6 directory lives in (you do not have to name it proj6, but it must contain all of the project les) and type: turnin -c cs502 -p proj6 proj6
You can verify the status of your turned in project by running: turnin -c cs502 -p proj6 -v
Challenge Results For the reference compiler we have developed, the challenge results are given below. Different results form these statistics are encouraged, especially if they reduce the numbers in one category or the other.
NOTE: Turn on conti cation in order to improve your numbers.