Code
Code
Simplifications
Consider small parts of AST at time
Simplify target machine
Use simplifying conventions
SP
Stack
BP
Register Machine
Fixed set of registers
Load and store from/to memory
Arithmetic operations on register only
Example
Load_Mem p, R1
p := p + 5
Load_Const 5, R2
Add_Reg R2, R1
Store_Reg R1, P
10
11
Example
Subt_Top2
Mult_Top2
Mult_Top2
*
Mult_Top2
b
Push_Local #b
Push_Local #b Push_Constant 4
a
Push_Local #a
c
Push_Local #c
12
13
14
15
16
17
18
19
Example
T=R1
Subt_Reg R1, R2
T=R1
Mult_Reg R2, R1
T=R2
Mult_Reg R3, R2
T=R1
T=R2
T=R3
Mult_Reg R4, R3
T=R2
*
T=R4
Load_Mem a, R3 Load_Mem c, R4
20
Example
21
Runtime Evaluation
22
Optimality
The generated code is suboptimal
May consume more registers than necessary
May require storing temporary results
23
Example
24
Observation (Aho&Sethi)
The compiler can reorder the computations of
sub-expressions
The code of the right-subtree can appear
before the code of the left-subtree
May lead to faster code
25
Example
T=R1
Subt_Reg R3, R1
T=R1
Mult_Reg R2, R1
T=R2
Mult_Reg R2, R3
T=R1
T=R2
T=R2
Mult_Reg R3, R2
T=R3
*
T=R3
Load_Mem a, R2 Load_Mem c, R3
26
Example
Load_Mem b, R1
Load_Mem b, R2
Mult_Reg R2, R1
Load_Mem a, R2
Load_Mem c, R3
Mult_Reg R3, R2
Load_Constant 4, R3
Mult_Reg R2, R3
Subt_Reg R3, R1
27
Top-Down
Generate the code using labeling by preferring
heavier subtrees (larger labeling)
28
m registers
m registers
+
n registers
29
m registers
n registers
+
n registers
30
m registers
m+1 registers
+
n registers
31
32
1 b
3
*
1 b
1 4
* 2
1
33
Top-Down
T=R1
Subt_Reg R2, R1
-3
T=R1
Mult_Reg R2, R1
T=R2
*2
Mult_Reg R3, R2
T=R1
*2
T=R2
b1
b1
T=R2
41
a1
T=R3
Mult_Reg R2, R3
*2
T=R2
c1
Load_Mem a, R3 Load_Mem c, R2
34
Generalizations
More than two arguments for operators
Function calls
Register/memory operations
Multiple effected registers
Spilling
Need more registers than available
35
36
1 b
2
*
0 b
1 4
* 1
0
37
Top-Down
T=R1
Subt_Reg R2, R1
-2
T=R2
Mult_Reg R1, R2
*1
T=R1
Mult_Mem b, R1
*2
T=R2
T=R1
b1
Load_Mem b, R1
b0
41
Load_Constant 4, R2
T=R2
Mult_Mem c,R1
*1
T=R1
a1
c0
Load_Mem a, R1
38
Empirical Results
Experience shows that for handwritten
programs 5 registers suffice (Yuval 1977)
But program generators may produce
arbitrary complex expressions
39
Spilling
Even an optimal register allocator can require
more registers than available
Need to generate code for every correct
program
The compiler can save temporary results
Spill registers into temporaries
Load when needed
42
Top-Down (2 registers)
Load_Mem T1, R2
Store_Reg R1, T1
Subt_Reg R2, R1
T=R1
T=R1
-3
Mult_Reg R2, R1
*2
T=R1
*2
Mult_Reg R2, R1
T=R2
T=R1
b1
T=R1
b1
41
Load_Mem b, R2 Load_Constant 4, R2
Load_Mem b, R1
T=R2
a1
T=R2
Mult_Reg R1, R2
*2
T=R1
c1
Load_Mem a, R2 Load_Mem c, R1
43
Top-Down (2 registers)
Load_Mem a, R2
Load_Mem c, R1
Mult_Reg R1, R2
Load_Constant 4, R2
Mult_Reg R2, R1
Store_Reg R1, T1
Load_Mem b, R1
Load_Mem b, R2
Mult_Reg R2, R1
Load_Mem T1, R2
Subtr_Reg R2, R1
44
Summary
Register allocation of expressions is simple
Good in practice
Optimal under certain conditions
Uniform instruction cost
`Symbolic trees
Code Generation
for Basic Blocks
Introduction
Chapter 4.2.5
46
47
48
Simplifications
Consider small parts of AST at time
One expression at the time
49
Basic Block
Parts of control graph without split
A sequence of assignments and expressions
which are always executed together
Maximal Basic Block Cannot be extended
Start at label or at routine entry
Ends just before jump like node, label, procedure
call, routine exit
50
Example
void foo()
x>8
{
if (x > 8) {
z=9;
z = 9;
t = z + 1;
}
t = z + 1;
z=z*z;
z = z * z;
t=tz;
bar();
t = t - z;
bar()
t = t + 1;
t=t+1;
51
Running Example
52
53
Optimized code(gcc)
54
Outline
Dependency graphs for basic blocks
Transformations on dependency graphs
From dependency graphs into code
Instruction selection
(linearizations of dependency graphs)
Register allocation (the general idea)
55
Dependency graphs
Threaded AST imposes an order of execution
The compiler can reorder assignments as long as the
program results are not changed
Define a partial order on assignments
a < b a must be executed before b
56
Running Example
57
Sources of dependency
Data flow inside expressions
Operator depends on operands
Assignment depends on assigned expressions
58
Sources of dependency
Order of subexpresion evaluation is
immaterial
As long as inside dependencies are respected
59
Operator Operand
60
Running Example
61
62
Running Example
63
64
Common Subexpressions
Repeated subexpressions
Examples
x = a * a + 2* a*b + b * b;
y=a*a2*a*b+b*b;
a[i] + b [i]
Can be eliminated by the compiler
In the case of basic blocks rewrite the DAG
65
Possible Heuristics
Late evaluation
Ladders
66
67
Register Allocation
Maps symbolic registers into physical registers
Reuse registers as much as possible
Graph coloring
Undirected graph
Nodes = Registers (Symbolic and real)
Edges = Interference
68
R2
X1
X1 R2
69
Running Example
70
Optimized code(gcc)
71
Summary
Heuristics for code generation of basic
blocks
Works well in practice
Fits modern machine architecture
Can be extended to perform other tasks
Common subexpression elimination
73