Commit 3ea7cfab authored by Todd Neal's avatar Todd Neal

cmd/compile: sort partitions by dom to speed up cse

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/21981Reviewed-by: 's avatarJosh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Todd Neal <todd@tneal.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 4721ea6a
......@@ -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)
}
......@@ -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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment