Lecture 016

Register Allocation

Since IR can use as many temporaries as possible, we need to rewrite the code to use no more temporaries than machine registers

Example many variable to 1 register mapping

Example many variable to 1 register mapping

Temporaries t_1, t_2 can share the same register if at any point in the program, at most one of t_1, t_2 can be live. (cannot share if both live at same time)

Example: Live Variables

Example: Live Variables

Register Interference Graph (RIG): variables in conflict in at least one place are connected.

When there is no edge, we can share register

When there is no edge, we can share register

If a RIG is k-colorable (NP-Hard), then it is possible to only use k registers to run the code.

Spilling

Spilling: If a RIG is not k-colorable, we need to store (spill) temporaries in the memory.

We do:

  1. We know RIG is not k-colorable if at some point of removing the vertices in k-colorable algorithm, we have every vertices have degree \geq k.
  2. In this case, we choose a vertex f, remove it, mark as spell
  3. Do normal procedure, add removed vertex back
  4. When encounter f, try again if color assignment is avaliable (optimistic coloring), if not, spell f
  5. Allocate memory location (typically in stack) with an address fa
  6. Before each operation that reads f, insert f := load fa
  7. After each operation that writes f, insert store f, fa

Recompute Liveness: note that klzzwxh:0010 has been split into three temporaries

Recompute Liveness: note that f has been split into three temporaries

But which temporary should we spill? Some heuristics:

RISC: machine with general registers

CISC: machine who's registers have limited instructions avaliable

Cache

Many people believe compiler now manage cache better than programmer can.

A common optimization is matrix tiling, which we have discussed in 15-213. However, most compiler don't implement loop tiling, so programmers have to do this most of the time.

Table of Content