Wk 8/9, Ch 10/11 – Liveness Analysis and Register Allocation
Time to put the infinite numbers of temporaries into real registers
Using control flow graphs
Calculating liveness using dataflow analysis
The temporaries are the data
Produces an interference graph indicating which temporaries are simultaneously live
Register allocation
By colouring the interference graph with K colours
K colours == K registers in the machine

Liveness
A temporary (register) is live
when its value may be used in the future
Two temporaries can use the same register if they are not live simultaneously

Step 1: Control Flow Graph
In a CFG
the statements of the program are nodes
if s2 may follow s1, draw an edge between them

Finding Live Ranges
Temporary t is live on all incoming edges to a node n where t is used
Temporary t is dead on all incoming edges to a node n where t is defined
Live Ranges are consecutive sequences of edges where a temporary is live
When live ranges overlap, multiple registers must be used

Finding Live Ranges : a dataflow analysis
Liveness of the temporaries flows around the edges of the CFG
Terminology
Pred[ n ], Succ[ n ] – direct predecessor, successor nodes of n
Use[ n ], Def[ n ] – temporaries used or defined at node n
Variable is live-in if it is live on any incoming edge to a node.  Live-out similarly.

Dataflow equations
in[ n ] = use[ n ] u (out[ n ] – def[ n ] )
in[n] is the set of temporaries that are live-in at node n
out[ n ] = Union of the live-in temporaries to all nodes in succ[ n ]
out[n] is the set of temporaries that are live-out at node n
Equations solved using an iterative approach to filling the sets in[n] and out[n]
Repeatedy treat equations as assignment statements until no change to in[n] and out[n] across an iteration

Static vs. Dynamic liveness
Some programs will never take certain branches dynamically (at execution)
Allows us to define dynamic liveness
However predicting branching behaviour requires complex analysis
In fact the Halting Problem can be used to show that full behaviour can never be predicted, in general
We stick to static liveness, based on CFGs
Assuming execution can always follow all branches

Determining Interference
Attempt to allocate t1…tm temporaries into r1…rn machine registers
Any condition preventing ti and tj from being allocated to rk is an interference
Commonly overlapping live ranges
Also, when ti is generated by an instruction that cannot address rk
Draw an interference graph
Where nodes are the temporaries of the program
Edges represent interference between 2 temporaries

Register Allocation
by colouring the interference graph
No nodes in interference graph joined by an edge may have the same colour
Aim for K-colouring with K m/c registers
If there is no K-colouring for the graph, we may have to spill some values into memory
NP-complete problem – but we have a linear time approximation with four phases
Build, Simplify, Spill, Select

Simplify
Pick a node with fewer than K neighbours
Remove it and its edges from the graph
And place onto a stack of removed nodes
If the remaining graph can be K-coloured, then so can the complete graph
Recursively remove another node…

Select
Ignore Spill just now, assume we removed all nodes to the stack
Rebuild graph by popping stack one element at a time
Give the element a colour
There will always be an available colour, since the node had less than K neighbours

Spill
Suppose on simplify that all nodes have significant degree (degree <= K)
Pick and mark a node for spilling
Decision is to represent it in memory during execution
Optimistically assume spilled node can be allocated with neighbours
Stack it, then continue with the simplify

Select after having to Spill
When the spill node was stacked, it was unclear whether it would be colourable
During select
May find that the K or more neighbours of the spill node already use all K colours
In which case, this is an actual spill
Don’t colour, continue with Select to find other actual spills
Otherwise, the node can be coloured

If Select cannot colour a node…
Rewrite program to
Fetch value from memory just before use
Store value back just after each definition
Creates several new temporaries with tiny live ranges
Since these will interfere with other temporaries, the algorithm is repeated
One or two iterations is usually enough

Coalescing
Any source and destination nodes of a move can be coalesced if they don’t interfere
Although beware joining two nodes that make a K-colourable graph subsequently uncolourable
Safe strategies exist
E.g. coalesce x and y if new node has fewer than K neighbours of significant degree
More complex sequence of operations when register allocating with coalescing

Finally,
Some nodes precoloured to represent specific m/c registers – e.g. SP  (P246)
Extra excitement with caller-save and callee-save registers (P247-)
Extensive implementation details given in remainder of Chapter 11 for Graph Col
A few remaining pieces to glue it all together and we’re done