aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/poset.go
diff options
context:
space:
mode:
authorGiovanni Bajo <rasky@develer.com>2019-09-27 23:39:42 +0200
committerGiovanni Bajo <rasky@develer.com>2019-10-26 07:16:46 +0000
commit18d57bc89235ea04b6db1ef3e2d4a3106f0b739e (patch)
treeb32fcaab0a9531b84260efb6c472af6b6be0aa99 /src/cmd/compile/internal/ssa/poset.go
parent7e68f81dd8759ce7cc8a1ff596503f66d6a0eeae (diff)
downloadgo-18d57bc89235ea04b6db1ef3e2d4a3106f0b739e.tar.gz
go-18d57bc89235ea04b6db1ef3e2d4a3106f0b739e.zip
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/+/200860 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Giovanni Bajo <rasky@develer.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/ssa/poset.go')
-rw-r--r--src/cmd/compile/internal/ssa/poset.go84
1 files changed, 51 insertions, 33 deletions
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index 021771a7e7..329471ac38 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) {
po.upushalias(n2.ID, 0)
}
-// aliasnode records that n2 (already in the poset) is an alias of n1
-func (po *poset) aliasnode(n1, n2 *Value) {
+// aliasnodes records that all the nodes i2s are aliases of a single master node n1.
+// 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]
if i1 == 0 {
panic("aliasnode for non-existing node")
}
-
- i2 := po.values[n2.ID]
- if i2 == 0 {
- panic("aliasnode for non-existing node")
+ if i2s.Test(i1) {
+ panic("aliasnode i2s contains n1 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 {
- if uint32(idx) != i1 {
- l, r := n.l, n.r
- if l.Target() == i2 {
- po.setchl(uint32(idx), newedge(i1, l.Strict()))
- po.upush(undoSetChl, uint32(idx), l)
+ // Do not touch i1 itself, otherwise we can create useless self-loops
+ if uint32(idx) == i1 {
+ continue
+ }
+ l, r := n.l, n.r
+
+ // Rename all references to i2s into i1
+ if i2s.Test(l.Target()) {
+ po.setchl(uint32(idx), newedge(i1, l.Strict()))
+ po.upush(undoSetChl, uint32(idx), l)
+ }
+ if i2s.Test(r.Target()) {
+ po.setchr(uint32(idx), newedge(i1, r.Strict()))
+ 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.Target() == i2 {
- po.setchr(uint32(idx), newedge(i1, r.Strict()))
- po.upush(undoSetChr, uint32(idx), r)
+ 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.
// This includes n2.ID.
for k, v := range po.values {
- if v == i2 {
+ if i2s.Test(v) {
po.values[k] = i1
- po.upushalias(k, i2)
+ po.upushalias(k, v)
}
}
- if n2.isGenericIntConst() {
- val := n2.AuxInt
- if po.flags&posetFlagUnsigned != 0 {
- val = int64(n2.AuxUnsigned())
- }
- if po.constants[val] != i2 {
- panic("aliasing constant which is not registered")
+ // If one of the aliased nodes is a constant, then make sure
+ // po.constants is updated to point to the master node.
+ for val, idx := range po.constants {
+ if i2s.Test(idx) {
+ po.constants[val] = i1
+ po.upushconst(i1, idx)
}
- po.constants[val] = i1
- po.upushconst(i1, i2)
}
}
@@ -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
l, r := po.children(i1)
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)
return true
}
@@ -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
// to n2 to become references to n1
- po.aliasnode(n1, n2)
-
- // Connect i2 (now dummy) as child of i1. This allows to keep the correct
- // order with its children.
- po.addchild(i1, i2, false)
+ i2s := newBitset(int(po.lastidx) + 1)
+ i2s.Set(i2)
+ po.aliasnodes(n1, i2s)
}
return true
}