]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: sort partitions by dom to speed up cse
authorTodd Neal <todd@tneal.org>
Wed, 13 Apr 2016 12:51:46 +0000 (08:51 -0400)
committerTodd Neal <todd@tneal.org>
Wed, 13 Apr 2016 19:55:15 +0000 (19:55 +0000)
We do two O(n) scans of all values in an eqclass when computing
substitutions for CSE.

In unfortunate cases, like those found in #15112, we can have a large
eqclass composed of values found in blocks none of whom dominate the
other.  This leads to O(n^2) behavior. The elements are removed one at a
time, with O(n) scans each time.

This CL removes the linear scan by sorting the eqclass so that dominant
values will be sorted first.  As long as we also ensure we don't disturb
the sort order, then we no longer need to scan for the maximally
dominant value.

For the code in issue #15112:

Before:
real    1m26.094s
user    1m30.776s
sys     0m1.125s

Aefter:
real    0m52.099s
user    0m56.829s
sys     0m1.092s

Updates #15112

Change-Id: Ic4f8680ed172e716232436d31963209c146ef850
Reviewed-on: https://go-review.googlesource.com/21981
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Todd Neal <todd@tneal.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/ssa/cse.go
src/cmd/compile/internal/ssa/sparsetree.go

index c12d51e50c5300ac0a143c91781bdb713a9234b3..76db9d54677b686731e3edf0157b5514ac32f08b 100644 (file)
@@ -137,23 +137,20 @@ func cse(f *Func) {
        // if v and w are in the same equivalence class and v dominates w.
        rewrite := make([]*Value, f.NumValues())
        for _, e := range partition {
+               sort.Sort(sortbyentry{e, f.sdom})
                for len(e) > 1 {
-                       // Find a maximal dominant element in e
+                       // e is sorted by entry value so maximal dominant element should be
+                       // found first in the slice
                        v := e[0]
-                       for _, w := range e[1:] {
-                               if f.sdom.isAncestorEq(w.Block, v.Block) {
-                                       v = w
-                               }
-                       }
-
+                       e = e[1:]
                        // Replace all elements of e which v dominates
                        for i := 0; i < len(e); {
                                w := e[i]
-                               if w == v {
-                                       e, e[i] = e[:len(e)-1], e[len(e)-1]
-                               } else if f.sdom.isAncestorEq(v.Block, w.Block) {
+                               if f.sdom.isAncestorEq(v.Block, w.Block) {
                                        rewrite[w.ID] = v
-                                       e, e[i] = e[:len(e)-1], e[len(e)-1]
+                                       // retain the sort order
+                                       copy(e[i:], e[i+1:])
+                                       e = e[:len(e)-1]
                                } else {
                                        i++
                                }
@@ -308,3 +305,16 @@ func (sv sortvalues) Less(i, j int) bool {
        // Sort by value ID last to keep the sort result deterministic.
        return v.ID < w.ID
 }
+
+type sortbyentry struct {
+       a    []*Value // array of values
+       sdom sparseTree
+}
+
+func (sv sortbyentry) Len() int      { return len(sv.a) }
+func (sv sortbyentry) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv sortbyentry) Less(i, j int) bool {
+       v := sv.a[i]
+       w := sv.a[j]
+       return sv.sdom.maxdomorder(v.Block) < sv.sdom.maxdomorder(w.Block)
+}
index cae91e7ddbf4cb3cc593261befe58dd9e0fe9f8a..45c78974963cdf5060b2ca39951fee5e8322873e 100644 (file)
@@ -116,6 +116,9 @@ func (t sparseTree) Child(x *Block) *Block {
 
 // isAncestorEq reports whether x is an ancestor of or equal to y.
 func (t sparseTree) isAncestorEq(x, y *Block) bool {
+       if x == y {
+               return true
+       }
        xx := &t[x.ID]
        yy := &t[y.ID]
        return xx.entry <= yy.entry && yy.exit <= xx.exit
@@ -123,7 +126,16 @@ func (t sparseTree) isAncestorEq(x, y *Block) bool {
 
 // isAncestor reports whether x is a strict ancestor of y.
 func (t sparseTree) isAncestor(x, y *Block) bool {
+       if x == y {
+               return false
+       }
        xx := &t[x.ID]
        yy := &t[y.ID]
        return xx.entry < yy.entry && yy.exit < xx.exit
 }
+
+// maxdomorder returns a value to allow a maximal dominator first sort.  maxdomorder(x) < maxdomorder(y) is true
+// if x may dominate y, and false if x cannot dominate y.
+func (t sparseTree) maxdomorder(x *Block) int32 {
+       return t[x.ID].entry
+}