diff options
Diffstat (limited to 'vendor/github.com/mmcloughlin/avo/pass/cfg.go')
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/pass/cfg.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/vendor/github.com/mmcloughlin/avo/pass/cfg.go b/vendor/github.com/mmcloughlin/avo/pass/cfg.go new file mode 100644 index 0000000..d5f6ea4 --- /dev/null +++ b/vendor/github.com/mmcloughlin/avo/pass/cfg.go @@ -0,0 +1,81 @@ +package pass + +import ( + "errors" + "fmt" + + "github.com/mmcloughlin/avo/ir" +) + +// LabelTarget populates the LabelTarget of the given function. This maps from +// label name to the following instruction. +func LabelTarget(fn *ir.Function) error { + target := map[ir.Label]*ir.Instruction{} + var pending []ir.Label + for _, node := range fn.Nodes { + switch n := node.(type) { + case ir.Label: + if _, found := target[n]; found { + return fmt.Errorf("duplicate label \"%s\"", n) + } + pending = append(pending, n) + case *ir.Instruction: + for _, label := range pending { + target[label] = n + } + pending = nil + } + } + if len(pending) != 0 { + return errors.New("function ends with label") + } + fn.LabelTarget = target + return nil +} + +// CFG constructs the call-flow-graph for the function. +func CFG(fn *ir.Function) error { + is := fn.Instructions() + n := len(is) + + // Populate successors. + for i := 0; i < n; i++ { + cur := is[i] + var nxt *ir.Instruction + if i+1 < n { + nxt = is[i+1] + } + + // If it's a branch, locate the target. + if cur.IsBranch { + lbl := cur.TargetLabel() + if lbl == nil { + return errors.New("no label for branch instruction") + } + target, found := fn.LabelTarget[*lbl] + if !found { + return fmt.Errorf("unknown label %q", *lbl) + } + cur.Succ = append(cur.Succ, target) + } + + // Otherwise, could continue to the following instruction. + switch { + case cur.IsTerminal: + case cur.IsUnconditionalBranch(): + default: + cur.Succ = append(cur.Succ, nxt) + } + } + + // Populate predecessors. + for _, i := range is { + for _, s := range i.Succ { + if s != nil { + s.Pred = append(s.Pred, i) + } + } + } + + return nil +} |