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. vv is live at point pp if some path from pp reaches a use of vv without passing a definition of vv. Otherwise vv is dead at pp.
  • useBuse_B. Variables used in block BB before any definition of them in BB (upward-exposed uses).
  • defBdef_B. Variables defined in BB before any use of them in BB.
  • Equations.
IN[B]=useB∪(OUT[B]−defB),OUT[B]=⋃S∈succ(B)IN[S],IN[exit]=∅IN[B] = use_B \cup (OUT[B] - def_B), \qquad OUT[B] = \bigcup_{S \in succ(B)} IN[S], \qquad IN[\text{exit}] = \emptyset
  • Instruction level. For x=yopzx = y \mathbin{op} z: livebefore=(liveafter−{x})∪{y,z}live_{before} = (live_{after} - \{x\}) \cup \{y, z\}. The uses are added after removing the definition, so in x = x + 1 the variable x is 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 useuse and defdef

Scan each block forward. A variable read before it is written in the block goes into useuse; a variable written before it is read goes into defdef. A variable read first and written later is in useuse only. A variable written first and read later is in defdef only (the read sees the block's own value).

Example 1: a loop

Text
B1: a = 0
B2: b = a + 1
    c = c + b
    a = b * 2
    if a < N goto B2
B3: return c

Edges: B1→B2B_1 \to B_2, B2→B2B_2 \to B_2, B2→B3B_2 \to B_3.

Blockuseusedefdef
B1B_1noneaa
B2B_2a,c,Na, c, Nbb
B3B_3ccnone

In B2B_2, aa and cc are read before being written, so they are in useuse, not defdef; only bb is written first.

Iterating backward in the order B3,B2,B1B_3, B_2, B_1 (reverse postorder of the reversed flow graph, the usual order for a backward problem) from empty sets:

BlockOUTOUT, pass 1ININ, pass 1OUTOUT, pass 2ININ, pass 2
B3B_3∅\emptysetcc∅\emptysetcc
B2B_2IN[B2]∪IN[B3]=cIN[B_2] \cup IN[B_3] = ca,c,Na, c, NIN[B2]∪IN[B3]=a,c,NIN[B_2] \cup IN[B_3] = a, c, Na,c,Na, c, N
B1B_1a,c,Na, c, Nc,Nc, Na,c,Na, c, Nc,Nc, N

In pass 1, OUT[B2]OUT[B_2] is computed while IN[B2]IN[B_2] is still empty, so the self-loop adds nothing yet; pass 2 adds aa and NN to OUT[B2]OUT[B_2] 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 B1,B2,B3B_1, B_2, B_3 leaves IN[B1]IN[B_1] empty after pass 1, so the IN sets settle only in pass 2 and either test makes three passes. cc and NN are live on entry to the program: NN is an input, but cc is read before it is ever assigned, a use of an uninitialised variable that liveness exposes.

Live sets inside B2B_2, working backward from OUT[B2]={a,c,N}OUT[B_2] = \{a, c, N\}:

PointLive
Before b = a + 1a,c,Na, c, N
Before c = c + bb,c,Nb, c, N
Before a = b * 2b,c,Nb, c, N
Before if a < N goto B2a,c,Na, c, N
End of B2B_2a,c,Na, c, N

aa is dead between b = a + 1 and a = b * 2, and bb is dead outside that stretch, so aa and bb never interfere.

Liveness sets of the three-block loop and its interference graph
Figure 1. Liveness on the loop a = 0; b = a + 1; c = c + b; a = b * 2; if a << N goto B2; return c: IN[B1] = {c, N}, IN[B2] = OUT[B2] = {a, c, N}, IN[B3] = {c}, with the live set before each instruction of B2 and the interference graph, which needs 3 registers.

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 kk-colouring of this graph is an assignment of kk registers with no conflicts (see Graph Colouring).

For Example 1, the interfering pairs are {a,c}\{a, c\}, {a,N}\{a, N\}, {b,c}\{b, c\}, {b,N}\{b, N\} and {c,N}\{c, N\}. The triangle b,c,Nb, c, N needs 3 colours, and 3 suffice because aa and bb can share a register. The loop needs 3 registers without spilling.

The copy exception. For a copy x = y, no edge is added between xx and yy merely because yy 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 {x,y}\{x, y\} appears only if some other definition of one of them happens while the other is live.

Example 2: registers for straight-line code

Text
x = 4
y = x + 2
z = x * y
w = y - 1
x = z + w
y = x * z
return y + w

Working backward from nothing live at the end:

BeforeLive
x = 4none
y = x + 2xx
z = x * yx,yx, y
w = y - 1y,zy, z
x = z + ww,zw, z
y = x * zw,x,zw, x, z
return y + ww,yw, y

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 w,x,y,zw, x, y, z, 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

Text
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 x

Edges: B1→B2B_1 \to B_2, B1→B3B_1 \to B_3, B2→B4B_2 \to B_4, B3→B4B_3 \to B_4, B4→B1B_4 \to B_1, B4→B5B_4 \to B_5.

BlockuseusedefdefININOUTOUT
B1B_1xxa,ba, bxxa,b,xa, b, x
B2B_2a,ba, bcca,ba, bb,cb, c
B3B_3xxb,cb, cxxb,cb, c
B4B_4b,cb, cxxb,cb, cxx
B5B_5xxnonexx∅\emptyset

Visiting B5,B4,B3,B2,B1B_5, B_4, B_3, B_2, B_1, the first pass already gives these sets and the second confirms them. Points worth noticing:

  • In B3B_3, cc is in defdef, not useuse: c = x - 1 writes it before b = c reads it.
  • xx is in OUT[B1]OUT[B_1] because the path through B3B_3 reads it, although B2B_2 never does. On the path through B2B_2 the value of xx is in fact dead, since B4B_4 overwrites xx before any read. Liveness is a "may" property: one path is enough.
  • aa is live at the end of B1B_1 only for the sake of B2B_2; bb is live there for B2B_2 as well, while B3B_3 redefines it.

The interfering pairs are {a,b}\{a, b\}, {a,x}\{a, x\}, {b,x}\{b, x\} (all three are live together at the end of B1B_1) and {b,c}\{b, c\}. There is no edge {c,x}\{c, x\}: when B4B_4 defines xx, cc is dead, and when cc is defined, xx is not live. The triangle a,b,xa, b, x needs 3 colours, and cc can share a register with aa or xx: 3 registers.

Example 4: a dead definition still needs a register

Text
a = 1
b = a + 1
t = a * b
c = a + b
return c

The live sets between instructions are ∅\emptyset, {a}\{a\}, {a,b}\{a, b\}, {a,b}\{a, b\}, {c}\{c\}: never more than 2. But t = a * b writes tt while aa and bb are both still live, and tt is never read. Unless the dead assignment is deleted first, the machine needs a third register to receive tt. In general the registers needed at an instruction are ∣liveafter∪{x}∣\lvert live_{after} \cup \{x\}\rvert for its target xx; 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 = y adds no edge between xx and yy, 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.
  • "defBdef_B is every variable assigned in BB." Only those assigned before any use in BB.
  • "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, xx at the end of B1B_1).

GATE examination perspective

  • Live-in and live-out sets. Consider blocks in a small flow graph: compute useuse and defdef 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 (cc in B3B_3 of Example 3) is in defdef only.
  • Dead definitions and register counts. A value written but never read still needs a register unless the assignment is removed.

Summary

Sources

  1. 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).

Next steps