In the introduction I mentioned something about 3AC and SSA. Make sure you check out the articles but the cut and dry is thus:
In SSA, each calculation is given a unique ID. These ID’s replace variable names and other objects.
So, what does this mean to us?
Consider the following two example infix arithmetic operations:
- a + b + c + d
- a * (b + c) / d
These two operations could be translated into something like the following:
Example 1: a + b + c + d
r1 := a + b
r2: := r1 + c
r3 := r2 + d
Example 1: a * (b + c) / d
r1 := b + c
r2 := a * r1
r3 := r2 / d
As you can see, the result of each binary operation is assigned to a new, unique variable. While verbose, it is much more akin to assembly and easy for C compilers to optimize.
It also ensures that calculations are done in the correct order and removes the necessity of pushing and popping operands to the stack.
Armed with knowledge, we can now get on with what I call tagging.
Tagging is the process by which we attach these unique identifiers to each operation. Variables, parameters, binary operations and unary operations all need to be tagged.
Oddly, perhaps, even if statements need to get tagged and you may wonder why that is. Well, if statements in Calc are not statements. They’re expressions. Like if expressions in functional languages, if expressions in Calc return a value.
As part of escape analysis and type checking, the value of any branch in an if expression must be checked and tagged since it’s result may be used elsewhere in the code.
As you can see, Folding constants can potentially save us time by reducing the number of operations needing an ID.
We can traverse the tree in any manner we chose provided that every ID is unique.
One more stop left to go. Code generation!