Loop invariant operations
for (i = 0; i < n; i++) { A[i] = m + n; }to (loop invariant code motion)
t = m + n; for (i = 0; i < n; i++) { A[i] = t; }
Partial Redundancy Elimination (aka lazy code motion)
Subsumes
BB1->BB2 BB1->BB3 BB2->BB4 BB3->BB4 BB2: a = b + c BB3: b = 7 BB4: d = b + ccan be changed to
BB1->BB2 BB1->BB3 BB2->BB4 BB3->BB4 BB2: t = b + c a = t BB3: b = 7 t = b + c BB3: d = tCan we place calculations of
b+c
such that no path re-executes the same expression? Algorithm based on PLDI92 paper by Knoop et. al. on "Lazy code motion"
BB1 --> BB3 BB2 --> BB3 BB2 --> BB4 BB1: c = a+b BB3: d = a+bA critical edge:
BB1 --> BB3 BB2 --> newBB BB2 --> BB4 newBB --> BB4 BB1: t = a+b c = t newBB: t = a+b BB3: d = t
Algorithm Prelims:
Algorithm Overview:
Example1:
BB1-->BB2 BB1-->BB3 BB1-->BB4 BB2-->BB5 BB3-->BB5 BB4-->BB6 BB2: x = a + b BB5: y = a + b BB4: a = 10 BB6: z = a + bchange to
BB1-->BB2 BB1-->BB3 BB1-->BB4 BB2-->BB5 BB3-->BB5 BB4-->BB6 BB2: x = a + b BB3: t = a + b BB5: y = t BB4: a = 10 t = a + b BB6: z = tNotice that we put t = a+b where a+b is "needed", i.e., it is needed on all paths in future
Example 2
BB1-->BB2 BB2-->BB3 BB3-->BB2 BB3-->BB4 BB2: x = a + bchange to
BB1-->BB2 BB2-->BB3 BB3-->BB2 BB3-->BB4 BB1: t = a+b BB2: x = tAgain, t=a+b is "needed" on all paths in future
Example 3
BB1-->BB2 BB2-->BB3 BB3-->BB4 BB4-->BB5 BB4-->BB6 BB5-->BB3 BB6-->BB3 BB1: x = a+b BB4: y=a+b BB6: a=10change to
BB1-->BB2 BB2-->BB3 BB3-->BB4 BB4-->BB5 BB4-->BB6 BB5-->BB3 BB6-->newBB newBB-->BB3 BB1: t = a+b x=t BB4: y=t BB6: a=10 newBB: t=a+b
Example 4 (not all redundancy can be eliminated)
BB1-->BB2 BB2-->BB3 BB3-->BB4 BB4-->BB5 BB5-->BB3 BB3-->BB6 BB6-->exit BB1: x=a+b BB5: y=a+b BB6: a=10change to
BB1-->BB2 BB2-->BB3 BB3-->BB4 BB4-->BB5 BB3-->BB6 BB6-->newBB newBB-->BB3 BB6-->exit BB1: t=a+b x=t BB5: y=t BB6: a=10 newBB: t=a+bThere is some redundancy in the transformed code which is unavoidable. Notice that the path from newBB to exit computes a+b even though it was not required. The other option is:
BB1-->BB2 BB2-->BB3 BB3-->BB4 BB4-->BB5 BB5-->BB3 BB3-->BB6 BB6-->exit BB1: t=a+b x=t BB5: t = a+b y=t BB6: a=10But now a+b is computed twice on the path B2->B3->B4->B5 (this is the solution that our analysis will yield).
{a+b}
for x=a+b
). Ekill is the set of expressions killed by this expression, e.g., all expressions containing x
are killed by x=a+b
.Proposal 1:
Example1
BB1->BB2 BB2->BB3 BB3->BB4 BB3->exit BB1: x=a+b BB4: y=a+bNow,
a+b
is needed at BB4 entry but not needed at BB3 exit. Yet computing t=a+b
on the edge BB3->BB4 is redundant because the expression a+b
is already available (or not missing) at BB4.
Example2
BB1->BB2 BB1->BB3 BB1->BB4 BB2->BB5 BB3->BB5 BB4: a=10 BB5: y=a+bHere, the frontier occurs at the end of BB1 but that is too early to compute
t=a+b
as we will take up an extra register for a long time unnecessarily!
Example3 (a more convincing example of why you should not compute a value too early)
BB1->BB2 BB1->BB3 BB2->BB4 BB4->BB2 BB4->BB5 BB5->BB6 BB3->BB7 BB7->BB6 BB3: a=b+c BB6: y=b+cThe frontier is at the end of BB1 but that would eat-up a register for the entire duration of the BB2-BB4 loop which seems too wasteful.
p
if its value has not been "needed" by any basic block along SOME path reaching p
. Will solve the redundancy problem with the first example.Place the expression at the earliest point we need it and is missing
x+y \in earliest[b]
, at beginning of b
, create a new variable t
, such that t=x+y
, and replace every original x+y
by t
.e
is postponed at a program point p
if: for all paths leading to p
, we have seen the earliest placement of e
but not a subsequent use. Take the third example again:
BB1->BB2 BB1->BB3 BB2->BB4 BB4->BB2 BB4->BB5 BB5->BB6 BB3->BB7 BB7->BB6 BB3: a=b+c BB6: y=b+cHere,
b+c
is postponed at the beginning of BB3 and on the edge BB5->BB6.
latest[b] = (earliest[b] \union postponed.in[b]) \intersection (EUse \union ExprsForWhichSomeSuccessorIsNotPostponedOrEarliest)
BB1->BB2 BB2->BB3 BB1: x=a+bNo need to generate temporaries in this case. But our algorithm will. Do a liveness analysis to see if the expression is used later (without an intervening
latest
as a latest
indicates
recomputation).
x+y \in (latest[b] \intersect used.out[b])
:
b
: add new t=x+y
x+y
by t
only if:
x+y \in (EUse \intersect \not(latest[b] \insersect \not(used.out[b])))
latest[b]
and not in used.out[b]
, this use of the expression does not need to be (and has not been) replaced by t
, so let it be as it is.