2015-03-03 13:38:14 -08:00
|
|
|
// 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
|
|
|
|
|
|
2015-05-30 13:17:12 -04:00
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
)
|
2015-03-03 13:38:14 -08:00
|
|
|
|
|
|
|
|
func printFunc(f *Func) {
|
2015-07-10 09:31:28 -06:00
|
|
|
f.Logf("%s", f)
|
2015-05-30 13:17:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Func) String() string {
|
|
|
|
|
var buf bytes.Buffer
|
2015-08-10 12:15:52 -07:00
|
|
|
p := stringFuncPrinter{w: &buf}
|
|
|
|
|
fprintFunc(p, f)
|
2015-05-30 13:17:12 -04:00
|
|
|
return buf.String()
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 12:15:52 -07:00
|
|
|
type funcPrinter interface {
|
|
|
|
|
header(f *Func)
|
|
|
|
|
startBlock(b *Block, reachable bool)
|
|
|
|
|
endBlock(b *Block)
|
|
|
|
|
value(v *Value, live bool)
|
|
|
|
|
startDepCycle()
|
|
|
|
|
endDepCycle()
|
2015-11-02 08:10:26 -08:00
|
|
|
named(n LocalSlot, vals []*Value)
|
2015-08-10 12:15:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 _, pred := range b.Preds {
|
|
|
|
|
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, " ")
|
2016-01-14 16:02:23 -08:00
|
|
|
//fmt.Fprint(p.w, v.Block.Func.Config.fe.Line(v.Line))
|
|
|
|
|
//fmt.Fprint(p.w, ": ")
|
2015-08-10 12:15:52 -07:00
|
|
|
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() {}
|
|
|
|
|
|
2015-11-02 08:10:26 -08:00
|
|
|
func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) {
|
|
|
|
|
fmt.Fprintf(p.w, "name %s: %v\n", n.Name(), vals)
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 12:15:52 -07:00
|
|
|
func fprintFunc(p funcPrinter, f *Func) {
|
|
|
|
|
reachable, live := findlive(f)
|
|
|
|
|
p.header(f)
|
2015-03-03 13:38:14 -08:00
|
|
|
printed := make([]bool, f.NumValues())
|
|
|
|
|
for _, b := range f.Blocks {
|
2015-08-10 12:15:52 -07:00
|
|
|
p.startBlock(b, reachable[b.ID])
|
2015-08-03 12:33:03 -07:00
|
|
|
|
|
|
|
|
if f.scheduled {
|
|
|
|
|
// Order of Values has been decided - print in that order.
|
|
|
|
|
for _, v := range b.Values {
|
2015-08-10 12:15:52 -07:00
|
|
|
p.value(v, live[v.ID])
|
2015-08-03 12:33:03 -07:00
|
|
|
printed[v.ID] = true
|
|
|
|
|
}
|
2015-08-10 12:15:52 -07:00
|
|
|
p.endBlock(b)
|
2015-08-03 12:33:03 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2015-03-03 13:38:14 -08:00
|
|
|
|
|
|
|
|
// print phis first since all value cycles contain a phi
|
2015-08-03 12:33:03 -07:00
|
|
|
n := 0
|
2015-03-03 13:38:14 -08:00
|
|
|
for _, v := range b.Values {
|
|
|
|
|
if v.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-08-10 12:15:52 -07:00
|
|
|
p.value(v, live[v.ID])
|
2015-03-03 13:38:14 -08:00
|
|
|
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 {
|
2015-06-29 11:56:28 -07:00
|
|
|
// 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] {
|
2015-03-03 13:38:14 -08:00
|
|
|
continue outer
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-10 12:15:52 -07:00
|
|
|
p.value(v, live[v.ID])
|
2015-03-03 13:38:14 -08:00
|
|
|
printed[v.ID] = true
|
|
|
|
|
n++
|
|
|
|
|
}
|
|
|
|
|
if m == n {
|
2015-08-10 12:15:52 -07:00
|
|
|
p.startDepCycle()
|
2015-03-03 13:38:14 -08:00
|
|
|
for _, v := range b.Values {
|
|
|
|
|
if printed[v.ID] {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-08-10 12:15:52 -07:00
|
|
|
p.value(v, live[v.ID])
|
2015-03-03 13:38:14 -08:00
|
|
|
printed[v.ID] = true
|
|
|
|
|
n++
|
|
|
|
|
}
|
2015-08-10 12:15:52 -07:00
|
|
|
p.endDepCycle()
|
2015-03-03 13:38:14 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 12:15:52 -07:00
|
|
|
p.endBlock(b)
|
2015-03-03 13:38:14 -08:00
|
|
|
}
|
2016-03-03 09:53:03 -08:00
|
|
|
for _, name := range f.Names {
|
|
|
|
|
p.named(name, f.NamedValues[name])
|
2015-11-02 08:10:26 -08:00
|
|
|
}
|
2015-03-03 13:38:14 -08:00
|
|
|
}
|