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):
| Form | Meaning |
|---|---|
x = y op z | binary operation (arithmetic, logical, bitwise) |
x = op y | unary operation (minus, not, conversion) |
x = y | copy |
goto L | unconditional jump to the instruction labelled L |
if x goto L, ifFalse x goto L | conditional jump on a boolean |
if x relop y goto L | conditional jump on a comparison |
param x, call p, n, y = call p, n, return y | procedure calls: n parameters are pushed with param, then call; the result goes into y |
x = y[i], x[i] = y | indexed copy (the element at offset i from address y, or x) |
x = &y, x = *y, *x = y | address 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 , the code is
t1 = minus c
t2 = b * t1
t3 = minus c
t4 = b * t3
t5 = t2 + t4
a = t5and 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 copyx = yis(=, y, , x); unary operators leavearg2empty; 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 copyx = yis stored as(=, x, y), with the target as the first argument. An array assignmentx[i] = yneeds 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.
| Format | Fields | Moving instructions | Space | Temporaries in symbol table |
|---|---|---|---|---|
| quadruples | 4 | easy (no references by position) | most | yes |
| triples | 3 | hard (indices change) | less | no |
| indirect triples | 3 + a pointer list | easy (reorder the list) | pointer list added | no |
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 -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 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 code | quadruple | triple | indirect 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.
Worked examples
EX 1Write quadruples
EasyFor 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
EasyThe 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
MediumIf 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
Mediumy = 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 levelHow 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 fields, the triples . 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):paramfor each argument, thencall p, n. - SSA: one assignment per variable, with at joins.
Traps and GATE patterns
Connections
Builds on
Unlocks
Across subjects
No cross-subject links yet.
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
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
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 ________.
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 _________.
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 answerHide
(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 answerHide
Triples and indirect triples: results are referred to by position.
Question 3
Why are indirect triples easier to optimise than triples?
Show answerHide
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 answerHide
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, 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
My notes (saved in this browser)