lastMems := findLastMems(f)
idom := f.Idom()
- sdom := f.sdom()
+ po := f.postorder()
+ // The ordering in the dominator tree matters; it's important that
+ // the walk of the dominator tree also be a preorder (i.e., a node is
+ // visited only after all its non-backedge predecessors have been visited).
+ sdom := newSparseOrderedTree(f, idom, po)
- if f.pass.debug > 2 {
+ if f.pass.debug > 1 {
fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
}
memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
// Propagate last mem definitions forward through successor blocks.
- po := f.postorder()
for i := len(po) - 1; i >= 0; i-- {
b := po[i]
mem := lastMems[b.ID]
mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
}
memDefsAtBlockEnds[b.ID] = mem
+ if f.pass.debug > 2 {
+ fmt.Printf("memDefsAtBlockEnds[%s] = %s\n", b, mem)
+ }
}
// Maps from block to newly-inserted phi function in block.
mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
headerMemPhi = newPhiFor(h, mem0)
newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
- addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis)
+ addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis, sdom)
}
tofixBackedges[i].m = headerMemPhi
}
+ if f.pass.debug > 0 {
+ for b, r := range newmemphis {
+ fmt.Printf("before b=%s, rewrite=%s\n", b, r.String())
+ }
+ }
+
+ // dfPhiTargets notes inputs to phis in dominance frontiers that should not
+ // be rewritten as part of the dominated children of some outer rewrite.
+ dfPhiTargets := make(map[rewriteTarget]bool)
- rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis)
+ rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis, dfPhiTargets, sdom)
if f.pass.debug > 0 {
for b, r := range newmemphis {
- fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
+ fmt.Printf("after b=%s, rewrite=%s\n", b, r.String())
}
}
f.invalidateCFG()
- if f.pass.debug > 2 {
+ if f.pass.debug > 1 {
sdom = newSparseTree(f, f.Idom())
fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
}
// if b has its own phi definition then it takes the place of h.
// defsForUses provides information about other definitions of the variable that are present
// (and if nil, indicates that the variable is no longer live)
-func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite) {
+// sdom must yield a preorder of the flow graph if recursively walked, root-to-children.
+// The result of newSparseOrderedTree with order supplied by a dfs-postorder satisfies this
+// requirement.
+func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite, dfPhiTargets map[rewriteTarget]bool, sdom SparseTree) {
// If b is a block with a new phi, then a new rewrite applies below it in the dominator tree.
if _, ok := newphis[b]; ok {
h = b
if w != x {
continue
}
- *p = append(*p, rewriteTarget{v, i})
+ tgt := rewriteTarget{v, i}
+
+ // It's possible dominated control flow will rewrite this instead.
+ // Visiting in preorder (a property of how sdom was constructed)
+ // ensures that these are seen in the proper order.
+ if dfPhiTargets[tgt] {
+ continue
+ }
+ *p = append(*p, tgt)
+ if f.pass.debug > 1 {
+ fmt.Printf("added block target for h=%v, b=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
+ h, b, x, y, v, i)
+ }
}
}
if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
for _, e := range b.Succs {
s := e.b
- if sphi, ok := newphis[s]; ok { // saves time to find the phi this way.
- *p = append(*p, rewriteTarget{sphi.after, e.i})
- continue
- }
+
for _, v := range s.Values {
if v.Op == OpPhi && v.Args[e.i] == x {
- *p = append(*p, rewriteTarget{v, e.i})
+ tgt := rewriteTarget{v, e.i}
+ *p = append(*p, tgt)
+ dfPhiTargets[tgt] = true
+ if f.pass.debug > 1 {
+ fmt.Printf("added phi target for h=%v, b=%v, s=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
+ h, b, s, x, y, v.LongString(), e.i)
+ }
break
}
}
newphis[h] = change
}
- sdom := f.sdom()
-
for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
- rewriteNewPhis(h, c, f, defsForUses, newphis) // TODO: convert to explicit stack from recursion.
+ rewriteNewPhis(h, c, f, defsForUses, newphis, dfPhiTargets, sdom) // TODO: convert to explicit stack from recursion.
}
}
// either b = h or h strictly dominates b.
// These newly created phis are themselves new definitions that may require addition of their
// own trivial phi functions in their own dominance frontier, and this is handled recursively.
-func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite) {
+func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite, sdom SparseTree) {
oldv := defForUses[b.ID]
if oldv != x { // either a new definition replacing x, or nil if it is proven that there are no uses reachable from b
return
}
- sdom := f.sdom()
idom := f.Idom()
outer:
for _, e := range b.Succs {
headerPhi := newPhiFor(s, old)
// the new phi will replace "old" in block s and all blocks dominated by s.
newphis[s] = rewrite{before: old, after: headerPhi} // record new phi, to have inputs labeled "old" rewritten to "headerPhi"
- addDFphis(old, s, s, f, defForUses, newphis) // the new definition may also create new phi functions.
+ addDFphis(old, s, s, f, defForUses, newphis, sdom) // the new definition may also create new phi functions.
}
for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
- addDFphis(x, h, c, f, defForUses, newphis) // TODO: convert to explicit stack from recursion.
+ addDFphis(x, h, c, f, defForUses, newphis, sdom) // TODO: convert to explicit stack from recursion.
}
}