# 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

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)

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

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

But which temporary should we spill? Some heuristics:

• spill temporaries with most conflict (resolve more conflicts)

• spill temporaries with few definitions and uses (small overhead)

• avoid spilling in inner loops (speed)

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