// 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 import ( "bytes" "crypto/sha256" "fmt" "io" ) func printFunc(f *Func) { f.Logf("%s", f) } func hashFunc(f *Func) []byte { h := sha256.New() p := stringFuncPrinter{w: h} fprintFunc(p, f) return h.Sum(nil) } func (f *Func) String() string { var buf bytes.Buffer p := stringFuncPrinter{w: &buf} fprintFunc(p, f) return buf.String() } type funcPrinter interface { header(f *Func) startBlock(b *Block, reachable bool) endBlock(b *Block) value(v *Value, live bool) startDepCycle() endDepCycle() named(n LocalSlot, vals []*Value) } type stringFuncPrinter struct { w io.Writer } func (p stringFuncPrinter) header(f *Func) { fmt.Fprint(p.w, f.Name) fmt.Fprint(p.w, " ") fmt.Fprintln(p.w, f.Type) } func (p stringFuncPrinter) startBlock(b *Block, reachable bool) { fmt.Fprintf(p.w, " b%d:", b.ID) if len(b.Preds) > 0 { io.WriteString(p.w, " <-") for _, e := range b.Preds { pred := e.b fmt.Fprintf(p.w, " b%d", pred.ID) } } if !reachable { fmt.Fprint(p.w, " DEAD") } io.WriteString(p.w, "\n") } func (p stringFuncPrinter) endBlock(b *Block) { fmt.Fprintln(p.w, " "+b.LongString()) } func (p stringFuncPrinter) value(v *Value, live bool) { fmt.Fprint(p.w, " ") //fmt.Fprint(p.w, v.Block.Func.fe.Pos(v.Pos)) //fmt.Fprint(p.w, ": ") fmt.Fprint(p.w, v.LongString()) if !live { fmt.Fprint(p.w, " DEAD") } fmt.Fprintln(p.w) } func (p stringFuncPrinter) startDepCycle() { fmt.Fprintln(p.w, "dependency cycle!") } func (p stringFuncPrinter) endDepCycle() {} func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) { fmt.Fprintf(p.w, "name %s: %v\n", n, vals) } func fprintFunc(p funcPrinter, f *Func) { reachable, live := findlive(f) defer f.retDeadcodeLive(live) p.header(f) printed := make([]bool, f.NumValues()) for _, b := range f.Blocks { p.startBlock(b, reachable[b.ID]) if f.scheduled { // Order of Values has been decided - print in that order. for _, v := range b.Values { p.value(v, live[v.ID]) printed[v.ID] = true } p.endBlock(b) continue } // print phis first since all value cycles contain a phi n := 0 for _, v := range b.Values { if v.Op != OpPhi { continue } p.value(v, live[v.ID]) printed[v.ID] = true n++ } // print rest of values in dependency order for n < len(b.Values) { m := n outer: for _, v := range b.Values { if printed[v.ID] { continue } for _, w := range v.Args { // w == nil shouldn't happen, but if it does, // don't panic; we'll get a better diagnosis later. if w != nil && w.Block == b && !printed[w.ID] { continue outer } } p.value(v, live[v.ID]) printed[v.ID] = true n++ } if m == n { p.startDepCycle() for _, v := range b.Values { if printed[v.ID] { continue } p.value(v, live[v.ID]) printed[v.ID] = true n++ } p.endDepCycle() } } p.endBlock(b) } for _, name := range f.Names { p.named(*name, f.NamedValues[*name]) } }