mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: in poset, implement path collapsing
Sometimes, poset needs to collapse a path making all nodes in the path aliases. For instance, we know that A<=N1<=B and we learn that B<=A, we can deduce A==N1==B, and thus we can collapse all paths from A to B into a single aliased node. Currently, this is a TODO. This CL implements the path-collapsing primitive by doing a DFS walk to build a bitset of all nodes across all paths, and then calling the new aliasnodes that allow to mark multiple nodes as aliases of a single master node. This helps only 4 times in std+cmd, but it will be fundamental when we will rely on poset to calculate numerical limits, to calculate the correct values. This also fixes #35157, a bug uncovered by a previous CL in this serie. A testcase will be added soon. Change-Id: I5fc54259711769d7bd7c2d166a5abc1cddc26350 Reviewed-on: https://go-review.googlesource.com/c/go/+/200861 Run-TryBot: Giovanni Bajo <rasky@develer.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
18d57bc892
commit
c70e5475e6
2 changed files with 161 additions and 12 deletions
|
|
@ -629,27 +629,56 @@ func (po *poset) mergeroot(r1, r2 uint32) uint32 {
|
|||
return r
|
||||
}
|
||||
|
||||
// collapsepath marks i1 and i2 as equal and collapses as equal all
|
||||
// nodes across all paths between i1 and i2. If a strict edge is
|
||||
// collapsepath marks n1 and n2 as equal and collapses as equal all
|
||||
// nodes across all paths between n1 and n2. If a strict edge is
|
||||
// found, the function does not modify the DAG and returns false.
|
||||
// Complexity is O(n).
|
||||
func (po *poset) collapsepath(n1, n2 *Value) bool {
|
||||
i1, i2 := po.values[n1.ID], po.values[n2.ID]
|
||||
if po.reaches(i1, i2, true) {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: for now, only handle the simple case of i2 being child of i1
|
||||
l, r := po.children(i1)
|
||||
if l.Target() == i2 || r.Target() == i2 {
|
||||
i2s := newBitset(int(po.lastidx) + 1)
|
||||
i2s.Set(i2)
|
||||
po.aliasnodes(n1, i2s)
|
||||
po.addchild(i1, i2, false)
|
||||
return true
|
||||
}
|
||||
// Find all the paths from i1 to i2
|
||||
paths := po.findpaths(i1, i2)
|
||||
// Mark all nodes in all the paths as aliases of n1
|
||||
// (excluding n1 itself)
|
||||
paths.Clear(i1)
|
||||
po.aliasnodes(n1, paths)
|
||||
return true
|
||||
}
|
||||
|
||||
// findpaths is a recursive function that calculates all paths from cur to dst
|
||||
// and return them as a bitset (the index of a node is set in the bitset if
|
||||
// that node is on at least one path from cur to dst).
|
||||
// We do a DFS from cur (stopping going deep any time we reach dst, if ever),
|
||||
// and mark as part of the paths any node that has a children which is already
|
||||
// part of the path (or is dst itself).
|
||||
func (po *poset) findpaths(cur, dst uint32) bitset {
|
||||
seen := newBitset(int(po.lastidx + 1))
|
||||
path := newBitset(int(po.lastidx + 1))
|
||||
path.Set(dst)
|
||||
po.findpaths1(cur, dst, seen, path)
|
||||
return path
|
||||
}
|
||||
|
||||
func (po *poset) findpaths1(cur, dst uint32, seen bitset, path bitset) {
|
||||
if cur == dst {
|
||||
return
|
||||
}
|
||||
seen.Set(cur)
|
||||
l, r := po.chl(cur), po.chr(cur)
|
||||
if !seen.Test(l) {
|
||||
po.findpaths1(l, dst, seen, path)
|
||||
}
|
||||
if !seen.Test(r) {
|
||||
po.findpaths1(r, dst, seen, path)
|
||||
}
|
||||
if path.Test(l) || path.Test(r) {
|
||||
path.Set(cur)
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether it is recorded that i1!=i2
|
||||
func (po *poset) isnoneq(i1, i2 uint32) bool {
|
||||
if i1 == i2 {
|
||||
|
|
|
|||
|
|
@ -438,7 +438,127 @@ func TestPosetStrict(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestSetEqual(t *testing.T) {
|
||||
func TestPosetCollapse(t *testing.T) {
|
||||
testPosetOps(t, false, []posetTestOp{
|
||||
{Checkpoint, 0, 0},
|
||||
// Create a complex graph of <= relations among nodes between 10 and 25.
|
||||
{SetOrderOrEqual, 10, 15},
|
||||
{SetOrderOrEqual, 15, 20},
|
||||
{SetOrderOrEqual, 20, vconst(20)},
|
||||
{SetOrderOrEqual, vconst(20), 25},
|
||||
{SetOrderOrEqual, 10, 12},
|
||||
{SetOrderOrEqual, 12, 16},
|
||||
{SetOrderOrEqual, 16, vconst(20)},
|
||||
{SetOrderOrEqual, 10, 17},
|
||||
{SetOrderOrEqual, 17, 25},
|
||||
{SetOrderOrEqual, 15, 18},
|
||||
{SetOrderOrEqual, 18, vconst(20)},
|
||||
{SetOrderOrEqual, 15, 19},
|
||||
{SetOrderOrEqual, 19, 25},
|
||||
|
||||
// These are other paths not part of the main collapsing path
|
||||
{SetOrderOrEqual, 10, 11},
|
||||
{SetOrderOrEqual, 11, 26},
|
||||
{SetOrderOrEqual, 13, 25},
|
||||
{SetOrderOrEqual, 100, 25},
|
||||
{SetOrderOrEqual, 101, 15},
|
||||
{SetOrderOrEqual, 102, 10},
|
||||
{SetOrderOrEqual, 25, 103},
|
||||
{SetOrderOrEqual, 20, 104},
|
||||
|
||||
{Checkpoint, 0, 0},
|
||||
// Collapse everything by setting 10 >= 25: this should make everything equal
|
||||
{SetOrderOrEqual, 25, 10},
|
||||
|
||||
// Check that all nodes are pairwise equal now
|
||||
{Equal, 10, 12},
|
||||
{Equal, 10, 15},
|
||||
{Equal, 10, 16},
|
||||
{Equal, 10, 17},
|
||||
{Equal, 10, 18},
|
||||
{Equal, 10, 19},
|
||||
{Equal, 10, vconst(20)},
|
||||
{Equal, 10, vconst2(20)},
|
||||
{Equal, 10, 25},
|
||||
|
||||
{Equal, 12, 15},
|
||||
{Equal, 12, 16},
|
||||
{Equal, 12, 17},
|
||||
{Equal, 12, 18},
|
||||
{Equal, 12, 19},
|
||||
{Equal, 12, vconst(20)},
|
||||
{Equal, 12, vconst2(20)},
|
||||
{Equal, 12, 25},
|
||||
|
||||
{Equal, 15, 16},
|
||||
{Equal, 15, 17},
|
||||
{Equal, 15, 18},
|
||||
{Equal, 15, 19},
|
||||
{Equal, 15, vconst(20)},
|
||||
{Equal, 15, vconst2(20)},
|
||||
{Equal, 15, 25},
|
||||
|
||||
{Equal, 16, 17},
|
||||
{Equal, 16, 18},
|
||||
{Equal, 16, 19},
|
||||
{Equal, 16, vconst(20)},
|
||||
{Equal, 16, vconst2(20)},
|
||||
{Equal, 16, 25},
|
||||
|
||||
{Equal, 17, 18},
|
||||
{Equal, 17, 19},
|
||||
{Equal, 17, vconst(20)},
|
||||
{Equal, 17, vconst2(20)},
|
||||
{Equal, 17, 25},
|
||||
|
||||
{Equal, 18, 19},
|
||||
{Equal, 18, vconst(20)},
|
||||
{Equal, 18, vconst2(20)},
|
||||
{Equal, 18, 25},
|
||||
|
||||
{Equal, 19, vconst(20)},
|
||||
{Equal, 19, vconst2(20)},
|
||||
{Equal, 19, 25},
|
||||
|
||||
{Equal, vconst(20), vconst2(20)},
|
||||
{Equal, vconst(20), 25},
|
||||
|
||||
{Equal, vconst2(20), 25},
|
||||
|
||||
// ... but not 11/26/100/101/102, which were on a different path
|
||||
{Equal_Fail, 10, 11},
|
||||
{Equal_Fail, 10, 26},
|
||||
{Equal_Fail, 10, 100},
|
||||
{Equal_Fail, 10, 101},
|
||||
{Equal_Fail, 10, 102},
|
||||
{OrderedOrEqual, 10, 26},
|
||||
{OrderedOrEqual, 25, 26},
|
||||
{OrderedOrEqual, 13, 25},
|
||||
{OrderedOrEqual, 13, 10},
|
||||
|
||||
{Undo, 0, 0},
|
||||
{OrderedOrEqual, 10, 25},
|
||||
{Equal_Fail, 10, 12},
|
||||
{Equal_Fail, 10, 15},
|
||||
{Equal_Fail, 10, 25},
|
||||
|
||||
{Undo, 0, 0},
|
||||
})
|
||||
|
||||
testPosetOps(t, false, []posetTestOp{
|
||||
{Checkpoint, 0, 0},
|
||||
{SetOrderOrEqual, 10, 15},
|
||||
{SetOrderOrEqual, 15, 20},
|
||||
{SetOrderOrEqual, 20, 25},
|
||||
{SetOrder, 10, 16},
|
||||
{SetOrderOrEqual, 16, 20},
|
||||
// Check that we cannot collapse here because of the strict relation 10<16
|
||||
{SetOrderOrEqual_Fail, 20, 10},
|
||||
{Undo, 0, 0},
|
||||
})
|
||||
}
|
||||
|
||||
func TestPosetSetEqual(t *testing.T) {
|
||||
testPosetOps(t, false, []posetTestOp{
|
||||
// 10<=20<=30<40, 20<=100<110
|
||||
{Checkpoint, 0, 0},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue