diff options
author | Keith Randall <khr@golang.org> | 2015-05-28 13:49:20 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2015-05-28 13:51:18 -0700 |
commit | 067e8dfd82163ddcbde248dbe5a1187a417e5d36 (patch) | |
tree | 7bfb46b901d03498c7739c92bec21d81d3a2c485 /src/cmd/compile/internal/ssa/dom.go | |
parent | 247786c1745abc0c7185f7c15ca256edf68ed6d6 (diff) | |
parent | ccc037699e2966b7c79ba84c67471cef5e67a3b8 (diff) | |
download | go-067e8dfd82163ddcbde248dbe5a1187a417e5d36.tar.gz go-067e8dfd82163ddcbde248dbe5a1187a417e5d36.zip |
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Semi-regular merge of tip to dev.ssa.
Complicated a bit by the move of cmd/internal/* to cmd/compile/internal/*.
Change-Id: I1c66d3c29bb95cce4a53c5a3476373aa5245303d
Diffstat (limited to 'src/cmd/compile/internal/ssa/dom.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/dom.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go new file mode 100644 index 0000000000..aaf3ab3da1 --- /dev/null +++ b/src/cmd/compile/internal/ssa/dom.go @@ -0,0 +1,121 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssa + +// This file contains code to compute the dominator tree +// of a control-flow graph. + +import "log" + +// postorder computes a postorder traversal ordering for the +// basic blocks in f. Unreachable blocks will not appear. +func postorder(f *Func) []*Block { + mark := make([]byte, f.NumBlocks()) + // mark values + const ( + notFound = 0 // block has not been discovered yet + notExplored = 1 // discovered and in queue, outedges not processed yet + explored = 2 // discovered and in queue, outedges processed + done = 3 // all done, in output ordering + ) + + // result ordering + var order []*Block + + // stack of blocks + var s []*Block + s = append(s, f.Entry) + mark[f.Entry.ID] = notExplored + for len(s) > 0 { + b := s[len(s)-1] + switch mark[b.ID] { + case explored: + // Children have all been visited. Pop & output block. + s = s[:len(s)-1] + mark[b.ID] = done + order = append(order, b) + case notExplored: + // Children have not been visited yet. Mark as explored + // and queue any children we haven't seen yet. + mark[b.ID] = explored + for _, c := range b.Succs { + if mark[c.ID] == notFound { + mark[c.ID] = notExplored + s = append(s, c) + } + } + default: + log.Fatalf("bad stack state %v %d", b, mark[b.ID]) + } + } + return order +} + +// dominators computes the dominator tree for f. It returns a slice +// which maps block ID to the immediate dominator of that block. +// Unreachable blocks map to nil. The entry block maps to nil. +func dominators(f *Func) []*Block { + // A simple algorithm for now + // Cooper, Harvey, Kennedy + idom := make([]*Block, f.NumBlocks()) + + // Compute postorder walk + post := postorder(f) + + // Make map from block id to order index (for intersect call) + postnum := make([]int, f.NumBlocks()) + for i, b := range post { + postnum[b.ID] = i + } + + // Make the entry block a self-loop + idom[f.Entry.ID] = f.Entry + if postnum[f.Entry.ID] != len(post)-1 { + log.Fatalf("entry block %v not last in postorder", f.Entry) + } + + // Compute relaxation of idom entries + for { + changed := false + + for i := len(post) - 2; i >= 0; i-- { + b := post[i] + var d *Block + for _, p := range b.Preds { + if idom[p.ID] == nil { + continue + } + if d == nil { + d = p + continue + } + d = intersect(d, p, postnum, idom) + } + if d != idom[b.ID] { + idom[b.ID] = d + changed = true + } + } + if !changed { + break + } + } + // Set idom of entry block to nil instead of itself. + idom[f.Entry.ID] = nil + return idom +} + +// intersect finds the closest dominator of both b and c. +// It requires a postorder numbering of all the blocks. +func intersect(b, c *Block, postnum []int, idom []*Block) *Block { + for b != c { + if postnum[b.ID] < postnum[c.ID] { + b = idom[b.ID] + } else { + c = idom[c.ID] + } + } + return b +} |