G27
Self-checkedTier 1 9 min readcd.dataflow-liveness

Liveness analysis

Live variable analysis: definition of liveness, use and def sets, the backward equations with union, the iterative solution on a flow graph, dead assignments, and the uses in dead-code elimination and register allocation.

Why it exists

A variable is only worth keeping if its current value will be read later. If it will not, the assignment that computed it is wasted (dead code), and the register or memory location can be reused for something else (register allocation). Liveness analysis finds, for every point of the program, the set of variables whose present value may still be used. It looks forward in the program but works backwards: whether xx is live now depends on what happens after.

Prerequisites

You need the data flow framework (data flow framework): gen-kill sets, meet, and iteration; liveness is its backward instance.

Precise definitions

Live variable. A variable xx is live at a point pp if the value of xx at pp may be used along some path starting at pp, that is, there is a path from pp to a use of xx on which xx is not redefined before that use. Otherwise it is dead at pp. (A may property: one path suffices.)

use and def of a block.

  • useB\text{use}_B: the variables whose value is read in BB before any assignment to them in BB.
  • defB\text{def}_B: the variables assigned in BB (whether or not they are used afterwards).

For a block a = b + c; b = 1; d = a: reading b and c before assigning, so use={b,c}\text{use} = \{b, c\} (the a read in d = a was assigned earlier in the block, so it is not in use); def={a,b,d}\text{def} = \{a, b, d\}.

Equations (backward, union).

IN[B]=useB∪(OUT[B]−defB),OUT[B]=⋃S succ of BIN[S],IN[exit]=∅ (nothing is live after the program ends).\text{IN}[B] = \text{use}_B \cup (\text{OUT}[B] - \text{def}_B),\qquad \text{OUT}[B] = \bigcup_{S\ \text{succ of}\ B} \text{IN}[S],\qquad \text{IN}[\text{exit}] = \emptyset\ \text{(nothing is live after the program ends)}.

IN[BB] is the set of variables live at the start of BB; OUT[BB] the set live at its end. A variable live on exit from BB is live on entry unless BB assigns it first; a variable used in BB before being assigned is live on entry. The initial value of every set is ∅\emptyset, and the blocks are visited in the reverse of the order used for forward problems. (If some variables are live on exit from the whole program, such as the results returned, they are put into the boundary value.)

Applications.

  1. Dead-code elimination. An assignment x = ... is dead if xx is not live immediately after it. Inside a block scan backwards from OUT[BB], keeping the live set: for each instruction, if its destination is not in the live set the instruction is dead (remove it, if it has no side effects); otherwise remove the destination from the set and add the operands.
  2. Register allocation. The number of variables live at the same time is a lower bound on the registers needed; two variables that are never live together can share a register (the interference graph is built from liveness).
  3. Detecting uninitialised variables: a variable live on entry to the program is used before it is defined.
  4. The live-on-exit set of a block is what local optimisation needs to remove dead assignments inside the block.

How it works

The flow graph has four blocks: B1 (a = 1; b = 2; c = a + b; if c > 5 goto B3), B2 (d = c * 2; goto B4), B3 (d = a - b) and B4 (print d), with edges B1 → B2, B1 → B3, B2 → B4, B3 → B4. The animation computes use and def, then iterates backwards, B4 first. B4 reads d, so IN[B4] = {d} and OUT[B4] = ∅. B3 defines d and reads a and b: IN[B3] = {a, b} (d is defined in B3 so it is removed from OUT[B3] = {d}). B2 reads c and defines d: IN[B2] = {c}. B1's OUT is the union of the IN sets of B2 and B3, {c} ∪ {a, b}, and since B1 defines a, b, c they are all removed from IN[B1], which is empty: nothing is live on entry to the program (good: no variable is used before it is defined).

Live variable analysis: the iterative algorithm: start

Computed by a script, not typed
  1. 11: a = 1
  2. 22: b = 2
  3. 33: c = a + b
  4. 44: if c > 5 goto 7
  5. 55: d = c * 2
  6. 66: goto 8
  7. 77: d = a - b
  8. 88: print d
blockusedefINOUT
B1∅{a, b, c}
B2{c}{d}
B3{a, b}{d}
B4{d}∅

initial values

Step 0

Live variables is a backward problem with union as the meet: a variable is live at a point if some path from there uses it before redefining it. Each block has a use set (variables read before being written in it) and a def set (variables written in it). The equations run from the exits backwards, in the reverse order of the blocks. Table columns: use, def, IN, OUT.

0 / 8
computed by script: the analysis is executed, one block at a time. python3 scripts/gen-cd-dfa-traces.py

Worked examples

EX 1use and def

Easy

Block B: x = y + 1; z = x * 2; y = 7. Reads: y (before any assignment to y), then x (assigned earlier in B). So useB={y}\text{use}_B = \{y\} and defB={x,z,y}\text{def}_B = \{x, z, y\}. If OUT[B] = {z}, then IN[B] = {y}∪({z}−{x,z,y})={y}\{y\} \cup (\{z\} - \{x, z, y\}) = \{y\}: only y is live on entry. The final y = 7 is dead (nothing reads y afterwards, since OUT[B] does not contain it).

EX 2Backward order

Easy

For a chain B1 → B2 → B3 where B3 reads v, B2 assigns v and B1 only reads w: start from B3: IN[B3] = {v}. OUT[B2] = {v}; B2 defines v, so IN[B2] = ∅ (the definition screens the use). OUT[B1] = ∅, IN[B1] = {w}. So v is live between B2 and B3, but not at the start of B2 or in B1. A forward pass would not give this answer; the sets flow from uses backwards.

EX 3A loop

Medium

B1: s = 0; i = 0; B2 (header): if i >= n goto B4; B3: s = s + i; i = i + 1; goto B2; B4: print s. Live sets (backward): IN[B4] = {s}. B2: OUT = IN[B3] ∪ IN[B4]; IN[B3] = {s, i} (reads before writing): so OUT[B2] = {s, i}, and B2 reads i and n: IN[B2] = {i, n, s}. OUT[B3] = IN[B2] = {i, n, s}; IN[B3] = {s, i} ∪ ({i, n, s} − {s, i}) = {s, i, n}. B1: OUT = {i, n, s}; defines s, i: IN[B1] = {n}: only the input n is live on entry, as it should be. Note that n stays live all around the loop because the test reads it every time.

EX 4Find the dead assignments in a block

Medium

x = 1; y = 2; z = x + y; x = 3; print z with nothing live on exit. Scan backwards with live = ∅: print z: live = {z}. x = 3: x is not live: dead, remove (live unchanged). z = x + y: z live: keep; live = {x, y}. y = 2: y live: keep; live = {x}. x = 1: x live: keep. Only the fourth instruction is dead (checked by the program). After removing it, the block still computes z = 3.

EX 5Which variables are live?

GATE level

For the flow graph of the animation: at the end of B1 the live variables are a, b (needed by B3's d = a - b) and c (needed by B2's d = c * 2). At the start of B3 they are a, b. Variable d is live at the end of B2, B3 (read by print d in B4) but dead at the start of B2, B3 (both assign it first). The maximum number of simultaneously live variables at any point is 3 (a, b, c after the first block), so three registers suffice for these variables.

Cheat box

Cheat box

  • Live at a point: the current value may be read later on some path before being overwritten.
  • use = read before written in the block; def = assigned in the block.
  • Backward, union: OUT[B] = ⋃\bigcup IN[successors]; IN[B] = use ∪\cup (OUT −- def). Start from ∅\emptyset; visit blocks in reverse order.
  • Dead assignment: destination not live immediately after the instruction.
  • Within a block scan backwards: if dest ∉\notin live: dead; else live = (live −- dest) ∪\cup operands.
  • Uses: dead-code elimination, register allocation, uninitialised variables.

Traps and GATE patterns

Connections

Liveness is the backward case of the data flow framework. It gives the live-on-exit sets that local optimisation needs to delete dead assignments, and the live ranges that decide register sharing in code generation. Reaching definitions asks the dual question about where a value came from (reaching definitions).

PYQs

