0% found this document useful (0 votes)
48 views73 pages

Code

Code generation for basic blocks involves creating a dependency graph from the AST and then linearizing the graph to generate target code while allocating registers. The dependency graph represents dependencies between assignments and expressions in a basic block. Common subexpressions can be eliminated by rewriting the graph. Linearizing follows dependencies to determine instruction ordering, and register allocation maps symbolic registers to physical registers to maximize reuse through graph coloring. While heuristics work well in practice, the approach can be generalized to procedures containing multiple basic blocks.

Uploaded by

Saravanan Pa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views73 pages

Code

Code generation for basic blocks involves creating a dependency graph from the AST and then linearizing the graph to generate target code while allocating registers. The dependency graph represents dependencies between assignments and expressions in a basic block. Common subexpressions can be eliminated by rewriting the graph. Linearizing follows dependencies to determine instruction ordering, and register allocation maps symbolic registers to physical registers to maximize reuse through graph coloring. While heuristics work well in practice, the approach can be generalized to procedures containing multiple basic blocks.

Uploaded by

Saravanan Pa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 73

Code Generation

Code generation issues


Code selection
Register allocation
Instruction ordering

Simplifications
Consider small parts of AST at time
Simplify target machine
Use simplifying conventions

Simple Code Generation

Fixed translation for each node type


Translates one expression at the time
Local decisions only
Works well for simple machine model
Stack machines (PDP 11, VAX)
Register machines (IBM 360/370)

Can be applied to modern machines


4

Simple Stack Machine

SP

Stack

BP

Stack Machine Instructions

Register Machine
Fixed set of registers
Load and store from/to memory
Arithmetic operations on register only

Register Machine Instructions

Example
Load_Mem p, R1

p := p + 5

Load_Const 5, R2
Add_Reg R2, R1
Store_Reg R1, P

Simple Code Generation for


Stack Machine
Tree rewritings
Bottom up AST traversal

10

Abstract Syntax Trees for Stack Machine Instructions

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

Bottom-Up Code Generation

13

Simple Code Generation for


Register Machine
Need to allocate register for temporary values
AST nodes

The number of machine registers may not


suffice
Simple Algorithm:
Bottom up code generation
Allocate registers for subtrees

14

Register Machine Instructions

15

Abstract Syntax Trees for


Register Machine Instructions

16

Simple Code Generation


Assume enough registers
Use DFS to:
Generate code
Assign Registers
Target register
Auxiliary registers

17

Code Generation with Register Allocation

18

Code Generation with Register Allocation(2)

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

Load_Mem b, R1 Load_Mem b, R2Load_Constant 4, R2


T=R3

*
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

Leads to larger execution time

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

Load_Mem b, R1 Load_Mem b, R2Load_Constant 4, R3


T=R2

*
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

Two Phase Solution


Dynamic Programming
Sethi & Ullman
Bottom-up (labeling)
Compute for every subtree
The minimal number of registers needed
Weight

Top-Down
Generate the code using labeling by preferring
heavier subtrees (larger labeling)

28

The Labeling Principle


m>n

m registers

m registers
+

n registers
29

The Labeling Principle


m<n

m registers

n registers
+

n registers
30

The Labeling Principle


m=n

m registers

m+1 registers
+

n registers
31

The Labeling Procedure

32

Labeling the example (weight)

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

Load_Mem b, R1 Load_Mem b, R2Load_Constant 4, R2


T=R3

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

Register Memory Operations


Add_Mem X, R1
Mult_Mem X, R1
No need for registers to store right operands

36

Labeling the example (weight)

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

Many heuristics exist


40

Simple Spilling Method


Heavy tree Needs more registers than
available
A `heavy tree contains a `heavy subtree
whose dependents are light
Generate code for the light tree
Spill the content into memory and replace
subtree by temporary
Generate code for the resultant tree
41

Simple Spilling Method

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

Can handle non-uniform cost


Code-Generator Generators exist (BURS)

Even simpler for 3-address machines


Simple ways to determine best orders
But misses opportunities to share registers between
different expressions
Can employ certain conventions

Better solutions exist


Graph coloring
45

Code Generation
for Basic Blocks
Introduction
Chapter 4.2.5

46

The Code Generation Problem


Given
AST
Machine description
Number of registers
Instructions + cost

Generate code for AST with minimum cost


NPC [Aho 77]

47

Example Machine Description

48

Simplifications
Consider small parts of AST at time
One expression at the time

Target machine simplifications


Ignore certain instructions

Use simplifying conventions

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

Running Example AST

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

Represented as a directed graph


Nodes are assignments
Edges represent dependency

Acyclic for basic blocks

56

Running Example

57

Sources of dependency
Data flow inside expressions
Operator depends on operands
Assignment depends on assigned expressions

Data flow between statements


From assignments to their use

Pointers complicate dependencies

58

Sources of dependency
Order of subexpresion evaluation is
immaterial
As long as inside dependencies are respected

The order of uses of a variable are immaterial


as long as:
Come between
Depending assignment
Next assignment

59

Creating Dependency Graph from AST


1. Nodes AST becomes nodes of the graph
2. Replaces arcs of AST by dependency arrows

Operator Operand

3. Create arcs from assignments to uses


4. Create arcs between assignments of the same
variable
5. Select output variables (roots)
6. Remove ; nodes and their arrows

60

Running Example

61

Dependency Graph Simplifications


Short-circuit assignments
Connect variables to assigned expressions
Connect expression to uses

Eliminate nodes not reachable from roots

62

Running Example

63

Cleaned-Up Data Dependency Graph

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

From Dependency Graph into Code


Linearize the dependency graph
Instructions must follow dependency

Many solutions exist


Select the one with small runtime cost
Assume infinite number of registers
Symbolic registers
Assign registers later
May need additional spill

Possible Heuristics
Late evaluation
Ladders

66

Pseudo Register Target Code

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

May require spilling

68

Register Allocation (Example)


R3
R1

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

But basic blocks are small


Can be generalized to a procedure
72

73

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy