Introduction
An occurrence of an expression is a common subexpression if the same expression was computed earlier and neither nor has changed since. Recomputing it wastes time; reusing the earlier value is common subexpression elimination (CSE). Within a basic block, the DAG finds such reuse directly. Across blocks, the compiler needs to know that the expression was computed on every path to the current point, which is the available expressions analysis.
This note covers the global case: the definition of availability, the and sets, the forward-intersection equations and their initialisation, and the transformation that introduces a temporary. Questions ask whether an expression is available at a point, for the IN and OUT sets of a small flow graph, or for the code after global CSE.
Prerequisites
- Local Optimisation and DAG Representation of Basic Blocks: local common subexpressions and why a redefined operand prevents reuse.
- Data-Flow Analysis Framework: forward analyses, meet by intersection, the iterative algorithm.
Core concepts
- Available expression. is available at point if every path from the entry to evaluates , and after the last such evaluation on each path there is no assignment to or .
- Generates. A block generates if it evaluates and does not afterwards redefine or .
- Kills. A block kills if it assigns or and does not afterwards recompute .
- Universe . All expressions appearing on the right of instructions in the program.
- Equations.
- Initialisation. for every other than the entry. Starting at and shrinking finds the largest solution.
How it works
Computing and within a block
Scan the block forward. For each instruction :
- Add to (and remove it from ).
- Remove from every expression that has as an operand, and add those expressions (from ) to .
The order matters: in x = x + y the expression is generated and then killed by the assignment to , so the block does not generate it.
Example 1: one expression available, one not
B1: a = x + y
p = x * y
B2: if a > 0 goto B4 (B1 -> B2; B2 -> B3; B2 -> B4)
B3: x = a - 1
q = x * y (B3 -> B4)
B4: c = x + y
e = x * yTake .
| Block | ||
|---|---|---|
| none | none | |
| none |
In , x = a - 1 kills both expressions over , but q = x * y then generates again; stays killed.
Solving (one pass already gives the fixed point here, a second confirms it):
| Block | ||
|---|---|---|
So in , is available but is not: along the path through , changes after was computed. Note that holds different values on the two paths (it was recomputed in after changed); availability only requires that the most recent evaluation on each path is still valid.

The global CSE transformation
For each instruction such that is available at (and not killed earlier in 's block):
- Search backward along the flow graph from to find the evaluations that reach (stopping at each such evaluation).
- Create a new temporary .
- Replace each such evaluation by followed by .
- Replace by .
For Example 1, the evaluations of reaching are in and :
B1: a = x + y
u1 = x * y
p = u1
B3: x = a - 1
u1 = x * y
q = u1
B4: c = x + y
e = u1One multiplication is saved on every execution of . The copies p = u1 and q = u1 are candidates for copy propagation: if later uses of p and q can read u1 instead, the copies become dead and are removed. In , c = x + y must stay: the expression is not available on the path through .
Example 2: why the initial value is
B1: a = x + y (B1 -> B2)
B2: (loop header; no code) (B2 -> B3, B2 -> B4)
B3: b = 2 (B3 -> B2, the back edge)
B4: c = x + yNothing in the loop touches or , so is available at . Starting from , the first pass gives , and the value survives every pass. Starting instead from , on the first pass and stays empty forever, because nothing in the loop regenerates . The empty start is safe but loses this common subexpression. Intersection problems start at the top, , so that back edges do not erase facts prematurely.
Example 3: a loop that redefines an operand
B1: t = a + b (B1 -> B2)
B2: c = a + b (B2 -> B3, B2 -> B4)
B3: a = c + 1 (B3 -> B2, the back edge)
B4: d = a + bTake . generates ; generates and kills ; generates and kills .
| Block | ||
|---|---|---|
c = a + bin is not redundant, although computed just before: on the second and later iterations control arrives from , where has changed.d = a + bin is redundant: the only way into is from , which has just evaluated with the current . The backward search from stops at , so only that evaluation gets the temporary: becomesu = a + b; c = u, and becomesd = u. is unchanged.
What else kills an expression
- Commutativity is not assumed. and are different expressions for the basic analysis; a compiler that normalises operand order (for commutative operators only) can treat them as one.
- Stores through pointers and procedure calls.
*p = wmay assign any variablepcan point to, and a call may assign any variable the callee can reach. Without alias information, such an instruction kills every expression whose operands might be affected. - Array element assignments kill expressions that read the same array, as in local CSE.
Local and global CSE together
Local CSE (the DAG of a block) handles repetitions inside a block; global CSE handles expressions whose earlier evaluation is in another block. A compiler usually runs local CSE first, so that each block evaluates each expression at most once before its operands change, then global CSE, then copy propagation and dead-code elimination to clean up the copies.
Related material. Partial-redundancy elimination handles expressions available on some paths but not all, as at in Example 1, by inserting evaluations on the paths that lack them (here, after x = a - 1 in ) so that the expression becomes fully redundant. It also subsumes loop-invariant code motion. It is the subject of Dragon Book Section 9.5 (lazy code motion).
Important properties and observations
- Forward and intersection: an expression must be available along all paths; one killing path suffices to make it unavailable.
- Initialise to (except at the entry). Initialising to is safe but can lose availability around loops (Example 2).
- Availability is about expressions, not values: at has different values on the two paths, and the temporary handles that.
- Kill by operand assignment: any assignment to or kills every expression over or unless it is recomputed later in the block.
- Order inside a block matters for and , as in
x = x + y. - CSE introduces copies, which copy propagation and dead-code elimination then remove.
Common misconceptions.
- "Available means computed on some path." That is a may property; availability is must.
- "An expression whose operands have the same values is available." Availability is defined by the absence of reassignment, not by equal values.
- "Global CSE replaces the later evaluation by the variable of the earlier one." That is wrong if that variable is reassigned in between; a fresh temporary is used.
GATE examination perspective
- Is available at a given point? Check every path for an evaluation not followed by an operand assignment.
- Compute , , IN and OUT. Work on a small flow graph, intersecting at joins and initialising to .
- Which expressions can be eliminated. Also consider what the code looks like after introducing a temporary.
- Loops that redefine an operand. An evaluation just before the loop does not make the same expression available at the loop header if the loop body changes an operand (Example 3).
- Hidden kills. Calls, pointer stores and array stores can kill an expression without naming its operands.
- Local versus global. DAG for one block; available expressions for the flow graph.
- Distinguish the classic analyses. Available expressions (forward, intersection) versus reaching definitions (forward, union) versus liveness (backward, union).
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 9.1.4 (global common subexpressions), Section 9.1.5 (copy propagation), Section 9.1.6 (dead-code elimination), Section 9.2.6 (available expressions), Section 9.5 (partial-redundancy elimination, related material only).