func prove(f *Func) {
idom := dominators(f)
sdom := newSparseTree(f, idom)
- domTree := make([][]*Block, f.NumBlocks())
-
- // Create a block ID -> [dominees] mapping
- for _, b := range f.Blocks {
- if dom := idom[b.ID]; dom != nil {
- domTree[dom.ID] = append(domTree[dom.ID], b)
- }
- }
// current node state
type walkState int
saved: saved,
})
- for _, s := range domTree[node.block.ID] {
+ for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
work = append(work, bp{
block: s,
state: descend,
package ssa
type sparseTreeNode struct {
- block *Block
child *Block
sibling *Block
parent *Block
t := make(sparseTree, f.NumBlocks())
for _, b := range f.Blocks {
n := &t[b.ID]
- n.block = b
if p := parentOf[b.ID]; p != nil {
n.parent = p
n.sibling = t[p.ID].child
return n + 2
}
+// Sibling returns a sibling of x in the dominator tree (i.e.,
+// a node with the same immediate dominator) or nil if there
+// are no remaining siblings in the arbitrary but repeatable
+// order chosen. Because the Child-Sibling order is used
+// to assign entry and exit numbers in the treewalk, those
+// numbers are also consistent with this order (i.e.,
+// Sibling(x) has entry number larger than x's exit number).
+func (t sparseTree) Sibling(x *Block) *Block {
+ return t[x.ID].sibling
+}
+
+// Child returns a child of x in the dominator tree, or
+// nil if there are none. The choice of first child is
+// arbitrary but repeatable.
+func (t sparseTree) Child(x *Block) *Block {
+ return t[x.ID].child
+}
+
// isAncestorEq reports whether x is an ancestor of or equal to y.
func (t sparseTree) isAncestorEq(x, y *Block) bool {
xx := &t[x.ID]