Code Improving Transformations
Chapter 13,14
Mooly Sagiv
Outline• Chapter 12- Redundency Elimination
– Global common sub-expression elimination/Forward Substitution
– Loop-Invariant Code Motion– Partial Redundency Elimination– Code Hoisting
• Chapter 13 - Loop Optimization (Friday)– Induction-Variable Optimizations– Strength Reduction– Live Variable Analysis– Optimizing array bound checking
Global Common Subexpression Elimination
entry
b a+2
c 4 * b
b < c
b1
b a+2
exit
Y
N
entry
t1 a+2
b t1
c 4 * b
b < c
b t1
exit
Y
N
b1
Who generates common subexpressions?
• Functional programming style
• Hidden computations in high level constructs – local variables allocated at stack frames– structure elements– array references
• array bound checking
– strings– ...
A Simple Iterative Computation
• Local information in basic blocks– EVALP - the expression that must be computed
executing the block– KILLP - the expressions that may be killed by
executing the block
• System of equations
AEinP(ENTRY) =
AEinP(B) = B’ Pred(B) AEoutP(B’)
AEoutP(B) = EVALP(B) (AEinP(B)-KILLP(B))
entry, exit
B1 {(a+b),(a*c), (d*d)}
B2 {(a+b), (c*2)}
B3 {(a*c)}
B4 {(d*d)}
B5
EVALP KILLP
entry, exit
B1 {(a*c),(d*d)}
B2 {(a*c), (c*2)}
B3
B4
B5 entry
B1
B2 {(a+b), (d*d)}
B3 {(a+b), (d*d)}
B4 {(a+b), (d*d)}
B5 {(a+b), (d*d)}
exit {(a+b), (d*d)}
AEinP
How does this algorithm relate to Kildall’s?
Using Global Information
• All the expressions e AEinP(B) are available at the beginning of B
• But how can we determine– the usage of e in B– the places where e is generated?
• Represent available expressions as triplets <e, B, k> - e is generated in block B at position k
• Local information is now tripletslocks– EVALP - the expression that must be computed
executing the block– KILLP - the expressions that may be killed by
executing the block
• System of equations AEinP(ENTRY) =
AEinP(B) = B’ Pred(B) AEoutP(B’)
AEoutP(B) = EVALP(B) (AEinP(B)-KILLP(B))
entry
B1 {<a+b, B1, 1>,<a*c, B1, 2>,<d*d, B1,3>}
B2 {<a+b, B2,1>, <c*2, B2, 2>}
B3 {<a*c, B3, 1>}
B4 {<d*d, B4, 1>}
B5
exit
EVALP
KILLP
entry
B1 {<a*c, B3, 1>,<d*d, B4, 1>}
B2 {<a*c, B1, 1>, <a*c, B3, 1>,<c*2, B2, 2>}
B3
B4
B5
exit
entry
B1
B2 {<a+b, B1, 1>, <d*d, B1, 3>}
B3 {<a+b, B1, 1>, <d*d, B1, 3>}
B4 {<a+b, B1, 1>, <d*d, B1, 3>}
B5 {<a+b, B1, 1>, <d*d, B1, 3>}
exit {<a+b, B1, 1>, <d*d, B1, 3>}
Global Subexpression Elimination
• For every e s.t. <e, *, *> AEinP(B)
• Locate the first occurrence of e in B
• Search backward to find if e was modified in B
• If e was not modified then:– generate a new temporary tj– replace the occurrence of e by tj– for all <e, B’, j> AEinP(B)
• assign e to tj
• replace e by tj
entry
B1
B2 {<a+b, B1, 1>, <d*d, B1, 3>}
B3 {<a+b, B1, 1>, <d*d, B1, 3>}
B4 {<a+b, B1, 1>, <d*d, B1, 3>}
B5 {<a+b, B1, 1>, <d*d, B1, 3>}
exit {<a+b, B1, 1>, <d*d, B1, 3>}
Copy Propagation
• Common subexpression elimination may generate a lot of copy assignments x y
• Can lead to slower programs (why?)
• Solutions:– Try to avoid copies (e.g., using CFA
information) – Apply copy propagation algorithm– Use register allocation with coalescing
Forward Substitution
• But still in many cases it my be beneficial to re-evaluate expressions
• Can be implemented easily
• Conclusions – LIR can be more appropriate for common
subexpression-elimination– Algorithms that combines elimination with
register allocation are being invented
ab+2
cb+2
d a*b
t1b+2
a t1
ct1
d a*b
Loop Invariant Code Motion
• Can be simply implemented using:– natural loops or strongly connected components– ud-chains
• In many cases cannot be eliminated by the programmer
A simple example
do i=1,100
do j =1,100
a(i, j) = 100*n+10*(i*(n+2))+j
enddo
enddo
t1 = 100*n
t2 = 10* (n+2)
do i=1,100
t3 = t1 + i * t2
do j =1,100
a(i, j) = t3+j
enddo
enddo
Identifying Loop Invariants
• An instruction is loop invariant if for every operand:– the operand is constant– all the definitions that reach this use are outside
the loop– there is exactly one definition that reaches this
use from inside the loop and this instruction is loop invariant
Partial Redundency Elimination
• An expression is partially redundent at a program point if it is computed more than once along some path to that point
• Generalizes loop invariants and commonsubexpression elimination
• Does not require loop identification• The original formulation is bi-directed• Formulated by Knoop, Ruting, and Steffen as
a series of unidirectional bit-vector problems
Code Hoisting• Find expressions that are “very busy”
evaluated at all paths
• An expression is very busy if it is evaluated regardless of the path taken from that point
• Can be used to reduce code size
• Iterative solution
VBout(EXIT) =
VBout(B) = B’ Succ(B) VBin(B’)
VBin(B) = EVALP(B) (VBout(B)-KILLP(B))
Reassociation
• Can lead to many more common subexpression/loop invariants/partial redundencies
A Trivial Example
do i=m,n
a = b + i
c = a - i
d = a
enddo
do i=m,n
a = b + i
c = b
d = a
enddo
c = b
do i=m,n
a = b + i
d = a
enddo
Conclusions
• Two viable options– common subexpression elimination+loop
invariant code motion– partial redundency elimination
• Optimizations that may help:– before? - constant propagation, reassociation– after? - copy propagation, code hoisting, dead-
code elimination