240 likes | 369 Views
Value Numbering. Compiler Baojian Hua bjhua@ustc.edu.cn. Motivation. a = x + y b = x + y x = m + n c = x + y d = x + y e = x f = y g = e + f. a = x + y b = x + y x = m + n c = x + y d = x + y e = x f = y g = e + f. a. x has been re-assigned!. c. c. Motivation. 2. 0.
E N D
Value Numbering Compiler Baojian Hua bjhua@ustc.edu.cn
Motivation a = x + y b = x + y x = m + n c = x + y d = x + y e = x f = y g = e + f a = x + y b = x + y x = m + n c = x + y d = x + y e = x f = y g = e + f a x has been re-assigned! c c
Motivation 2 0 1 a = x + y b = x + y x = m + n c = x + y d = x + y e = x f = y g = e + f 2 0 1 0 x 1 y 5 3 4 2 x+y 2 a 6 5 1 2 b 3 6 5 1 m 4 n 5 5 5 m+n 5 x 1 1 What’s a good data structure for this? 6 5 1
Value Numbering (VN) Algorithm • The algorithm is in Tiger 17.4 • This is a deep semantic property of expressions • In deciding whether “x+y” has been calculated and thus can be avoided, one can NOT just search the expression (by syntax), but some semantic property (here, the value number of “x+y”) • x+y == a+b <==> V(x)=V(a) /\ V(y)=V(b) • A form of abstract interpretation
VN vs CSE • The goals of both of the two algorithms is to perform redundancy elimination • how to detect redundancy: • VN: value number • CSE: available expression analysis • The key difference is the viewpoint to define “redundancy” • VN: semantics • CSE: syntax
VN vs CSE x = a+b VN: Yes! CSE: No! t = a s = b y = t+s But research has revealed that each of them come with pros and cons. So most compilers contain both of them. z = a+b h = a+b Is this a redundancy computation? VN CSE
What about control flow? • VN can be extended to extended basic block (EBB) easily (recall that EBBs form a local tree): • Do a preorder walk of the EBB tree; • Maintain a scoped table along the way (just as we did with the scoped declarations of variables when we discuss elaboration) a = x + y b = x + y x = 2 a = 3 a? d = x + y a? b? Available expression + Reaching expression
Example 0 x 1 y 2 x+y 2 a = x + y a 2 b b = x + y x = 2 a = 3 a d = x + y
Example 0 x 1 y 2 x+y 2 a = x + y a 3 x 4 a b = x + y x = 2 a = 3 d = x + y
GVN: Global Value Numbering • It’s hard to do global value numbering for general CFG • But for SSA, there are good algorithms: • 1988: partition-based algorithm • Alpern ‘88 • 1997: dominator-based algorithm • Kooper ‘97 • 2004: GVN-PRE • implemented in GCC
Partition-based GVN L1: a = x + y L2: L3: x = x + y x = x + y L4: d = x + y
Partition-based GVN L1: • Key observations: • Variables defined with different operators can not be equal (arity), thus we group them in different congruent classes; • for variables with same definition operator, they are equal iff the corresponding operands are from the same congruent classes. a = x + y L2: L3: x1 = x + y x2 = x + y L4: x3=ϕ(x1, x2) d = x3 + y
Partition-based GVN L1: Initial partitions: {a, x1, x2, d} {x3} {x} {y} this partition is based on the expression operators. a = x + y L2: L3: x1 = x + y x2 = x + y a = x+y x1 = x+y x2 = x+y d = x3+y x3 = ϕ(x1, x2) x = ? y = ? L4: x3=ϕ(x1, x2) d = x3 + y In the same set <==> take good chance of equality.
Partition-based GVN L1: {a, x1, x2, d} {x3} {x} {y} a = x + y Now, consider {x}: There are 3 uses of x, but not x3! L2: L3: x1 = x + y x2 = x + y a = x+y x1 = x+y x2 = x+y d = x3+y x3 = ϕ(x1, x2) x = ? y = ? L4: x3=ϕ(x1, x2) d = x3 + y
Partition-based GVN L1: {a, x1, x2, d} {x3} {x} {y} a = x + y Final partitions: {a, x1, x2} {d} {x3} {x} {y} L2: L3: x1 = x + y x2 = x + y a = x+y x1 = x+y x2 = x+y d = x3+y x3 = ϕ(x1, x2) x = ? y = ? L4: x3=ϕ(x1, x2) d = x3 + y a a a As “a” dominates both x1 and x2, so all uses of x1 and x2 can be replaced by “a”.
Partition-based GVN Algorithm partition() P = all initial partitions (a queue of sets) while (!empty(P)) S = deQueue(P) // suppose S is an array n = arity(S[0]) // example: + ==> n == 2 for (i=0 to n-1) use_v[i] = S[0][i]; // calculate use sets T = {S[0]} foreach (x \in s[1]…s[k-1]) // k=|s| for (i=0 to n-1) if (use[x_i]!=use_v[i]) break; T \/= {x} if (T!=S) enQueue (T); enQueue (S-T);
Example L1: i = 1 j = 1 L1: i1 = 1 j1 = 1 L2: L2: i3 = ϕ(i1, i2) j3 = ϕ (j1, j2) L4: L4: L3: L3: i = i+1 j = j+1 i = i+3 j = j+3 i4 = i3+1 j4 = j3+1 i5 = i3+3 j5 = j3+3 L5: L5: i2 = ϕ(i4, i5) j2 = ϕ (j4, j5) CFG SSA
Example L1: i1 = 1 j1 = 1 {i1, j1} {i3, j3} {i4, j4, i5, j5} {i2, j2} // Be partitioned into: {i1, j1} {i3, j3} {i4, j4} {i5, j5} {i2, j2} L2: i3 = ϕ(i1, i2) j3 = ϕ (j1, j2) L4: L3: i4 = i3+1 j4 = j3+1 i5 = i3+3 j5 = j3+3 L5: i2 = ϕ(i4, i5) j2 = ϕ (j4, j5) SSA
Example L1: i = 1 j = 1 L1: i1 = 1 j1 = 1 L2: L2: i3 = ϕ(i1, i2) j3 = ϕ (j1, j2) L4: L4: L3: L3: i = i+1 j = j+1 i = i+3 j = j+3 i4 = i3+1 j4 = j3+1 i5 = i3+3 j5 = j3+3 L5: L5: i2 = ϕ(i4, i5) j2 = ϕ (j4, j5) CFG SSA
Dominator-based GVN • VN can be extended to GVN • on dominator trees: • Do a (what order?) walk of the dominator tree; • Maintain a scoped table along the way (just as we did with the scope declarations of variables) • for each block B, do VN as before, for a successor S of B, modify the ϕarguments L1: 2 0 1 a = x + y L2: L3: x1 = x + y x2 = x + y 2 2 0 1 0 1 L4: 2 2 L1 2 x3=ϕ(x1, x2) d = x3 + y 3 2 1 L2 L4 L3
Another Example • VN can be extended to GVN • on dominator trees: • Do a (what order?) walk of the dominator tree; • Maintain a scoped table along the way (just as we did with the scope declarations of variables) • for each block B, do VN as before, for a successor S of B, modify the ϕarguments. L1: 2 0 1 a = x + y L2: L3: b = x + y x1 = 2 a1 = 3 3 3 2 0 1 4 4 L4: L1 5 3 0 x2=ϕ(x, x1) d = x2 + y 6 5 1 L2 L4 L3