G27
Self-checkedTier 1 9 min readcd.three-address-code

Three-address code, quadruples and triples

The instruction set of three-address code (assignments, copies, jumps, indexed and pointer operations, procedure calls) and its three storage formats: quadruples, triples and indirect triples, with their trade-offs for optimisation and counting questions.

Why it exists

An intermediate code must be written down in some concrete form the compiler can store, search and rewrite. The best-known form is three-address code: a very small, uniform instruction set that is close enough to assembly to be translated easily, and abstract enough to be optimised before a particular machine is chosen. The way each instruction is stored (as four fields, three fields, or as a pointer into a table) affects how easily the optimiser can move code.

Prerequisites

You need the translation of expressions into three-address code with temporaries (intermediate code generation).

Precise definitions

Addresses. An operand of an instruction is a name (a variable of the source program, referred to through the symbol table), a constant, or a compiler-generated temporary.

Instruction forms (the standard repertoire):

FormMeaning
x = y op zbinary operation (arithmetic, logical, bitwise)
x = op yunary operation (minus, not, conversion)
x = ycopy
goto Lunconditional jump to the instruction labelled L
if x goto L, ifFalse x goto Lconditional jump on a boolean
if x relop y goto Lconditional jump on a comparison
param x, call p, n, y = call p, n, return yprocedure calls: n parameters are pushed with param, then call; the result goes into y
x = y[i], x[i] = yindexed copy (the element at offset i from address y, or x)
x = &y, x = *y, *x = yaddress and pointer assignments

Instructions may carry labels. A call p(x1, ..., xn) becomes param x1, ..., param xn, call p, n.

Storage formats. The same code can be stored in three ways. For a=b∗−c+b∗−ca = b * -c + b * -c, the code is

t1 = minus c
t2 = b * t1
t3 = minus c
t4 = b * t3
t5 = t2 + t4
a = t5

and the three forms of it are shown in the animation below.

  • Quadruples: four fields (op, arg1, arg2, result). The result is a name (usually a temporary that must be entered in the symbol table). A copy x = y is (=, y, , x); unary operators leave arg2 empty; a jump has the target label in the result field. Instructions can be moved about without changing the others, because instructions refer to each other through names; this suits optimisers.
  • Triples: three fields (op, arg1, arg2). There is no result field: the result of a triple is referred to by the position (index) of the triple, written (k). A temporary never needs a name or a symbol-table entry, so triples save space. But if instructions are reordered or deleted, the indices used by other triples change, which makes optimisation awkward. A copy x = y is stored as (=, x, y), with the target as the first argument. An array assignment x[i] = y needs two triples (one for the element address with []=, one for the copy).
  • Indirect triples: the triples are kept in one table, and a separate list of pointers to triples gives the execution order. Moving an instruction means moving a pointer, so the triples do not change and may even be shared; this combines the compact triple format with the freedom of quadruples (at the cost of one extra level of indirection).

Comparison.

FormatFieldsMoving instructionsSpaceTemporaries in symbol table
quadruples4easy (no references by position)mostyes
triples3hard (indices change)lessno
indirect triples3 + a pointer listeasy (reorder the list)pointer list addedno

Static single assignment form (SSA). A variant in which every variable is assigned once: the variables are renamed (x1, x2, ...) and at a join of control flow a ϕ\phi-function chooses the right version. It simplifies many optimisations; the syllabus items on data flow analysis do not require it.

How it works

The animation builds the three storage forms of the six-instruction code of a=b∗−c+b∗−ca = b * -c + b * -c column by column. Compare the second and the third column: in the quadruples each result has a name (t1 to t5, and a); in the triples the second operand of (1) is written (0), the position of the triple that computes minus c. The last triple is the copy (=, a, (4)). The last column is the instruction list of the indirect triples, which numbers the pointers from 35 as in the textbook figure.

Quadruples, triples and indirect triples of a = b * -c + b * -c: start

Computed by a script, not typed
#three-address codequadrupletripleindirect triples
0
1
2
3
4
5

Step 0

The three-address code of a = b * -c + b * -c, one operator per instruction. There are three ways to store it.

0 / 4
computed by script: the algorithm is executed, one step at a time. python3 scripts/gen-cd-icg-traces.py

Worked examples

EX 1Write quadruples

Easy

For x=y∗z+wx = y * z + w the three-address code is t1 = y * z, t2 = t1 + w, x = t2. Quadruples: (*, y, z, t1), (+, t1, w, t2), (=, t2, , x). Three quadruples with four fields each: 12 fields, 2 temporaries (which must be in the symbol table). The same code needs no t1 and t2 in the triple form.

EX 2Write triples

Easy

The triples for the same code: (0) (*, y, z), (1) (+, (0), w), (2) (=, x, (1)). Each triple has three fields and refers to earlier ones by position: nine fields in all. If a later optimisation removed or moved (0), the references (0) in (1) would have to be renumbered, which is the weakness of triples.

EX 3Indirect triples after reordering

Medium

If an optimiser decides to execute the instructions (2), (0), (1) in a new order (valid only if there are no dependences), in indirect triples the three triples stay where they are and only the pointer list changes, from 35 → (0), 36 → (1), 37 → (2) to 35 → (2), 36 → (0), 37 → (1). In quadruples one moves the whole quadruples, which is also easy because they refer to temporaries by name. In plain triples moving requires renumbering all references to the moved triples.

EX 4A procedure call and an array access

Medium

y = f(a, b + 1): t1 = b + 1, param a, param t1, y = call f, 2. x = A[i] is x = A[i] (an indexed copy, where i is already a byte offset in the textbook); A[i] = x + 1 is t1 = x + 1, A[i] = t1. A pointer assignment *p = x is *p = x. The number of param instructions equals the number of arguments, and the call records that number.

EX 5Counting question

GATE level

How many quadruples (with a t for every operator) does the statement a = b + c * d - e need in the textbook translation? Operators: *, +, -: three temporaries t1 = c * d, t2 = b + t1, t3 = t2 - e, and the copy a = t3: 4 quadruples, 4 triples (the copy is also a triple), and the quadruples have 4×4=164 \times 4 = 16 fields, the triples 3×4=123 \times 4 = 12. Both formats have as many instructions as the three-address code; they differ in fields per instruction and in how temporaries are named. (The count of 4 was confirmed by running the translator.)

Cheat box

Cheat box

  • Three-address code: at most three addresses per instruction (x = y op z), plus copies, jumps, indexed and pointer assignments, param/call/return.
  • Quadruple: (op, arg1, arg2, result), results named by temporaries. Triple: (op, arg1, arg2), results referred to by index. Indirect triples: triples + pointer list for the execution order.
  • Triples save the temporaries but are hard to reorder; quadruples and indirect triples reorder easily.
  • Copy x = y: quadruple (=, y, , x); triple (=, x, y).
  • Call p(x1..xn): param for each argument, then call p, n.
  • SSA: one assignment per variable, with ϕ\phi at joins.

Traps and GATE patterns

Connections

The code format is the output of intermediate code generation; the translation of conditions and loops, which introduces the jump instructions and the labels, is control-flow translation. Optimisation reorders and rewrites it (local optimisation).

PYQs

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

GATE 2024 · MCQQ6 · page 280 of the book
Consider the following expression: x[i] = (p + r)
*-s[i] + u/w
(0)
+
p
r
(1)

(2)
uminus
(1)

(3)

(4)
/
u
w
(5)
+
(3)
(4)
(6)

(7)
=
(6)
(5)

Which one of the following options fills in the
missing entries CORRECTLY?
  • (a)(1) = []si, (3) *(0)(2), (6)[] = xi
  • (b)(1)[] = si, (3) -(0)(2), (6) = []x(5)
  • (c)(1) = []si, (3) *(0)(2), (6)[] = x(5)
  • (d)(1)[] = si, (3) -(0)(2), (6) = []xi
GATE 2016 · NATQ12 · page 281 of the book
Consider the following code segment.

x = u - t;

y = x * v;

x = y + w;

y = t - z;

y = x * y;

The minimum number of  variables required to
convert the above code segment to static single
assignment form is ________.
GATE 2015 · NATQ15 · page 282 of the book
The least number of temporary variables required
to create a three-address code in static single
assignment form for the expression

q + r/3 + s – t * 5 + u * v/w  is _________.
GATE 2014 · MCQQ19 · page 282 of the book
For a C program accessing X[i][j][k], the following
intermediate code is generated by a compiler. Assume
that the size of an integer is 32 bits and the size of a
character is 8 bits.

t0 = i * 1024

t1 = j * 32

t2 = k * 4

t3 = t1 + t0

COMPILER DESIGN

t4 = t3 + t2

t5 = x[t4]

Which one of the following statements about the
source code for the C program is CORRECT?
  • (a)X is declared as "int X[32][32][8]".
  • (b)X is declared as "int X[4][1024][32]".
  • (c)X is declared as "char X[4][32][8]".
  • (d)X is declared as "char X[32][16][2]".

Self-check

Question 1

What are the triples for x = a * b and y = x + 1?

Show answer

(0) (*, a, b), (1) (=, x, (0)), (2) (+, x, 1), (3) (=, y, (2)).

Question 2

Which storage format needs no entries in the symbol table for the temporaries?

Show answer

Triples and indirect triples: results are referred to by position.

Question 3

Why are indirect triples easier to optimise than triples?

Show answer

The triples are never moved: reordering instructions changes only the list of pointers, so the position references inside the triples stay valid.

Question 4

How is z = g(u, v, w) written in three-address code?

Show answer

param u, param v, param w, z = call g, 3.

Revision card

One-screen revision

  • Instructions: x = y op z, copies, jumps, if x relop y goto L, param/call, indexed and pointer forms.
  • Quadruples (op, a1, a2, result); triples (op, a1, a2) with positions; indirect triples = triples + pointer list.
  • Triples hard to reorder; quadruples and indirect triples easy.
  • SSA: single assignment, ϕ\phi at joins.

References

  • ·Aho, Lam, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (2nd edition), Chapter 6 Intermediate-Code Generation (6.2.1 to 6.2.4 addresses and instructions, quadruples, triples, static single-assignment form)

Verification

The quadruple, triple and indirect-triple forms in the animation are derived by script from the generated instructions, and the triple form is executed by the check script (scripts/enum-checks/cd_icg.py): it computes the same value as the source expression. The encoding of array assignments by two triples and the layout of the call instructions (param, call, return) are quoted from the textbook and not computed here. Different books list slightly different instruction sets. 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