5 previous year questions from your book. I re-solved each one myself (2 by running or simulating, 3 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2026 · MCQQ2 · page 279 of the book
Consider the control flow graph given below.

Which one of the following options is the set of live
variables at the exit point of each basic block?
  • (a)B1:{a, b, c, e, f}, B2:{d, e}, B3:{b, c, e, f}, B4:∅
  • (b)B1:∅, B2:{d, e}, B3:{a, c, f}, B4:∅
  • (c)B1:{a, b, c, e, f}, B2:{d, e}, B3:{c, e, f}, B4:∅
  • (d)B1:∅, B2:{d, e, f}, B3:{a, b, c, e, f}, B4:∅
GATE 2025 · MCQQ5 · page 280 of the book
Which ONE of the following techniques used in
compiler code optimization uses live variable
analysis?
  • (a)Run-time function call management
  • (b)Register assignment to variables
  • (c)Strength reduction
  • (d)Constant folding
GATE 2021 · MCQQ9 · page 281 of the book
For a statement S in a program, in the context of
liveness analysis, the following sets are defined:

USE (S) : the set of variables used in S

IN (S) : the set of variables that are live at the entry
of S

OUT(S) : the set of variables that are live at the exit
of S

Consider a basic block that consists of two
statements, S1 followed by S2. Which one of the
following statements is correct?
  • (a)OUT(S1) = IN(S1) ∪ USE(S1)
  • (b)OUT(S1) = IN(S2) ∪ OUT(S2)
  • (c)OUT(S1) = IN(S2)
  • (d)OUT(S1) = USE(S1) ∪ IN(S2)
GATE 2014 · MCQQ17 · page 282 of the book
Which one of the following is FALSE?
  • (a)A basic block is a sequence of instructions where control enters the sequence at the beginning and exits at the end.
  • (b)Available expression analysis can be used for common subexpression elimination.
  • (c)Live variable analysis can be used for dead code elimination.
  • (d)x=4*5⇒x=20 is an example of common subexpression elimination
GATE 2010 · MCQ · 2 marksQ26 · page 285 of the book
The program below uses six temporary variables a,
b, c, d, e, f.

a = 1

b = 10

c = 20

d = a+b

e = c+d

f = c+e

b = c+e

e = b+f

d = 5+e

return d+f

Assuming that all operations take their operands
from registers, what is the minimum number of
registers needed to execute this program without
spilling?
  • (a)2
  • (b)3
  • (c)4
  • (d)6

Self-check

Question 1

What are use and def of the block a = b + c; c = a * 2?

Show answer

use = {b, c} (c is read before it is assigned); def = {a, c}. (a is read after being assigned in the block, so it is not in use.)

Question 2

Block B has use={x}\text{use} = \{x\}, def={y}\text{def} = \{y\} and OUT[B] = {y, z}. What is IN[B]?

Show answer

IN[B] = {x} ∪\cup ({y, z} −- {y}) = {x, z}.

Question 3

When is the assignment t = e dead?

Show answer

When t is not live immediately after it.

Question 4

Why does liveness run backwards?

Show answer

Whether a value is live depends on later uses, so the information must flow from the uses back towards the definitions.

Revision card

One-screen revision

  • Live = may be used later before redefinition. use (read first), def (assigned).
  • Backward, union: OUT = ⋃\bigcup IN[succ]; IN = use ∪\cup (OUT −- def).
  • Dead assignment: destination not live after it; used for dead code and registers.
  • Example sets: IN = ∅, {c}, {a, b}, {d} for B1 to B4.

References

  • ·Aho, Lam, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (2nd edition), Chapter 9 Machine-Independent Optimizations (9.2.5 live-variable analysis); Chapter 8 (8.6.3 register allocation and liveness)
  • ·Cooper and Torczon, Engineering a Compiler, Chapter 8 and 9 (live analysis)

Verification

The live-variable sets are computed by the backward iterative algorithm (scripts/cd_dfa.py) and, for 222 random programs, recomputed by a different method: a search over single instructions for a path from the point to a use with no redefinition in between (scripts/enum-checks/cd_dfa.py). The dead assignment of the page example was found by a backward scan within the block. Registers are mentioned only as an application; interference graphs are outside the syllabus items and are not developed here. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (token counts, FIRST and FOLLOW sets, LL(1) tables and moves, LR item sets, state counts and parses, operator-precedence values, attribute evaluation and printing schemes, activation-record counts and access links, parameter-passing results, three-address code, jumping and backpatched code, leaders and blocks, value numbering and DAGs, gen/kill and data flow sets, Sethi-Ullman labels and live ranges); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.

last verified: never