Fall 2014-2015 Compiler Principles Lecture 0: Local Optimizations Roman Manevich Ben-Gurion University Tentative syllabus Front End Intermediate Representation Optimizations Code Generation Local Optimizations Register Allocation Top-down Parsing (LL) Dataflow Analysis Instruction Selection Bottom-up Parsing (LR) Loop Optimizations Scanning mid-term Lowering exam 2 Previously • • • • The need for Intermediate Representations Three-Address Code Lowering abstract syntax trees (AST) to IR Sethi-Ullman algorithm for efficient lowering 3 agenda • Introduction to optimizations • Formalisms for program analysis – Basic blocks – Control flow graphs • Local program analyses and optimizations – Available expressions common sub-expression elimination + copy propagation – Live variables dead code elimination 4 Introduction to optimizations 5 Optimization points source code User profile program change algorithm Front end IR Compiler apply IR optimizations Code generator target code Compiler register allocation instruction selection peephole transformations today and next week 6 Overview of IR optimization • Formalisms and Terminology – Control-flow graphs – Basic blocks • Local optimizations – Optimizing small pieces of a function • Global optimizations – Optimizing functions as a whole • The dataflow framework – Defining and implementing a wide class of optimizations 7 Semantics-preserving optimizations • An optimization is semantics-preserving if it does not alter the semantics of the original program • Examples: – Eliminating unnecessary statements – Computing values that are known statically at compile-time instead of runtime – Evaluating constant expressions outside of a loop instead of inside • Non-examples: – Reordering side-effecting computations – Replacing bubble sort with quicksort (why?) • The optimizations we will consider in this class are all semantics-preserving • How can we find opportunities for optimizations? 8 Program analysis • In order to optimize a program, the compiler has to be able to reason about the properties of that program • An analysis is called sound if it never asserts an incorrect fact about a program • All the analyses we will discuss in this class are sound – (Why?) 9 Soundness int x; int y := get(); if (y < 5) x := 137; else x := 42; “At this point in the program, x holds some integer value” Print(x); 10 Soundness int x; int y := get(); if (y < 5) x := 137; else x := 42; “At this point in the program, x is either 137 or 42” Print(x); 11 Soundness int x; int y := get(); if (y < 5) x := 137; else x := 42; “At this point in the program, x is 137” Print(x); 12 Soundness int x; int y := get(); if (y < 5) x := 137; else x := 42; “At this point in the program, x is either 137, 42, or 271” Print(x); 13 Control flow graphs 14 Visualizing IR main: _tmp0 := Call _ReadInteger; a := _tmp0; _tmp1 := Call _ReadInteger; b := _tmp1; _L0: _tmp2 := 0; _tmp3 := b == _tmp2; _tmp4 := 0; _tmp5 := _tmp3 == _tmp4; IfZ _tmp5 Goto _L1; c := a; a := b; _tmp6 := c % a; b := _tmp6; Goto _L0; _L1: Push a; Call _PrintInt; 15 Visualizing IR main: _tmp0 := Call _ReadInteger; a := _tmp0; _tmp1 := Call _ReadInteger; b := _tmp1; _L0: _tmp2 := 0; _tmp3 := b == _tmp2; _tmp4 := 0; _tmp5 := _tmp3 == _tmp4; IfZ _tmp5 Goto _L1; c := a; a := b; _tmp6 := c % a; b := _tmp6; Goto _L0; _L1: Push a; Call _PrintInt; 16 Visualizing IR main: _tmp0 := Call _ReadInteger; a := _tmp0; _tmp1 := Call _ReadInteger; b := _tmp1; _L0: _tmp2 := 0; _tmp3 := b == _tmp2; _tmp4 := 0; _tmp5 := _tmp3 == _tmp4; IfZ _tmp5 Goto _L1; c := a; a := b; _tmp6 := c % a; b := _tmp6; Goto _L0; _L1: Push a; Call _PrintInt; start _tmp0 := Call _ReadInteger; a := _tmp0; _tmp1 := Call _ReadInteger; b := _tmp1; _tmp2 := 0; _tmp3 := b == _tmp2; _tmp4 := 0; _tmp5 := _tmp3 == _tmp4; IfZ _tmp5 Goto _L1; c := a; a := b; _tmp6 := c % a; b := _tmp6; Goto _L0; Push a; Call _PrintInt; end 17 Basic blocks • A basic block is a sequence of IR instructions where – There is exactly one spot where control enters the sequence, which must be at the start of the sequence – There is exactly one spot where control leaves the sequence, which must be at the end of the sequence • Informally, a sequence of instructions that always execute as a group 18 Control-flow graphs • A control-flow graph (CFG) is a graph of the basic blocks in a function – From here on CFG stands for “control-flow graph” and not “context free grammar” • Each edge from one basic block to another indicates that control can flow from the end of the first block to the start of the second block • Dedicated nodes for the start and end of a function 19 Scope of optimizations • An optimization is local if it works on just a single basic block • An optimization is global if it works on an entire control-flow graph • An optimization is interprocedural if it works across the control-flow graphs of multiple functions – We won't talk about this in this course 20 Examples of control flow graphs and optimizations 21 Basic blocks example int main() { int x; int y; int z; START: y := 137 + 3; if (x == 0) z := y; else x := y; { _t0 := 137; y := _t0 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; Goto END: _L0: _t2 := y; x := _t2; END: Divide the code into basic blocks 22 Control-flow graph example int main() { int x; int y; int z; START: y := 137 + 3; if (x == 0) z := y; else x := y; { _t0 := 137; y := _t0 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; Goto END: _L0: _t2 := y; x := _t2; END: Draw the control-flow graph 23 Control-flow graph example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start _t0 := 137; y := _t0 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; _t2 := y; x := _t2; end 24 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start _t0 := 137; y := _t0 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; _t2 := y; x := _t2; end 25 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start _t0 := 137; y := _t0 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; _t2 := y; x := _t2; end 26 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start Copy propagation y := 137 + 3; IfZ x Goto _L0; _t1 := y; z := _t1; _t2 := y; x := _t2; end 27 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start Constant folding y := 140; IfZ x Goto _L0; _t1 := y; z := _t1; _t2 := y; x := _t2; end 28 Local optimizations example int main() { int x; int y; int z; start y := 137 + 3; if (x == 0) z := y; else x := y; { Copy propagation y := 140; IfZ x Goto _L0; _t1 := y; z := y; _t2 := y; x := _t2; end 29 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start y := 140; IfZ x Goto _L0; Dead code elimination _t2 := y; x := _t2; z := y; end 30 Local optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start y := 140; IfZ x Goto _L0; _t2 := y; x := _t2; z := y; end 31 Local optimizations example int main() { int x; int y; int z; start y := 140; IfZ x Goto _L0; y := 137 + 3; if (x == 0) z := y; else x := y; { z := y; Copy propagation followed by dead code elimination x := y; end 32 Global optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start y := 140; IfZ x Goto _L0; z := y; x := y; end 33 Global optimizations example int main() { int x; int y; int z; y := 137 + 3; if (x == 0) z := y; else x := y; { start y := 140; IfZ x Goto _L0; z := y; x := y; end 34 Global optimizations example int main() { int x; int y; int z; start y := 137 + 3; if (x == 0) z := y; else x := y; { Copy propagation y := 140; IfZ x Goto _L0; z := 140; x := 140; end 35 Common Subexpression elimination 36 CSE Example b c d e := := := := a a b b * * + + a; a; c; b; 37 CSE Example b c d e := := := := a a b b * * + + a; a; c; b; 38 CSE Example b c d e := := := := a * a; b; b + c; b + b; Common sub-expression elimination 39 Common Subexpression Elimination • If we have two variable assignments v1 := a op b … v2 := a op b • and the values of v1, a, and b have not changed between the assignments, rewrite the code as v1 := a op b … v2 := v1 • Eliminates useless recalculation • Paves the way for later optimizations 40 copy propagation 41 CP Example b c d e := := := := a * a; b; b + c; b + b; 42 CP Example b c d e := := := := a * a; b; b + b; b + b; Copy propagation 43 Copy Propagation • If we have a variable assignment v1 := v2 then as long as v1 and v2 are not reassigned, we can rewrite expressions of the form a := … v1 … as a := … v2 … 44 Local optimizations example b c d e := := := := a * a; b; b + b; b + b; Which optimization should we apply here? 45 Local optimizations example b c d e := := := := a * a; b; b + b; d; Which optimization should we apply here? Common sub-expression elimination (again) 46 Optimizations and analyses • Most optimizations are only possible given some analysis of the program's behavior • In order to implement an optimization, we will talk about the corresponding program analyses • Program analysis = algorithm that processes program and infers facts – Sound facts = facts that hold for all program executions – Sound analysis = program analysis that infers only sound facts 47 Available expressions 48 Available expressions • Both common subexpression elimination and copy propagation depend on an analysis of the available expressions in a program • An expression a = b op c is called available at program location L if variable a holds the value of b op c at that location – Similarly for a = b • In common subexpression elimination, we replace an available expression (b op c) by the variable holding its value (a) • In copy propagation, we replace the use of a variable (a) by the available expression it holds (b) 49 Finding available expressions • Compute for each program location L a set of expressions AEL of the forms a = b op c and a = b that are definitely available there • Idea: Iterate across the basic block, beginning with the empty set of expressions and updating available expressions at each statement • Whenever we execute a statement a := b op c: – Any expression holding a is invalidated – The expression a = b op c becomes available 50 Available expressions step Input Value AEin a := b + c Note that this is an equation (a fact) – not a statement AEout = (AEin \ {e | e contains a}) {a=b+c} Expressions of the forms a=… and x=…a… Output Value AEout Provided that a and b and a and c are different pairs of variables 51 Available expressions example { } a := b; { a = b } c := b; { a = b, c d := a + b; { a = b, c e := a + b; { a = b, c d := b; { a = b, c f := a + b; { a = b, c = b } = b, d = a + b } = b, d = a + b, e = a + b } = b, d = b, e = a + b } = b, d = b, e = a + b, f = a + b } 52 Optimizing via available expressions • Common sub-expression elimination – If {… t = y op z … } x := y op z – Can transform statement into x := t • Copy propagation – If {… y = t … } x := y op z – Can transform statement into x := t op z • Note: same for x=y 53 Applying CSE + CP { } a := b; { a = b } c := b; { a = b, c d := a + b; { a = b, c e := a + b; { a = b, c d := b; { a = b, c f := a + b; { a = b, c = b } = b, d = a + b } = b, d = a + b, e = a + b } = b, d = b, e = a + b } = b, d = b, e = a + b, f = a + b } 54 Applying CSE + CP { } a := b; { a = b } c := b; { a = b, c d := a + b; { a = b, c e := a + b; { a = b, c d := b; { a = b, c f := a + b; { a = b, c = b } = b, d = a + b } = b, d = a + b, e = a + b } = b, d = b, e = a + b } = b, d = b, e = a + b, f = a + b } 55 Applying CSE + CP { } a := b; { a = b } c := a; { a = b, c d := a + b; { a = b, c e := d; { a = b, c d := a; { a = b, c f := e; { a = b, c = b } = b, d = a + b } = b, d = a + b, e = a + b } = b, d = b, e = a + b } = b, d = b, e = a + b, f = a + b } 56 dead code elimination 57 Dead code elimination a := b; c := a; d := a + b; Can we remove this statement? Can we remove this statement? Can we remove this statement? e := d; Can we remove this statement? d := a; Can we remove this statement? f := e; Can we remove this statement? Print(d); Can we remove this statement? 58 Dead code elimination • An assignment to a variable v is called dead if the value of that assignment is never read anywhere • Dead code elimination removes dead assignments from IR • Determining whether an assignment is dead depends on assignments preceding it 59 Live variables • The analysis corresponding to dead code elimination is called liveness analysis • A variable is live at a point in a program if later in the program its value will be read before it is written to again • Dead code elimination works by computing liveness for each variable, then eliminating assignments to dead variables 60 Computing live variables • To know if a variable will be used at some point, we iterate across the statements in a basic block in reverse order • Initially, some small set of values are known to be live (which ones depends on the particular program) – Usually arguments of a function call or a returned variable (temporaries that are pushed on the stack) • When we see the statement a := b op c: – Just before the statement, a is not alive, since its value is about to be overwritten – Just before the statement, both b and c are alive, since we're about to read their values – (what if we have a := a + b?) 61 Live variables step Input Value LVin a := b + c LVin = (LVout \ {a}) {b,c} Output Value LVout 62 { b } a := b; { a, b } c := a; { a, b } d := a + b; { a, b, d } e := d; { a, b, e } d := a; { b, d, e } f := e; { b, d } Push b; { d } Push d; { } Liveness analysis Which statements are dead? 63 Optimizing via liveness analysis • Dead code elimination – If x := y op z {v1,…,vk} – And x {v1,…,vk} – We can eliminate x := y op z • Note: same for x:=y 64 Dead code elimination { b } a := b; { a, b } c := a; Which statements are dead? { a, b } d := a + b; { a, b, d } e := d; { a, b, e } d := a; { b, d, e } f := e; { b, d } - given 65 Dead code elimination { b } a := b; { a, b } { a, b } d := a + b; { a, b, d } e := d; { a, b, e } d := a; { b, d, e } { b, d } 66 Liveness analysis II { b } a := b; { a, b } d := a + b; { a, b, d } e := d; { a, b } d := a; { b, d } Which statements are dead? 67 Liveness analysis II { b } a := b; { a, b } d := a + b; { a, b, d } e := d; { a, b } d := a; { b, d } Which statements are dead? 68 Dead code elimination { b } a := b; { a, b } d := a + b; { a, b, d } e := d; { a, b } d := a; { b, d } Which statements are dead? 69 Dead code elimination { b } a := b; { a, b } d := a + b; { a, b, d } { a, b } d := a; { b, d } 70 Liveness analysis III { b } a := b; { a, b } d := a + b; Which statements are dead? { a, b } d := a; { b, d } 71 Dead code elimination { b } a := b; { a, b } d := a + b; Which statements are dead? { a, b } d := a; { b, d } 72 Dead code elimination { b } a := b; { a, b } { a, b } d := a; { b, d } 73 Dead code elimination a := b; If we further apply copy propagation this statement can be eliminated too d := a; 74 A combined algorithm • Start with initial live variables at end of block • Traverse statements from end to beginning • For each statement – If assigns to dead variables – eliminate it – Otherwise, compute live variables before statement and continue in reverse 75 A combined algorithm a := b; c := a; d := a + b; e := d; d := a; f := e; 76 A combined algorithm a := b; c := a; d := a + b; e := d; d := a; f := e; { b, d } 77 A combined algorithm a := b; c := a; d := a + b; e := d; d := a; f := e; { b, d } 78 A combined algorithm a := b; c := a; d := a + b; e := d; d := a; { b, d } 79 A combined algorithm a := b; c := a; d := a + b; e := d; { a, b } d := a; { b, d } 80 A combined algorithm a := b; c := a; d := a + b; e := d; { a, b } d := a; { b, d } 81 A combined algorithm a := b; c := a; d := a + b; { a, b } d := a; { b, d } 82 A combined algorithm a := b; c := a; d := a + b; { a, b } d := a; { b, d } 83 A combined algorithm a := b; c := a; { a, b } d := a; { b, d } 84 A combined algorithm a := b; c := a; { a, b } d := a; { b, d } 85 A combined algorithm a := b; { a, b } d := a; { b, d } 86 A combined algorithm { b } a := b; { a, b } d := a; { b, d } 87 A combined algorithm a := b; d := a; 88 Notes about optimizations 89 Applying local optimizations • The different optimizations we've seen so far all take care of just a small piece of the optimization – Common subexpression elimination eliminates unnecessary statements – Copy propagation helps identify dead code – Dead code elimination removes statements that are no longer needed • To get maximum effect, we may have to apply these optimizations numerous times 90 Optimization path done with IR optimizations IR CFG builder Control-Flow Graph Code Generation (+optimizations) IR optimizations Target Code Program Analysis Annotated CFG Optimizing Transformation 91 Other types of local optimizations • Arithmetic Simplification – Replace “hard” operations with easier ones – e.g. rewrite x := 4 * a; as x := a << 2; • Constant Folding – Evaluate expressions at compile-time if they have a constant value. – e.g. rewrite x := 4 * 5; as x := 20; 92 Next lecture: Global Optimizations via Dataflow Analysis