diff options
author | Giovanni Bajo <rasky@develer.com> | 2019-09-27 23:39:42 +0200 |
---|---|---|
committer | Giovanni Bajo <rasky@develer.com> | 2019-10-26 07:16:46 +0000 |
commit | 18d57bc89235ea04b6db1ef3e2d4a3106f0b739e (patch) | |
tree | b32fcaab0a9531b84260efb6c472af6b6be0aa99 /src/cmd/compile/internal/ssa/poset.go | |
parent | 7e68f81dd8759ce7cc8a1ff596503f66d6a0eeae (diff) | |
download | go-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.go | 84 |
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 } |