Skip to content

Commit 18d57bc

Browse files
committed
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 <[email protected]> Run-TryBot: Giovanni Bajo <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 7e68f81 commit 18d57bc

File tree

1 file changed

+51
-33
lines changed

1 file changed

+51
-33
lines changed

src/cmd/compile/internal/ssa/poset.go

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) {
419419
po.upushalias(n2.ID, 0)
420420
}
421421

422-
// aliasnode records that n2 (already in the poset) is an alias of n1
423-
func (po *poset) aliasnode(n1, n2 *Value) {
422+
// aliasnodes records that all the nodes i2s are aliases of a single master node n1.
423+
// aliasnodes takes care of rearranging the DAG, changing references of parent/children
424+
// of nodes in i2s, so that they point to n1 instead.
425+
// Complexity is O(n) (with n being the total number of nodes in the poset, not just
426+
// the number of nodes being aliased).
427+
func (po *poset) aliasnodes(n1 *Value, i2s bitset) {
424428
i1 := po.values[n1.ID]
425429
if i1 == 0 {
426430
panic("aliasnode for non-existing node")
427431
}
428-
429-
i2 := po.values[n2.ID]
430-
if i2 == 0 {
431-
panic("aliasnode for non-existing node")
432+
if i2s.Test(i1) {
433+
panic("aliasnode i2s contains n1 node")
432434
}
433-
// Rename all references to i2 into i1
434-
// (do not touch i1 itself, otherwise we can create useless self-loops)
435+
436+
// Go through all the nodes to adjust parent/chidlren of nodes in i2s
435437
for idx, n := range po.nodes {
436-
if uint32(idx) != i1 {
437-
l, r := n.l, n.r
438-
if l.Target() == i2 {
439-
po.setchl(uint32(idx), newedge(i1, l.Strict()))
440-
po.upush(undoSetChl, uint32(idx), l)
438+
// Do not touch i1 itself, otherwise we can create useless self-loops
439+
if uint32(idx) == i1 {
440+
continue
441+
}
442+
l, r := n.l, n.r
443+
444+
// Rename all references to i2s into i1
445+
if i2s.Test(l.Target()) {
446+
po.setchl(uint32(idx), newedge(i1, l.Strict()))
447+
po.upush(undoSetChl, uint32(idx), l)
448+
}
449+
if i2s.Test(r.Target()) {
450+
po.setchr(uint32(idx), newedge(i1, r.Strict()))
451+
po.upush(undoSetChr, uint32(idx), r)
452+
}
453+
454+
// Connect all chidren of i2s to i1 (unless those children
455+
// are in i2s as well, in which case it would be useless)
456+
if i2s.Test(uint32(idx)) {
457+
if l != 0 && !i2s.Test(l.Target()) {
458+
po.addchild(i1, l.Target(), l.Strict())
441459
}
442-
if r.Target() == i2 {
443-
po.setchr(uint32(idx), newedge(i1, r.Strict()))
444-
po.upush(undoSetChr, uint32(idx), r)
460+
if r != 0 && !i2s.Test(r.Target()) {
461+
po.addchild(i1, r.Target(), r.Strict())
445462
}
463+
po.setchl(uint32(idx), 0)
464+
po.setchr(uint32(idx), 0)
465+
po.upush(undoSetChl, uint32(idx), l)
466+
po.upush(undoSetChr, uint32(idx), r)
446467
}
447468
}
448469

449470
// Reassign all existing IDs that point to i2 to i1.
450471
// This includes n2.ID.
451472
for k, v := range po.values {
452-
if v == i2 {
473+
if i2s.Test(v) {
453474
po.values[k] = i1
454-
po.upushalias(k, i2)
475+
po.upushalias(k, v)
455476
}
456477
}
457478

458-
if n2.isGenericIntConst() {
459-
val := n2.AuxInt
460-
if po.flags&posetFlagUnsigned != 0 {
461-
val = int64(n2.AuxUnsigned())
462-
}
463-
if po.constants[val] != i2 {
464-
panic("aliasing constant which is not registered")
479+
// If one of the aliased nodes is a constant, then make sure
480+
// po.constants is updated to point to the master node.
481+
for val, idx := range po.constants {
482+
if i2s.Test(idx) {
483+
po.constants[val] = i1
484+
po.upushconst(i1, idx)
465485
}
466-
po.constants[val] = i1
467-
po.upushconst(i1, i2)
468486
}
469487
}
470488

@@ -623,7 +641,9 @@ func (po *poset) collapsepath(n1, n2 *Value) bool {
623641
// TODO: for now, only handle the simple case of i2 being child of i1
624642
l, r := po.children(i1)
625643
if l.Target() == i2 || r.Target() == i2 {
626-
po.aliasnode(n1, n2)
644+
i2s := newBitset(int(po.lastidx) + 1)
645+
i2s.Set(i2)
646+
po.aliasnodes(n1, i2s)
627647
po.addchild(i1, i2, false)
628648
return true
629649
}
@@ -1135,11 +1155,9 @@ func (po *poset) SetEqual(n1, n2 *Value) bool {
11351155

11361156
// Set n2 as alias of n1. This will also update all the references
11371157
// to n2 to become references to n1
1138-
po.aliasnode(n1, n2)
1139-
1140-
// Connect i2 (now dummy) as child of i1. This allows to keep the correct
1141-
// order with its children.
1142-
po.addchild(i1, i2, false)
1158+
i2s := newBitset(int(po.lastidx) + 1)
1159+
i2s.Set(i2)
1160+
po.aliasnodes(n1, i2s)
11431161
}
11441162
return true
11451163
}

0 commit comments

Comments
 (0)