
CSc 453 Compilers and Systems Software Introduction 22 : Optimization Department of Computer Science University of Arizona [email protected] Copyright °c 2009 Christian Collberg Compiler Phases Intermediate Code Optimization Local Opt Global Opt Inter−Proc. Opt Transformation 1 Transformation 1 Transformation 1 Transformation 2 Transformation 2 Transformation 2 tokens .... .... .... source Lexer Parser Lexical Analysis AST Syntactic Analysis AST Semantic Analysis errors errors gen[S]={..} kill[S1]={..} AST ... IR Tree Interm. Semantic Optimize SOURCE Transformations Code Gen Analyser Build Call Data Flow B5 IR Graph Analysis AST errors Machine We are here! Code Gen Or how about here? Machine Code Gen. Or maybe here! Interm. Code Gen. asm Peephole Opt. Control Flow Analysis What do we Optimize? 1 Optimize everything, all the time. The problem is that optimization interferes with debugging. In fact, many (most) compilers don’t let you generate an optimized program with What do we Optimize? debugging information. The problem of debugging optimized code is an important research field. Furthermore, optimization is probably the most time consuming pass in the compiler. Always optimizing everything (even routines which will never be called!) wastes valuable time. 2 The programmer decides what to optimize. The problem is that the programmer has a local view of the code. When timing a program programmers are often very surprised to see where most of the time is spent. 3 Turn optimization on when program is complete. 5 Use profiling information to guide what to optimize. Compiler Code Unfortunately, optimizers aren’t perfect, and a program that Optimizer Front−End Generator performed OK with debugging turned on often behaves Profile differently when debugging is off and optimization is on. data "Carefully Executable 4 Optimize inner loops only. Unfortunately, procedure calls can chosen input" Program hide inner loops: 6 Runtime code generation/optimization. We delay code PROCEDURE P(n); generation and optimization until execution time. At that BEGIN time we have more information to guide the otpimizations: Execution time FOR k:=1 TO n DO ··· END; Interm. Code Interm. Compiled call P(x,3) END P; Compiler Code Table Code Table Front−End P [...] P [...] Gen spec. code Q [...] Q [...] for P(_,3), P(_,3) [...] optimize, then FOR i:=1 TO 10000 DO P(i) END; call Specialized Code Local, Global, Inter-Proc. Some compilers optimize more aggressively than others. An aggressive compiler optimizes over a large piece of code, a Local vs. Global vs. simple one only considers a small chunk of code at a time. Inter-procedural Optimization Local Optimization: Consider each basic block by itself. (All compilers.) Global Optimization: Consider each procedure by itself. (Most compilers.) Inter-Procedural Optimization: Consider the control flow between procedures. (A few compilers do this.) Local Optimization — Transformations Peephole Optimization Local common subexpression elimination. Can be done at the machine code level or at the intermediate Local copy propagation. code level. Local dead-code elimination. 1 Examine a “window” of instructions. Algebraic optimization. 2 Improve code in window. Jump-to-jump removal. 3 Slide window. Reduction in strength. 4 Repeat until “optimal”. Peephole optimization—Redundant Loads A naive code generator will generate the same address or variable several times. Local Optimization A:=A+1; ⇒ set A, %l0 set A, %l1 ld [%l1], %l1 add %l1, 1, %l1 st %l1, [%l0] ⇓ set A, %l0 ld [%l0], %l1 add %l1, 1, %l1 st %l1, [%l0] Peephole optimization—Jumps-to-jumps Algebraic Simplification Beware of numerical problems: Complicated boolean expressions (with many and, or, (x ∗ 0.00000001) ∗ 10000000000.0 nots) can easily produce lots of jumps to jumps. may produce a different result than if a < b goto L1 ⇒ if a < b goto L3 ... ... (x ∗ 1000.0) L1: goto L2 L1: goto L3 ... ... ! L2: goto L3 L2: goto L3 FORTRAN requires that parenthesis be honored: (5.0 ∗ x) ∗ (6.0 ∗ y) can’t be evaluated as (30.0 ∗ x ∗ y). Note that multiplication is often faster than division. Algebraic Simplification. Reduction in Strength SHL(x,y) = shift x left y steps. Multiplications (and divisions) by constants can be replaced x := x + 0; ⇒ by cheaper sequences of shifts and adds. x := x - 0; ⇒ x := x ∗ 32 ⇒ x := SHL(x, 5); x := x ∗ 1; ⇒ x := 1 ∗ 1; ⇒ x := 1 x := x ∗ 100 x := x / 1; ⇒ ⇓ x := x ** 2; ⇒ x := x * x; x := x ∗ (64 + 32 + 4) f := f / 2.0; ⇒ f := f ∗ 0.5; ⇓ x := x ∗ 64 + x ∗32 + x ∗4 ⇓ x := SHL(x,6) + SHL(x,5) + SHL(x,2) Local, Global,Inter-Procedural FUNCTION P (X,n): INT; Original Code IF n=3 THEN RETURN X[1] ELSE RETURN X[n]; CONST R = 1; FUNCTION P (X,n): INT; BEGIN IF n = 3 THEN RETURN X[1] K := 3; ... ELSE RETURN X[n]; IF P(X,K) = X[1] THEN X[1] := R * (X[1] ** 2) CONST R = 1; BEGIN After Local Optimization K := 3; ... IF P(X,K) = X[1] THEN FUNCTION P (X,n): INT; X[1] := R * (X[1] ** 2) IF n=3 THEN RETURN X[1] ELSE RETURN X[n] BEGIN K := 3; ... IF P(X,K) = X[1] THEN X[1] := X[1] * X[1] FUNCTION P (X,n): INT; FUNCTION P (X,n): INT; IF n=3 THEN RETURN X[1] ELSE RETURN X[n] IF THEN RETURN ELSE RETURN n=3 X[1] X[n] BEGIN BEGIN IF P(X,3) = X[1] THEN X[1] := X[1] * X[1] K := 3; ... After Inter-Procedural Opt IF P(X,K) = X[1] THEN X[1] := X[1] * X[1] BEGIN After Global Optimization IF TRUE THEN X[1] := X[1] * X[1] FUNCTION P (X,n): INT; After Another Local Opt IF n=3 THEN RETURN X[1] ELSE RETURN X[n] BEGIN BEGIN X[1] := X[1] * X[1] ... IF P(X,3) = X[1] THEN X[1] := X[1] * X[1] Delete P if it isn’t used elsewhere. This can maybe be deduced by an inter-procedural analysis. Global Optimization Makes use of control-flow and data-flow analysis. Dead code elimination. Global Optimization Common subexpression elimination (local and global). Loop unrolling. Code hoisting. Induction variables. Reduction in strenght. Copy propagation. Live variable analysis. Uninitialized Variable Analysis. Control Flow Graphs B1 Common Sub−Expression Elimination Perform optimizations over the control flow graph of a procedure. B1 B2 Basic Block B2 B3 if ... goto B2 t3 := 4 * j t3 := 4 * j B3 t5 := j * 4 A[t3] := 20 A[t5] := 20 if ... goto B3 B4 B4 No changes to j here! if ... goto B6 B5 B6 B5 goto B2 t9 := 4 * j x := A[t9] x := A[t3] No changes to x! x := 23 B1 Dead Code B3 Elimination x := t3 x := t3 Copy Propagation B2 No changes to x here! A[t4] := x A[t4] := t3 if x>20 goto B4 B4 B3 A[t4] := t3 t1 := 4 * j A[t3] := 20 No more uses of x! B5 B4 Nor here! A[x] := 20 A[t3] := 20 B5 Many optimizations produce X := Y . After an assignment X := Y , replace references to X by Y . A piece of code is dead if we can determine at compile time Remove the assignment if possible. that it will never be executed. x := 23 B1 Induction Variables Code B2 B1 B1 Hoisting if a<5 goto B2 t1 := A[i+3]; if a<5 goto B2 t1 := 4 * j B2 B3 B2 B3 B3 x := 23; X:=A[i+3]*6 X:=A[i+3]+9 X:=t1+9 X:=t1*6 j := j + 1 REPEAT j := j + 1 j := j + 1; t1 := 4 * j t1 := t1 + 4 t4 := A[4*j] UNTIL ....; t4 := A[t1] t4 := A[t1] if ... goto B3 if ... goto B3 IF a < 5 THEN X := A[i+3] + 9; B4 ELSE X := A[i+3] * 6 END If i and j are updated simultaneously in a loop, and Move code that is computed twice in different basic blocks to j = i ∗ c1 + c2 (c1, c2 are consants) we can remove one of a common ancestor block. them, and/or replace ∗ by +. Loop Unrolling – Constant Bounds FOR i := 1 TO 5 DO Loop Unrolling A[i]:=i END ⇓ A[1] := 1; A[2] := 2; A[3] := 3; A[4] := 4; A[5] := 5; Loop unrolling increases code size. How does this effect caching? Loop Unrolling – Variable Bounds FOR i := 1 TO n DO A[i] := i END ⇓ Inter-procedural Optimizations i := 1; WHILE i <= (n-4) DO A[i]:=i; A[i+1]:=i+1; A[i+2]:=i+2; A[i+3]:=i+3; A[i+4]:=i+4; i:=i+5; END; WHILE i<=n DO A[i]:=i; i:=i+1; END Inter-procedural Optimization Inline Expansion—Original Code Consider the entire program during optimization. FUNCTION Power (n, exp:INT):INT; How can this be done for languages that support separately IF exp < 0 THEN result := 0; compiled modules? ELSIF exp = 0 THEN result := 1; Transformations ELSE result := n; Inline expansion: Replace a procedure call with the code of the FOR i := 2 TO exp DO called procedure. result := result * n; Procedure Cloning: Create multiple specialized copies of a single END; END; procedure. RETURN result; END Power; Inter-procedural constant propagation: If we know that a particular procedure is always called with a constant BEGIN X := 7; PRINT Power(X,2) END; parameter with a specific value, we can optimize for this case. Inline Expansion—Expanded Code Inline Expansion—After copy propagation BEGIN BEGIN X := 7; X := 7; result := X; result := 7; FOR i := 2 TO 2 DO FOR i := 2 TO 2 DO result := result * X; result := result * 7; END; END; PRINT result; PRINT result; END END Inline Expansion—More optimization Procedure Cloning—Original Code After loop unrolling BEGIN FUNCTION Power (n, exp:INT):INT; X := 7; IF exp < 0 THEN result := 0; result := 7; ELSIF exp = 0 THEN result := 1; result := result * 7; ELSE result := n; PRINT result; FOR i := 2 TO exp DO END result := result * n; END; After constant folding RETURN result; BEGIN END Power; result := 49; PRINT result; BEGIN PRINT Power(X,2), Power(X,7) END; END Procedure Cloning—Cloned Routines FUNCTION Power0 (n):INT; RETURN 1; Machine Dependent vs.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages17 Page
-
File Size-