Commit 18d57bc8 authored by Giovanni Bajo's avatar Giovanni Bajo

cmd/compile: in poset, allow multiple aliases in a single pass

Change aliasnode into aliasnodes, to allow for recording
multiple aliases in a single pass. The nodes being aliased
are passed as bitset for performance reason (O(1) lookups).
It does look worse in the existing case of SetEqual where
we now need to allocate a bitset just for a single node,
but the new API will allow to fully implement a path-collapsing
primitive in next CL.

No functional changes, passes toolstash -cmp.

Change-Id: I06259610e8ef478106b36852464ed2caacd29ab5
Reviewed-on: https://go-review.googlesource.com/c/go/+/200860Reviewed-by: default avatarKeith Randall <khr@golang.org>
Run-TryBot: Giovanni Bajo <rasky@develer.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 7e68f81d
...@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) { ...@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) {
po.upushalias(n2.ID, 0) po.upushalias(n2.ID, 0)
} }
// aliasnode records that n2 (already in the poset) is an alias of n1 // aliasnodes records that all the nodes i2s are aliases of a single master node n1.
func (po *poset) aliasnode(n1, n2 *Value) { // aliasnodes takes care of rearranging the DAG, changing references of parent/children
// of nodes in i2s, so that they point to n1 instead.
// Complexity is O(n) (with n being the total number of nodes in the poset, not just
// the number of nodes being aliased).
func (po *poset) aliasnodes(n1 *Value, i2s bitset) {
i1 := po.values[n1.ID] i1 := po.values[n1.ID]
if i1 == 0 { if i1 == 0 {
panic("aliasnode for non-existing node") panic("aliasnode for non-existing node")
} }
if i2s.Test(i1) {
i2 := po.values[n2.ID] panic("aliasnode i2s contains n1 node")
if i2 == 0 {
panic("aliasnode for non-existing node")
} }
// Rename all references to i2 into i1
// (do not touch i1 itself, otherwise we can create useless self-loops) // Go through all the nodes to adjust parent/chidlren of nodes in i2s
for idx, n := range po.nodes { for idx, n := range po.nodes {
if uint32(idx) != i1 { // Do not touch i1 itself, otherwise we can create useless self-loops
if uint32(idx) == i1 {
continue
}
l, r := n.l, n.r l, r := n.l, n.r
if l.Target() == i2 {
// Rename all references to i2s into i1
if i2s.Test(l.Target()) {
po.setchl(uint32(idx), newedge(i1, l.Strict())) po.setchl(uint32(idx), newedge(i1, l.Strict()))
po.upush(undoSetChl, uint32(idx), l) po.upush(undoSetChl, uint32(idx), l)
} }
if r.Target() == i2 { if i2s.Test(r.Target()) {
po.setchr(uint32(idx), newedge(i1, r.Strict())) po.setchr(uint32(idx), newedge(i1, r.Strict()))
po.upush(undoSetChr, uint32(idx), r) po.upush(undoSetChr, uint32(idx), r)
} }
// Connect all chidren of i2s to i1 (unless those children
// are in i2s as well, in which case it would be useless)
if i2s.Test(uint32(idx)) {
if l != 0 && !i2s.Test(l.Target()) {
po.addchild(i1, l.Target(), l.Strict())
}
if r != 0 && !i2s.Test(r.Target()) {
po.addchild(i1, r.Target(), r.Strict())
}
po.setchl(uint32(idx), 0)
po.setchr(uint32(idx), 0)
po.upush(undoSetChl, uint32(idx), l)
po.upush(undoSetChr, uint32(idx), r)
} }
} }
// Reassign all existing IDs that point to i2 to i1. // Reassign all existing IDs that point to i2 to i1.
// This includes n2.ID. // This includes n2.ID.
for k, v := range po.values { for k, v := range po.values {
if v == i2 { if i2s.Test(v) {
po.values[k] = i1 po.values[k] = i1
po.upushalias(k, i2) po.upushalias(k, v)
} }
} }
if n2.isGenericIntConst() { // If one of the aliased nodes is a constant, then make sure
val := n2.AuxInt // po.constants is updated to point to the master node.
if po.flags&posetFlagUnsigned != 0 { for val, idx := range po.constants {
val = int64(n2.AuxUnsigned()) if i2s.Test(idx) {
}
if po.constants[val] != i2 {
panic("aliasing constant which is not registered")
}
po.constants[val] = i1 po.constants[val] = i1
po.upushconst(i1, i2) po.upushconst(i1, idx)
}
} }
} }
...@@ -623,7 +641,9 @@ func (po *poset) collapsepath(n1, n2 *Value) bool { ...@@ -623,7 +641,9 @@ func (po *poset) collapsepath(n1, n2 *Value) bool {
// TODO: for now, only handle the simple case of i2 being child of i1 // TODO: for now, only handle the simple case of i2 being child of i1
l, r := po.children(i1) l, r := po.children(i1)
if l.Target() == i2 || r.Target() == i2 { if l.Target() == i2 || r.Target() == i2 {
po.aliasnode(n1, n2) i2s := newBitset(int(po.lastidx) + 1)
i2s.Set(i2)
po.aliasnodes(n1, i2s)
po.addchild(i1, i2, false) po.addchild(i1, i2, false)
return true return true
} }
...@@ -1135,11 +1155,9 @@ func (po *poset) SetEqual(n1, n2 *Value) bool { ...@@ -1135,11 +1155,9 @@ func (po *poset) SetEqual(n1, n2 *Value) bool {
// Set n2 as alias of n1. This will also update all the references // Set n2 as alias of n1. This will also update all the references
// to n2 to become references to n1 // to n2 to become references to n1
po.aliasnode(n1, n2) i2s := newBitset(int(po.lastidx) + 1)
i2s.Set(i2)
// Connect i2 (now dummy) as child of i1. This allows to keep the correct po.aliasnodes(n1, i2s)
// order with its children.
po.addchild(i1, i2, false)
} }
return true return true
} }
......
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