You are on page 1of 40

Intermediate representation

 Goals:  encode knowledge about the program  facilitate analysis  facilitate retargeting  facilitate optimization

scanning HIR semantic analysis parsing

HIR intermediate code gen.

LIR

optim

LIR code gen.

Intermediate representation
 Components  code representation  symbol table  analysis information  string table  Issues  Use an existing IR or design a new one?  How close should it be to the source/target?

IR selection
 Using an existing IR  cost savings due to reuse  it must be expressive and appropriate for the compiler operations  Designing an IR  decide how close to machine code it should be  decide how expressive it should be  decide its structure  consider combining different kinds of IRs

IR classification: Level
 High-level  closer to source language  used early in the process  usually converted to lower form later on  Example: AST

IR classification: Level
 Medium-level  try to reflect the range of features in the source language in a language-independent way  most optimizations are performed at this level  algebraic simplification  copy propagation  dead-code elimination  common subexpression elimination  loop-invariant code motion  etc.

IR classification: Level
 Low-level  very close to target-machine instructions  architecture dependent  useful for several optimizations  loop unrolling  branch scheduling  instruction/data prefetching  register allocation  etc.

IR classification: Level
for i := op1 to op2 step op3 instructions endfor i := op1 if step < 0 goto L2 L1: if i > op2 goto L3 instructions i := i + step goto L1 L2: if i < op2 goto L3 instructions i := i + step goto L2 L3:

High-level

Medium-level
7

IR classification: Structure
 Graphical  Trees, graphs  Not easy to rearrange  Large structures  Linear  Looks like pseudocode  Easy to rearrange  Hybrid  Combine graphical and linear IRs  Example:  low-level linear IR for basic blocks, and  graph to represent flow of control
8

Graphical IRs
 Parse tree  Abstract syntax tree  High-level  Useful for source-level information  Retains syntactic structure  Common uses  source-to-source translation  semantic analysis  syntax-directed editors

Graphical IRs
 Tree, for basic block*  root: operator  up to two children: operands  can be combined  Uses:  algebraic simplifications  may generate locally optimal code.
L1: i := 2 t1:= i+1 t2 := t1>0 2 if t2 goto L1 i 1 t1 0 assgn, i add, t1 gt, t2 assgn, i 1 gt, t2

add, t1

2
10

*straight-line code with no branches or branch targets.

Graphical IRs
 Directed acyclic graphs (DAGs)  Like compressed trees  leaves: variables, constants available on entry  internal nodes: operators


annotated with variable names?

 

 

distinct left/right children Used for basic blocks (DAGs don't show control flow) Can generate efficient code.  Note: DAGs encode common expressions But difficult to transform Good for analysis


11

Graphical IRs
 Generating DAGs  Check whether an operand is already present  if not, create a leaf for it  Check whether there is a parent of the operand that represents the same operation  if not create one, then label the node representing the result with the name of the destination variable, and remove that label from all other nodes in the DAG.

12

Graphical IRs
 Directed acyclic graphs (DAGs)  Example m := 2 * y * z n := 3 * y * z p := 2 * y - z

13

Graphical IRs
 Control flow graphs (CFGs)  Each node corresponds to a  basic block, or  part of a basic block, or


may need to determine facts at specific points within BB more space and time

a single statement


Each edge represents flow of control

14

Graphical IRs
 Dependence graphs : they represents constraints on

the sequencing of operations




Dependence = a relation between two statements that puts a constraint on their execution order.  Control dependence


Based on the program's control flow. Based on the flow of data between statements.

Data dependence


 

Nodes represent statements Edges represent dependences  Labels on the edges represent types of dependences

 Built for specific optimizations, then discarded


15

Graphical IRs
 Dependence graphs  Example:
s1 s2 s3 s4 s5 L1: a := b + c if a>10 goto L1 d := b * e e := d + 1 d := e / 2
control dependence: s3 and s4 are executed only when a<=10 true or flow dependence: s2 uses a value defined in s1 This is read-after-write dependence antidependence: s4 defines a value used in s3 This is write-after-read dependence output dependence: s5 defines a value also defined in s3 This is write-after-write dependence input dependence: s5 uses a value also uses in s3 This is read-after-read situation. It places no constraints 16 in the execution order, but is used in some optimizations.

s1

s2

s3

s4

s5

Basic blocks


Basic block = a sequence of consecutive statements in which flow


of control enters at the beginning and leaves at the end without halt or possibility of branching except at the end.

Partitioning a sequence of statements into BBs


1.

2.

Determine leaders (first statements of BBs)  The first statement is a leader  The target of a conditional is a leader  A statement following a branch is a leader For each leader, its basic block consists of the leader and all the statements up to but not including the next leader.

17

Basic blocks
unsigned int fibonacci (unsigned int n) { unsigned int f0, f1, f2; f0 = 0; f1 = 1; if (n <= 1) return n; for (int i=2; i<=n; i++) { f2 = f0+f1; f0 = f1; f1 = f2; } return f2; } read(n) f0 := 0 f1 := 1 if n<=1 goto L0 i := 2 L2: if i<=n goto L1 return f2 L1: f2 := f0+f1 f0 := f1 f1 := f2 i := i+1 go to L2 L0: return n

18

Basic blocks
Leaders: read(n) f0 := 0 f1 := 1 if n<=1 goto L0 i := 2 L2: if i<=n goto L1 return f2 L1: f2 := f0+f1 f0 := f1 f1 := f2 i := i+1 go to L2 L0: return n entry read(n) f0 := 0 f1 := 1 n <= 1 return n

i := 2 i<=n

f2 := f0+f1 f0 := f1 f1 := f2 i := i+1

return f2

exit

19

Linear IRs
 Sequence of instructions that execute in order of

appearance  Control flow is represented by conditional branches and jumps  Common representations
 

stack machine code three-address code

20

Linear IRs
 Stack machine code  Assumes presence of operand stack  Useful for stack architectures, JVM  Operations typically pop operands and push results.  Advantages  Easy code generation  Compact form  Disadvantages  Difficult to rearrange  Difficult to reuse expressions

21

Linear IRs
 Three-address code  Compact  Generates temp variables  Level of abstraction may vary  Loses syntactic structure  Quadruples  operator  up to two operands  destination  Triples  similar to quadruples but the results are not named explicitly (index of operation is implicit name)  Implement as table, array of pointers, or list
22

Linear IRs
L1: i := 2 t1:= i+1 t2 := t1>0 if t2 goto L1 Quadruples (1) 2 (2) i st (1) (3) i + 1 (4) (3) > 0 (5) if (4), (1) Triples
23

SSA form
 Static Single Assignment Form  Encodes information about data and control flow  Two constraints:  Each definition has a unique name  Each use refers to a single definition


all uses reached by a definition are renamed accordingly

Advantages:  Simplifies data flow analysis & several optimizations  SSA size is linear to program size  Eliminates certain dependences (write-after-read, writeafter-write) Example: x := 5 x := 5
0

x := x +1 y := x * 2

x1 := x0 +1 y0 := x1 * 2

24

SSA form
 Consider a situation where two control-flow paths

merge (e.g. due to a loop, or an if-statement)


read(x) x>0 read(x0) x0 > 0

read(x) if ( x > 0) y:= 5 else y:=10 x := y

y := 5

y := 10

y0 := 5

y1 := 10

x := y

x1 := y should this be y0 or y1?


25

SSA form
 The compiler inserts special join functions (called N-

functions) at points where different control flow paths meet.


read(x0) x0 > 0

N is not an executable function!


If we do need to generate executable code from this form, we insert appropriate copy statements in the predecessors: y0 := 5 y2 := y0 y1 := 10 y2 := y1

y0 := 5

y1 := 10

y2 = N(y0, y1) x1 := y2

x1 := y2
26

SSA form
 Example 2:
x := 0 i := 1 while (i<10) x := x+i i := i+1
x := 0 i := 1 x0 := 0 i0 := 1

i < 10

x1 := N(x0, x2) i1 := N(i0, i2) i1 < 10

x := x + 1 i := i + 1

exit

x2 := x1 + 1 i2 := i1 + 1

exit

27

SSA form
B1 x0 := 0 i0 := 1
 When and where do we add N

functions?  Intuition:


x1 := N(x0, x2) i1 := N(i0, i2) B3 i < 10 1

  

B2

x2 := x1 + 1 i2 := i1 + 1

exit

There is a definition of x in B1 and another in B2 There is a path from B1 to B3 There is a path from B2 to B3 B3 is the first "common" node in these two paths. A N function for x should be placed in B3.

28

SSA form
 A program is in SSA form if  Each variable is assigned a value in exactly one statement  Each use of a variable is dominated by the definition.  Domination  Node A dominates node B if every path from the flow graph entry to B goes through A  Every node dominates itself  Intuition: control will have to go through A in order to reach B  Dominators are useful in identifying loops and in

computing the SSA form.

29

Dominators
 A node N may have several dominators, but one of

them will be closest to N and be dominated by all other dominators of N. That node is called the immediate dominator of N.  The dominator tree is a data structure that shows the dominator relationships of a control flow graph.


Each node in the tree is the immediate dominator of its children.

30

entry

B1 B2 B3 B4 B5 B7 B8 B9
exit

The dominator tree shows the dominator relation: each node in the tree is the immediate dominator of its children. Example: B7 is dominated by B1, B3, and B4, but its immediate (closest) dominator is B4 Note: B5 does not dominate B7 because we can go from the entry to B7 through the B6 path.

B1 B6 B2 B3 B4 B5 B6 B7 B8 B9 B10
31

B10

Dominators and loops


 We can use dominators to identify the loops in a flow

graph:  Natural Loop = A set of basic blocks with


 

a single entry point called the header, which dominates all other blocks in the set, and at least one way to iterate (i.e. go back to the header)

 Loop-finding algorithm:  Find an edge BpA where A dominates B. This is called a back-edge. Add A and B to the loop  Find all nodes that can reach B without going through A. Add them to the loop.

32

entry

Loops
back edge: B9pB1 loop: {B9, B8, B7, B10, B6, B5, B4, B3, B2, B1}

B1 B2 B3 B4 B5 B7 B8 B9
exit

back edge: B10pB7 loop: {B10, B8, B7} back edge: B8pB3 loop: {B8, B7, B10, B6, B5, B4, B3 } back edge: B7pB4 loop: {B7, B10, B6, B5, B8, B4} back edge: B4pB3 loop: {B4, B7, B10, B8, B6, B5, B3}
33

B6

B10

Nested Loops
 Loop K is nested within loop L if  L and K have different headers, P and O respectively, and  P is dominated by O

34

Dominators and SSA form


 Dominators can be used in a more efficient computation of the

SSA form.  Node A strictly dominates node B if A dominates B and A { B.  The dominance frontier of a node B is the set of all nodes X such that
  

B does not strictly dominate X B dominates a predecessor of X Intuition:  The nodes in the dominance frontier of B are destinations of the edges that leave an area dominated by B.  Since those destinations are not dominated by B, there must be some other path from the entry to them.  Therefore, they must be convergence points, and we need to place N functions in them for any variables defined in B.
35

 Y is a successor of X if there is an edge XpY in the flow graph.

Dominance frontier
B0 B1 B2 B11 B3 B5 B6 B4 B7
The paths that converge to B8 have been marked. B2 dominates B3, B4, and B5. B2 does not dominate B6 or B8, but does dominate their predecessors. B6 and B8 are the dominance frontier of B2.

B8 B10

B9

For each variable definition in B2, insert a N function in B6 and in B8.

36

Dominance frontier
 The dominance frontier of a node B can be computed

as follows:
 DF(B) = DFlocal(B)  where:
 

U
C

DFup(C)

C is the set of children of B in the dominator tree DFup(C) is the set of nodes in the dominance frontier of C, that are not strictly dominated by C's immediate dominator DFlocal(B) are the successors of B that are not strictly dominated by B.

37

Dominance frontier algorithm


compute the dominator tree for each X in a bottom-up traversal of the tree, do DF(X) := { } for each Y Succ (X) do if (idom (Y) { X) DFlocal then DF(X) := DF(X) {Y} end for for each Z in children(X) do for each W DF(Z) do if (idom (W) { X) DFup then DF(X) := DF(X) {Y} end for end for end for
38

entry

1 2 1 3 4 5 7 2 {ex}

entry

exit

{ex}

6 {8} 8 4 9 1 0 1 1 1 2 {local, {6} 5 {6} 6 {8} 3

7 {8}

8 {2, ex} 9 {2, ex} 1 0 {11} 1 1 {9, 2, ex} 1 2

up}

{2, ex} 39

exit

entry B0 B1 B2 B11 B3 B5 B6 B4 B7 B8
{B10}

entry B0
{}

B11
{B6}

B1
{B6, exit}

B6
{exit}

exit

B8 B10

B9

B2

B7

B10
{exit}

{B8, B6} {B8, B10}

B3 exit
{B5}

B4
{B8}

B5
{B6}

B9
{B10}
40

You might also like