Introduction
A variable is live at a program point if its current value may still be read later. A register holding a dead variable can be reused; an assignment to a variable that is dead immediately afterwards is useless and can be deleted. Liveness therefore drives two of the most important back-end decisions: register allocation and dead-code elimination.
Liveness is the standard backward, may data-flow problem. Examination questions ask for live-in and live-out sets of blocks, for the variables live at a particular instruction, or for the minimum number of registers a code fragment needs without spilling, which follows from the live sets.
Prerequisites
- Data-Flow Analysis Framework: direction, meet, transfer functions and the iterative algorithm.
- Basic blocks, successors and flow graphs (see the note Basic Blocks and Control-Flow Graphs).
Core concepts
- Live. is live at point if some path from reaches a use of without passing a definition of . Otherwise is dead at .
- . Variables used in block before any definition of them in (upward-exposed uses).
- . Variables defined in before any use of them in .
- Equations.
- Instruction level. For : . The uses are added after removing the definition, so in
x = x + 1the variablexis live before. - Live range. The set of points where a particular value (a definition and the uses it reaches) is live. Two values interfere if one is defined at a point where the other is live.
How it works
Computing and
Scan each block forward. A variable read before it is written in the block goes into ; a variable written before it is read goes into . A variable read first and written later is in only. A variable written first and read later is in only (the read sees the block's own value).
Example 1: a loop
B1: a = 0
B2: b = a + 1
c = c + b
a = b * 2
if a < N goto B2
B3: return cEdges: , , .
| Block | ||
|---|---|---|
| none | ||
| none |
In , and are read before being written, so they are in , not ; only is written first.
Iterating backward in the order (reverse postorder of the reversed flow graph, the usual order for a backward problem) from empty sets:
| Block | , pass 1 | , pass 1 | , pass 2 | , pass 2 |
|---|---|---|---|---|
In pass 1, is computed while is still empty, so the self-loop adds nothing yet; pass 2 adds and to but changes no IN set. Pass 3 changes nothing, so three passes are made; a loop that stops as soon as no IN set changes stops after pass 2. The order changes the count, not the result: visiting leaves empty after pass 1, so the IN sets settle only in pass 2 and either test makes three passes. and are live on entry to the program: is an input, but is read before it is ever assigned, a use of an uninitialised variable that liveness exposes.
Live sets inside , working backward from :
| Point | Live |
|---|---|
Before b = a + 1 | |
Before c = c + b | |
Before a = b * 2 | |
Before if a < N goto B2 | |
| End of |
is dead between b = a + 1 and a = b * 2, and is dead outside that stretch, so and never interfere.

From liveness to registers
Build the interference graph: one node per variable (or per live range), and an edge between two nodes if one is defined where the other is live (apart from the defined one itself). A -colouring of this graph is an assignment of registers with no conflicts (see Graph Colouring).
For Example 1, the interfering pairs are , , , and . The triangle needs 3 colours, and 3 suffice because and can share a register. The loop needs 3 registers without spilling.
The copy exception. For a copy x = y, no edge is added between and merely because is live after the copy: both hold the same value, so they may share a register, and the copy can then be deleted. An edge appears only if some other definition of one of them happens while the other is live.
Example 2: registers for straight-line code
x = 4
y = x + 2
z = x * y
w = y - 1
x = z + w
y = x * z
return y + wWorking backward from nothing live at the end:
| Before | Live |
|---|---|
x = 4 | none |
y = x + 2 | |
z = x * y | |
w = y - 1 | |
x = z + w | |
y = x * z | |
return y + w |
At most 3 values are live at once, so 3 registers are needed, and 3 suffice if each value (each definition with its uses) may get its own register. Renaming the definitions, x1 = 4, y1 = x1 + 2, z1 = x1 * y1, w1 = y1 - 1, x2 = z1 + w1, y2 = x2 * z1, gives an interference graph with chromatic number 3.
A trap: if each source name must stay in one register for the whole block, x and y each cover two separate live ranges and the name-level interference graph becomes the complete graph on , needing 4 registers. The value-based count is the usual reading of "minimum number of registers", but check the wording.
For straight-line code, the minimum number of registers without spilling equals the maximum number of simultaneously live values, since the live ranges are intervals and an interval graph's chromatic number equals its largest clique. With loops and branches the interference graph can need more colours than the largest live set.
Example 3: a branch inside a loop
B1: a = x + 1
b = 2
if a > 5 goto B3
B2: c = a * b
goto B4
B3: c = x - 1
b = c
B4: x = c + b
if x < 100 goto B1
B5: return xEdges: , , , , , .
| Block | ||||
|---|---|---|---|---|
| none |
Visiting , the first pass already gives these sets and the second confirms them. Points worth noticing:
- In , is in , not :
c = x - 1writes it beforeb = creads it. - is in because the path through reads it, although never does. On the path through the value of is in fact dead, since overwrites before any read. Liveness is a "may" property: one path is enough.
- is live at the end of only for the sake of ; is live there for as well, while redefines it.
The interfering pairs are , , (all three are live together at the end of ) and . There is no edge : when defines , is dead, and when is defined, is not live. The triangle needs 3 colours, and can share a register with or : 3 registers.
Example 4: a dead definition still needs a register
a = 1
b = a + 1
t = a * b
c = a + b
return cThe live sets between instructions are , , , , : never more than 2. But t = a * b writes while and are both still live, and is never read. Unless the dead assignment is deleted first, the machine needs a third register to receive . In general the registers needed at an instruction are for its target ; the bound "maximum live" assumes that dead assignments have been removed. After deleting t = a * b, 2 registers suffice.
Dead-code elimination
An assignment x = e (with no side effects in e) is dead if x is not live immediately after it. Deleting it can make other variables dead, so the analysis and deletion are repeated until nothing changes. In Example 1 nothing is dead: every assignment's target is live right after it.
Important properties and observations
- Backward and union: the meet is over successors, and a variable is live if it is live along any path.
- Live-in of the entry block lists possibly uninitialised variables (or inputs).
- A use and a definition in the same instruction: the variable is live before, and the defined one is not live before unless also used.
- Liveness at the end of a block depends only on the successors' live-in sets; at the end of the program nothing is live unless the question says that some variables are live on exit.
- Registers needed for straight-line code = maximum live at any point, counting values rather than names.
- A dead definition still occupies its target register at the moment it is written (Example 4); delete dead assignments before counting.
- Copies need not interfere:
x = yadds no edge between and , which lets the allocator merge them. - Next-use information within a block (where each live variable is next read) is the instruction-level form of liveness used by simple code generators.
Common misconceptions.
- "A variable is live from its definition to its last textual use." Liveness follows control flow, including back edges; a value used at the top of a loop is live along the back edge.
- " is every variable assigned in ." Only those assigned before any use in .
- "Liveness is forward because definitions come first." Whether a value will be read depends on the future, so information flows backward.
- "A variable live at the end of a block is live on every path." One path that reads it before redefining it is enough (Example 3, at the end of ).
GATE examination perspective
- Live-in and live-out sets. Consider blocks in a small flow graph: compute and carefully, then iterate backward.
- Variables live at a given point. In a block: scan backward from the block's live-out set.
- Minimum registers without spilling. Apply this to straight-line code: maximum live set size; watch for the name-versus-value reading.
- Interference graphs and colouring. Apply this to small loops.
- Dead assignments. An assignment is removable when its target is dead immediately after it.
- Use versus def inside a block. A variable written before it is read in the block ( in of Example 3) is in only.
- Dead definitions and register counts. A value written but never read still needs a register unless the assignment is removed.
Summary
Sources
- A. V. Aho, M. S. Lam, R. Sethi, J. D. Ullman, Compilers, Principles, Techniques, and Tools, 2nd ed., Pearson Addison-Wesley, 2007: Section 8.4.2 (next-use information), Section 8.8.4 (register allocation by graph colouring), Section 9.1.6 (dead-code elimination), Section 9.2.5 (live-variable analysis).