]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/ssa: use reverse postorder traversal
authorHeschi Kreinick <heschi@google.com>
Thu, 19 Oct 2017 22:59:41 +0000 (18:59 -0400)
committerHeschi Kreinick <heschi@google.com>
Tue, 24 Oct 2017 20:22:05 +0000 (20:22 +0000)
Instead of the hand-written control flow analysis in debug info
generation, use a reverse postorder traversal, which is basically the
same thing. It should be slightly faster.

More importantly, the previous version simply gave up in the case of
non-reducible functions, and produced output that caused a later stage
to crash. It turns out that there's a non-reducible function in
compress/flate, so that wasn't a theoretical issue.

With this change, all blocks will be visited, even for non-reducible
functions.

Change-Id: Id47536764ee93203c6b4105a1a3013fe3265aa12
Reviewed-on: https://go-review.googlesource.com/73110
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/fmt_test.go
src/cmd/compile/internal/ssa/debug.go

index e4707fb310d48e9894591c5d8db94c41ee370531..cc0ff0cee7229b198fba1d8c81861b5bfd0351e1 100644 (file)
@@ -606,7 +606,6 @@ var knownFormats = map[string]string{
        "[16]byte %x":                                     "",
        "[]*cmd/compile/internal/gc.Node %v":              "",
        "[]*cmd/compile/internal/gc.Sig %#v":              "",
-       "[]*cmd/compile/internal/ssa.Block %+v":           "",
        "[]*cmd/compile/internal/ssa.Value %v":            "",
        "[][]cmd/compile/internal/ssa.SlotID %v":          "",
        "[]byte %s":                                       "",
index cf59e76d7607ac12fab56353675504ead283dc25..60c914d778dd1d819045d5daefd9338d75a84d04 100644 (file)
@@ -274,30 +274,14 @@ func BuildFuncDebug(f *Func, loggingEnabled bool) *FuncDebug {
        // Build up block states, starting with the first block, then
        // processing blocks once their predecessors have been processed.
 
-       // TODO: use a reverse post-order traversal instead of the work queue.
-
        // Location list entries for each block.
        blockLocs := make([]*BlockDebug, f.NumBlocks())
 
-       // Work queue of blocks to visit. Some of them may already be processed.
-       work := []*Block{f.Entry}
-
-       for len(work) > 0 {
-               b := work[0]
-               work = work[1:]
-               if blockLocs[b.ID] != nil {
-                       continue // already processed
-               }
-               if !state.predecessorsDone(b, blockLocs) {
-                       continue // not ready yet
-               }
-
-               for _, edge := range b.Succs {
-                       if blockLocs[edge.Block().ID] != nil {
-                               continue
-                       }
-                       work = append(work, edge.Block())
-               }
+       // Reverse postorder: visit a block after as many as possible of its
+       // predecessors have been visited.
+       po := f.Postorder()
+       for i := len(po) - 1; i >= 0; i-- {
+               b := po[i]
 
                // Build the starting state for the block from the final
                // state of its predecessors.
@@ -351,7 +335,7 @@ func BuildFuncDebug(f *Func, loggingEnabled bool) *FuncDebug {
                        last.End = BlockEnd
                }
                if state.loggingEnabled {
-                       f.Logf("Block done: locs %v, regs %v. work = %+v\n", state.BlockString(locs), state.registerContents, work)
+                       f.Logf("Block done: locs %v, regs %v\n", state.BlockString(locs), state.registerContents)
                }
                blockLocs[b.ID] = locs
        }
@@ -382,30 +366,6 @@ func isSynthetic(slot *LocalSlot) bool {
        return c == '.' || c == '~'
 }
 
-// predecessorsDone reports whether block is ready to be processed.
-func (state *debugState) predecessorsDone(b *Block, blockLocs []*BlockDebug) bool {
-       f := b.Func
-       for _, edge := range b.Preds {
-               // Ignore back branches, e.g. the continuation of a for loop.
-               // This may not work for functions with mutual gotos, which are not
-               // reducible, in which case debug information will be missing for any
-               // code after that point in the control flow.
-               if f.sdom().isAncestorEq(b, edge.b) {
-                       if state.loggingEnabled {
-                               f.Logf("ignoring back branch from %v to %v\n", edge.b, b)
-                       }
-                       continue // back branch
-               }
-               if blockLocs[edge.b.ID] == nil {
-                       if state.loggingEnabled {
-                               f.Logf("%v is not ready because %v isn't done\n", b, edge.b)
-                       }
-                       return false
-               }
-       }
-       return true
-}
-
 // mergePredecessors takes the end state of each of b's predecessors and
 // intersects them to form the starting state for b.
 // The registers slice (the second return value) will be reused for each call to mergePredecessors.