8 CodeGeneration
8 CodeGeneration
Midterm Statistics
• No variables or registers
5
7 7 ⊕ 12
stack … … … …
7
Why Use a Stack Machine?
Invariants
• The result of computing an expression is
always in the accumulator
• For an operation op(e1,…,en) push the
accumulator on the stack after computing
each of e1,…,en-1
– The result of en is in the accumulator before op
– After the operation pop n-1 values
• After computing an expression the stack is as
before
Stack Machine with Accumulator: Example
acc 7 5 12
⊕
7 7
stack … … … …
MIPS architecture
– Prototypical Reduced Instruction Set Computer
(RISC) architecture
– Arithmetic operations use registers for operands
and results
– Must use load and store instructions to use
operands and results in memory
– 32 general purpose registers (32 bits each)
• We will use $sp, $a0 and $t1 (a temporary register)
• Read the SPIM handout for more details
A Sample of MIPS Instructions
– lw reg1 offset(reg2)
• Load 32-bit word from address reg2 + offset into reg1
– add reg1 reg2 reg3
• reg1 ← reg2 + reg3
– sw reg1 offset(reg2)
• Store 32-bit word in reg1 at address reg2 + offset
– addiu reg1 reg2 imm
• reg1 ← reg2 + imm
• “u” means overflow is not checked
– li reg imm
• reg ← imm
MIPS Assembly: Example
P → D; P | D
D → def id(ARGS) = E;
ARGS → id, ARGS | id
E → int | id | if E1 = E2 then E3 else E4
| E1 + E2 | E1 – E2 | id(E1,…,En)
A Small Language (Cont.)
cgen(i) = li $a0 i
cgen(e1 + e2) =
cgen(e1)
sw $a0 0($sp)
addiu $sp $sp -4
cgen(e2)
lw $t1 4($sp)
add $a0 $t1 $a0
addiu $sp $sp 4
• Possible optimization: Put the result of e1 directly in
register $t1 ?
Code Generation for Add. Wrong!
cgen(e1 + e2) =
cgen(e1)
move $t1 $a0
cgen(e2)
add $a0 $t1 $a0
FP FP FP
SP old FP old FP SP
y y
x x
SP FP return
SP
Code Generation for Variables
SP
Summary
• NT(e1 + e2)
– Needs at least as many temporaries as NT(e1)
– Needs at least as many temporaries as NT(e2) + 1
Old FP
xn
...
x1
Return Addr.
Temp NT(e)
...
Temp 1
Revised Code Generation
cgen(e1 + e2) =
cgen(e1)
sw $a0 0($sp)
addiu $sp $sp -4
cgen(e2)
lw $t1 4($sp)
add $a0 $t1 $a0
addiu $sp $sp 4
Code Generation for + (revised)
Class A {
a: Int <- 0;
d: Int <- 1;
f(): Int { a <- a + d };
};
Class Tag 0
Object Size 4
Dispatch Ptr 8
Attribute 1 12
Attribute 2 16
...
Cool Object Layout (Cont.)
Offset 0 4 8 12 16 20
Class
A Atag 5 * a d
B Btag 6 * a d b
C Ctag 6 * a d c
Subclasses (Cont.)
Header A1 object
A1 attrs. A2 object
A2 attrs A3 object
A3 attrs
...
Dynamic Dispatch
Class C inherits A {
Class B inherits A {
c: Int <- 3;
b: Int <- 2;
h(): Int { a <- a * c };
f(): Int { a };
};
g(): Int { a <- a - b };
};
Dynamic Dispatch Example
• e.g()
– g refers to method in B if e is a B
• e.f()
– f refers to method in A if f is an A or C
(inherited in the case of C)
– f refers to method in B for a B object
• To evaluate f(e)
– Evaluate e to a value v
– Bind v to the formal parameter in the function body
• Example
g(x) = x <- x + 1;
f(y) = { g(y); print(y); }
y 0
f(y)
g(y) y 0
x <- x + 1 x 0
print(y)
y 0
x 1
y 0
Call-By-Value Discussion
• To evaluate f(e)
– e is evaluated
– A pointer to e is passed as the argument
– f’s code accesses the argument through the
pointer
y 0
f(y)
g(y) y 0
x <- x + 1 x
print(y)
y 1
x
y 1
Call-By-Reference Discussion
• To evaluate f(e’)
– e’ is passed unevaluated to f
– e’ is evaluated each time e refers to x
– The expression e’ is always evaluated in its original
environment
The Stack Under Call-By-Name
Example
j(y) = { print(y); print(y); }
{z <- 0; j(z++); }
z 0
z <- 0 z 0
j(z++) y z++
print(y); z 1
print(y); y z++
z 2
Call-By-Name Discussion