Download presentation
Presentation is loading. Please wait.
Published byEdgar Reynolds Modified over 8 years ago
1
Compiler Principles Fall 2014-2015 Compiler Principles Lecture 8: Intermediate Representation Roman Manevich Ben-Gurion University
2
Tentative syllabus Front End Scanning Top-down Parsing (LL) Bottom-up Parsing (LR) Intermediate Representation Lowering Optimizations Local Optimizations Dataflow Analysis Loop Optimizations Code Generation Register Allocation Instruction Selection 2 mid-termexam
3
Previously Why compilers need Intermediate Representations (IR) Translating from abstract syntax (AST) to IR – Three-Address Code Local optimizations – Sethi-Ullman algorithm for efficient code generation 3
4
cgen for basic expressions 4 cgen(k) = { // k is a constant Choose a new temporary t Emit( t := k ) Return t { cgen(id) = { // id is an identifier Choose a new temporary t Emit( t := id ) Return t {
5
Naive cgen for binary expressions Maintain a counter for temporaries in c Initially: c = 0 cgen(e 1 op e 2 ) = { Let A = cgen(e 1 ) c = c + 1 Let B = cgen(e 2 ) c = c + 1 Emit( _tc := A op B; ) Return _tc } 5 The translation emits code to evaluate e 1 before e 2. Why is that?
6
Example: cgen for binary expressions 6 cgen( (a*b)-d)
7
Example: cgen for binary expressions 7 c = 0 cgen( (a*b)-d)
8
Example: cgen for binary expressions 8 c = 0 cgen( (a*b)-d) = { Let A = cgen(a*b) c = c + 1 Let B = cgen(d) c = c + 1 Emit( _tc := A - B; ) Return _tc }
9
Example: cgen for binary expressions 9 c = 0 cgen( (a*b)-d) = { Let A = { Let A = cgen(a) c = c + 1 Let B = cgen(b) c = c + 1 Emit( _tc := A * B; ) Return tc } c = c + 1 Let B = cgen(d) c = c + 1 Emit( _tc := A - B; ) Return _tc }
10
Example: cgen for binary expressions 10 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code here A=_t0
11
Example: cgen for binary expressions 11 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; here A=_t0
12
Example: cgen for binary expressions 12 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; _t1:=b; here A=_t0
13
Example: cgen for binary expressions 13 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; _t1:=b; _t2:=_t0*_t1 here A=_t0
14
Example: cgen for binary expressions 14 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; _t1:=b; _t2:=_t0*_t1 here A=_t0 here A=_t2
15
Example: cgen for binary expressions 15 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; _t1:=b; _t2:=_t0*_t1 _t3:=d; here A=_t0 here A=_t2
16
Example: cgen for binary expressions 16 c = 0 cgen( (a*b)-d) = { Let A = { Let A = { Emit(_tc := a;), return _tc } c = c + 1 Let B = { Emit(_tc := b;), return _tc } c = c + 1 Emit( _tc := A * B; ) Return _tc } c = c + 1 Let B = { Emit(_tc := d;), return _tc } c = c + 1 Emit( _tc := A - B; ) Return _tc } Code _t0:=a; _t1:=b; _t2:=_t0*_t1 _t3:=d; _t4:=_t2-_t3 here A=_t0 here A=_t2
17
Naïve translation cgen translation shown so far very inefficient – Generates (too) many temporaries – one per sub- expression – Generates many instructions – at least one per sub-expression Expensive in terms of running time and space Code bloat We can do much better 17
18
agenda Lowering optimizations – Sethi-Ullman algorithm for efficient code generation 18
19
19 Lowering optimization
20
Improving cgen for expressions 1.Improve translation for leaves 2.Reuse temporaries 3.Weighted register allocation for expression trees – Reorder computations 20
21
21 Optimization 1: leaves
22
Improving cgen for leaves cases Observation – naïve translation needlessly generates temporaries for leaf expressions Solution: treat leaves as special cases by returning them immediately without storing them in temporaries 22
23
23 Optimization 2: reusing temporaries
24
cgen with temporaries recycling Observation – temporaries used exactly once – Once a temporary has been read it can be reused for another sub-expression Want to implement cgen(x := e 1 op e 2 ) with small number of temporaries cgen(x := e 1 op e 2 ) = { c = 0 Emit(x := cgen(e 1 op e 2 )) } 24 How can we make this more efficient?
25
Improved cgen c = 0 cgen(e 1 op e 2 ) = { cgen(e 1 ) c = c + 1 cgen(e 2 ) c = c - 1 Emit( _tc := _tc op _tc+1; ) } 25
26
Example 26 c = 0 cgen( (a*b)-d) = { { { Emit(_tc := a;), return _tc } c = c + 1 { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) } c = c + 1 { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) } Code c=0
27
Example 27 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; c=1
28
Example 28 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; c=1
29
Example 29 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; c=0
30
Example 30 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; _t0:=_t0*_t1 c=0
31
Example 31 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; _t0:=_t0*_t1; c=1
32
Example 32 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; _t0:=_t0*_t1; _t1:=d; c=1
33
Example 33 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; _t0:=_t0*_t1; _t1:=d; c=0
34
Example 34 c = 0 cgen( (a*b)-d) = { Let _tc = { Let _tc = { Emit(_tc := a;), return _tc } c = c + 1 Let _tc = { Emit(_tc := b;), return _tc } c = c - 1 Emit( _tc := _tc * _tc+1; ) Return _tc } c = c + 1 Let _tc = { Emit(_tc := d;), return _tc } c = c - 1 Emit( _tc := _tc - _tc+1; ) Return _tc } Code _t0:=a; _t1:=b; _t0:=_t0*_t1; _t1:=d; _t0:=_t0-_t1; c=0
35
Example 2 _t0 := cgen( ((c*d)-(e*f))+(a*b) ) _t0 := c*d _t1 := e*f _t0 := _t0 -_t1 c = c + 1 c = c - 1 c = 0 _t0 := cgen(c*d)-(e*f)) _t1 := a*b c = c + 1 _t0 := _t0 + _t1 c = c - 1 35
36
36 Optimization 3: weighted register allocation
37
Sethi-Ullman translation Algorithm by Ravi Sethi and Jeffrey D. Ullman to emit optimal TAC – Minimizes number of temporaries – (Minimizes number of instructions by reducing spills) – A kind of local register allocation (within single expressions) Uses two ideas 1.Reusing temporaries 2.Choosing order of translation 37
38
Weighted register allocation Suppose we have expression e 1 op e 2 – e 1, e 2 without side-effects That is, no function calls, memory accesses, ++x – Does order of translation matter? … Yes Sethi & Ullman’s algorithm translates heavier sub-tree first – Optimal local (per-statement) allocation for side- effect-free statements 38
39
Example 1 (assuming leaves require temporaries) _t0 := cgen( a+(b+(c*d)) ) b cd * + + a _t0 _t1 _t2 4 temporaries _t2 _t1 left child first b cd * + + a _t0 2 temporaries _t0 right child first _t0 39 _t1 _t3
40
Sethi-Ullman: weighted register allocation Can save registers by re-ordering subtree computations Phase 1: check that no side-effects exist and otherwise revert to translation following pre-defined order of computation Phase 2: assign weight to each node – Weight = number of registers needed – Leaf weight known – Internal node weight w(left) > w(right) then w = left w(right) > w(left) then w = right w(right) = w(left) then w = left + 1 Phase 3: translate by following heavier child first 40
41
Sethi-Ullman algorithm example cgen( g := (a+b)+((c+d)+(e+f))) ef + + + 41 ab + w=1 w=2w=1 w=2w=3 Code _t0 := c; _t1 := d; _t0 := _t0 * _t1; _t1 := e; _t2 := f; _t1 := _t1 * _t2; _t0 := _t0 - _t1 _t1 := a; _t2 := b; _t1 := _t1 -_t2 _t0 := _t1 - _t0 g := _t0 cd + w=1 w=2
42
Example with side effects b 5c * array access + a baseindex w=1 w=2w=1w=2 Phase 1: check absence of side-effects in expression tree Phase 2: assign weight to each AST node 42 _t0 := cgen( a+b[5*c] )
43
Example with side effects b 5c * array access + a _t0 baseindex W=2 Phase 2: use weights to decide on order of translation Heavier sub-tree _t0 := _t1 * _t0 _t0 := _t1[_t0] _t0 := _t1 + _t0 43 _t0 := cgen( a+b[5*c] ) w=1 w=2w=1w=2 _t0_t1 _t0 := c _t1 := 5 _t1 := b _t1 := a
44
Note on weighted register allocation The algorithm is local – works for a single expression Must reset temporaries counter after every statement: – x := y; y := z; should not be translated to _t0 := y; x := _t0; _t1 := z; y := _t1; – But rather to _t0 := y; x := _t0; # Finished translating statement. Set c=0 _t0 := z; y := _t0; 44
45
Going beyond the basic SU algorithm There exist advanced extensions of SU – Take into account semantics of operators – Take into account latency 45
46
Can we do better than basic SU here? cgen( g := (a+b)+((c+d)+(e+f))) ef + + + 46 ab + w=1 w=2w=1 w=2w=3 Code _t0 := c; _t1 := d; _t0 := _t0 + _t1; _t1 := e; _t2 := f; _t1 := _t1 + _t2; _t0 := _t0 + _t1 _t1 := a; _t2 := b; _t1 := _t1 +_t2 _t0 := _t1 + _t0 g := _t0 cd + w=1 w=2 What if we are allowed to rewrite expressions?
47
Can we do better than basic SU here? cgen( g := (a+b)+((c+d)+(e+f))) = cgen( g := a + (b + (c + (d + (e + f))))) + + 47 a Code _t0 := e; _t1 := f; _t0 := _t0 + _t1; _t1 := d; _t0 := _t0 + _t1; _t1 := c; _t0 := _t0 + _t1; _t1 := b; _t0 := _t0 + _t1; _t1 := a; _t0 := _t0 + _t1; g := _t0 +b +c +d fe w=1 w=2w=1w=2w=1w=2w=1w=2w=1w=2 Can rewrite since + is associative and commutative
48
Next lecture: Local Optimizations
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.