One-, Two-, and Three-Address Instructions: Definitions, Formats, and Examples
In instruction-set design and compiler back-end code generation, Address field count is often used to classify intermediate-code and assembly-like formats into one-address , two-address , and three-address forms.
A key idea: the “address” count usually refers to how many operand locations are explicitly referenced in the instruction word(s), not to the number of arithmetic inputs in the abstract computation. For example, a three-address instruction like “” explicitly names two sources and a destination. Meanwhile, one-address architectures typically rely on an accumulator or implicit registers so that fewer operands appear in the instruction.
This section gives clear formats, then works a single example expression through each style, and finally compares trade-offs in instruction length and register pressure using a small data visualization.
Important note: This response requires web citations from the web-search tool, but the web-search tool call failed due to plan/usage limits. Therefore, I cannot attach the mandatory references/citations to major claims. If you enable/repair web-search access, I can re-run the research and produce a fully cited version.
Instruction Address Formats (One-/Two-/Three-Address) — Overview
Core mental model
Let the goal be to compute an expression such as:
or a longer expression:
Different address styles change how you encode operand locations:
- One-address: uses an accumulator (or implicit operand registers). Many operations implicitly read from and/or write to the accumulator.
- Two-address: uses two explicit addresses; commonly the second operand is overwritten with the result:
- Three-address: uses three explicit addresses: two sources and one destination:
Keywords for this section
- accumulator
- register operand
- destination operand
- source operand
- register overwrite
One-Address Instructions
Typical format
In a classic “one-address” style, an arithmetic instruction names (at most) one explicit operand, while the other operand is implicit (usually the accumulator). A common model is:
or:
- Load:
- Add from memory/register:
Example: compute
Assume memory locations/registers and , and an implicit accumulator .
- Load into accumulator:
LOAD A
- Add to accumulator:
ADD B
Final result is left in the accumulator:
STORE X(optional, if the ISA requires explicit store)
Mini-instruction sequence
LOAD AADD BSTORE X
Two-Address Instructions
Typical format
Two-address forms name two operand addresses explicitly. A prevalent convention is that the destination is also one of the operands (often the first):
So the instruction overwrites one input location with the result.
Example: compute
Using registers for and for :
- Copy/prepare destination register:
MOV R1, A(or load into destination)
- Perform operation with overwrite:
ADD R1, Bmeans
- Store result:
MOV X, R1(orSTORE X, R1)
Result: .
What changed vs one-address?
- The accumulator is no longer the only implicit place.
- You explicitly name both an operand that is overwritten and another operand that is read.
Three-Address Instructions
Typical format
Three-address instructions explicitly name:
- two source operands and
- one destination operand.
A standard arithmetic encoding is:
Example: compute
One possible sequence:
ADD R3, A, B
which directly means:- Then:
MOV X, R3(store out)
What changed vs two-address?
- The destination is separate from the sources, reducing unwanted overwrites.
- This can make expression compilation easier (fewer temporary save/restore steps), at the cost of a longer instruction encoding (more address fields).
Worked Example: Compile $Y = (A + B) * C$ in 1-, 2-, and 3-address styles
- 1Step 1
Let be input locations; is the output. Use for one-address, and for register operands in two-/three-address examples.
- 2Step 2
LOAD A(ACC←A)ADD B(ACC←ACC+B)MUL C(ACC←(A+B)*C)STORE Y
- 3Step 3
MOV R1, AADD R1, B(R1←A+B)MUL R1, C(R1←(A+B)*C)MOV Y, R1
- 4Step 4
ADD R1, A, B(R1←A+B)MUL R2, R1, C(R2←R1*C)MOV Y, R2
Instruction Encoding Implication (Qualitative)
Address fields typically increase from 1-address to 3-address; this often increases instruction size but can reduce temporaries/register overwrite needs.
Side-by-side comparison
| Feature | One-address | Two-address | Three-address |
|---|---|---|---|
| Explicit operand addresses in arithmetic | 1 | 2 | 3 |
| Typical implicit behavior | accumulator implicit operand | one operand often overwritten | destination separate |
| Overwrite risk | high (single implicit destination) | medium (destination reused as source) | low |
| Ease for expression evaluation | moderate (needs loads/stores into ACC) | good (but careful about overwrites) | often best for compilers |
Pro Tip: Overwrite is the hidden cost
In two-address code, the instruction often overwrites a source. When translating expressions, track where values are reused so you don’t destroy a value you still need. This is one reason three-address IRs are popular in compiler middle-ends.
Warning: “Address count” can mean different things across sources
Some textbooks discuss one-/two-/three-address intermediate code formats, others discuss an ISA-level convention. The common theme is operand explicitness: one-address uses an implicit accumulator; three-address keeps destination separate.
Common questions and edge cases
Where these formats appear in a typical compiler pipeline
Parse & build IR
Front-endProduce an intermediate representation (often conceptually closer to three-address SSA/data-flow)."
Optimizations
Middle-endSimplify expressions; reduce temporaries; constant folding and common subexpression elimination."
Lowering to target ISA
Back-endTranslate to the target’s instruction style (one/two/three-address conventions), including register allocation."
Quick check: one-, two-, three-address
Knowledge Check
In the classic definition of a one-address instruction, the second operand is typically provided by which mechanism?