170 likes | 305 Views
Code Optimization Circa 1969. Flow Graphs Constant Folding Global Common Subexpressions Induction Variables/Reduction in Strength. Jeffrey D. Ullman Stanford University. Dawn of Code Optimization. A never-published Stanford technical report by Fran Allen in 1968 .
E N D
Code Optimization Circa 1969 Flow GraphsConstant FoldingGlobal Common SubexpressionsInduction Variables/Reduction in Strength Jeffrey D. Ullman Stanford University
Dawn of Code Optimization • A never-published Stanford technical report by Fran Allen in 1968. • Fran won the Turing award in 2006. • Flow graphs of intermediate code. • Key things worth doing.
Intermediate Code • Steps with < 3 addresses (2 operands + result). • Assignments with < 1 arithmetic operator. • Examples: x = 0; x = y; x = y+z but not x = w+y*z. • Indirection and pointer access. • Examples: x = *p; p = &x; x = a[i]; x[i] = y. • Branches with one comparison operator, gotos. • Examples: if x == 0 goto s1; goto s2 but not if x == 0 || y == 1 goto s3. • Call, return. • Arguments copied like assignments w/o operator.
Example: Intermediate Code • Here’s typical source code: for (i=0; i<n; i++) A[i] = 1.0; • Intermediate code exposes optimizable constructs we cannot see at source-code level. i = 0 L1: if i>n goto L2 t1 = 8*i A[t1] = 1.0 i = i+1 goto L1 L2: ... Notice hidden offset calculation.
Basic Blocks • Make flow explicit by breaking into basic blocks= sequences of steps with entry at beginning, exit at end, no branches in interior. • Break intermediate code at leaders = • First statement. • Statements targeted by a branch or goto. • Statements following a branch. • Simplification: make each intermediate-code statement its own basic block. • Saves the trouble of figuring out data flow within blocks.
i = 0 if i>n goto … t1 = 8*i A[t1] = 1.0 i = i+1 Example: Basic Blocks i = 0 L1: if i>n goto L2 t1 = 8*i A[t1] = 1.0 i = i+1 goto L1 L2: ...
Induction Variables • x is an induction variableat a point within a loop if it takes on a linear sequence of values each time through that point. • One induction variable can do the job of another. • Common case: loop index like i and computed array offset like t1. • We really don’t need i. • Replace multiplication by addition (reduction in strength).
Example: Replace i by t1 • In the basic block t1 = 8*i; A[t1] = 1.0; i = i+1, t1 = 8i at the point where t1 is used, at A[t1] = 1.0. • Replace i = i+1 by t1 = t1 + 8. • Initialize t1 = 0. • Now, t1 always has value 8i where it is used, even though its calculation does not depend on i. • We can drop i = 0 and t1 = 8*i altogether if we replace the test i <= n.
i = 0 if i>n goto … t1 = 8*i A[t1] = 1.0 i = i+1 Example: Eliminating i Needed to express condition i <= n in terms of t1 t1 = 0 n1 = 8*n if t1>n1 goto … A[t1] = 1.0 t1 = t1+8 Question: is that always good? Initialization block grows, but the loop block shrinks
Loop-Invariant Code Motion • Sometimes, a computation is done each time around a loop. • Move it before the loop to save n-1 computations. • Be careful: could n=0? I.e., the loop is typically executed 0 times.
Example: y+z is Loop-Invariant So move computation of t1 here and compute it only once i = 0 i = 0 t1 = y+z if i>n goto … if i>n goto … t1 = y+z x = x+t1 i = i+1 x = x+t1 i = i+1 Neither y nor z changes within the loop
Constant Folding • Sometimes a variable has a known constant value at a point. • If so, replacing the variable by the constant simplifies and speeds-up the code. • Easy within a basic block; harder across blocks.
i = 0 n = 100 if i>n goto … t1 = 8*i A[t1] = 1.0 i = i+1 Example: First Flowgraph, but Fixed n Notice n1 is no longer needed So make the substitution at compile time Only possible assignment to this n1 is n1 = 800 t1 = 0 n1 = 8*100 t1 = 0 if t1>n1 goto … if t1>800 goto … A[t1] = 1.0 t1 = t1+8 A[t1] = 1.0 t1 = t1+8 Not only did we eliminate n1, but comparison of a variable And a constant can’t be worse than comparing two variables.
Global Common Subexpressions • Suppose block B has a computation of x+y. • Suppose we are certain that when we reach this computation, we have: • Computed x+y, and • Not subsequently reassigned x or y. • Then we can hold the value of x+yin a temporary variable and use it in B.
a = x+y t = x+y a = t b = x+y t = x+y b = t c = x+y c = t Example: Common Subexpression Elimination t holds value of x+y Every place x+y might be computed prior to c = x+y We know t has the right value here
Partial Redundancy Elimination • Not known in 1969. • Sometimes, an expression has been computed along some paths to a block B, but not along others. • Replicate the block so the expression is computed exactly when it is needed.
t = x+y a = t t = x+y b = t c = t Example: Partial Redundancy Elimination We may already have computed x+y So duplicate the block, depending on how it is reached t = x+y a = t b = t t = x+y b = t c = t Here, t already holds the value we need for b Here it doesn’t; so compute it