Home | History | Annotate | Download | only in ssa
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package ssa
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"io"
     11 )
     12 
     13 func printFunc(f *Func) {
     14 	f.Logf("%s", f)
     15 }
     16 
     17 func (f *Func) String() string {
     18 	var buf bytes.Buffer
     19 	p := stringFuncPrinter{w: &buf}
     20 	fprintFunc(p, f)
     21 	return buf.String()
     22 }
     23 
     24 type funcPrinter interface {
     25 	header(f *Func)
     26 	startBlock(b *Block, reachable bool)
     27 	endBlock(b *Block)
     28 	value(v *Value, live bool)
     29 	startDepCycle()
     30 	endDepCycle()
     31 	named(n LocalSlot, vals []*Value)
     32 }
     33 
     34 type stringFuncPrinter struct {
     35 	w io.Writer
     36 }
     37 
     38 func (p stringFuncPrinter) header(f *Func) {
     39 	fmt.Fprint(p.w, f.Name)
     40 	fmt.Fprint(p.w, " ")
     41 	fmt.Fprintln(p.w, f.Type)
     42 }
     43 
     44 func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
     45 	fmt.Fprintf(p.w, "  b%d:", b.ID)
     46 	if len(b.Preds) > 0 {
     47 		io.WriteString(p.w, " <-")
     48 		for _, e := range b.Preds {
     49 			pred := e.b
     50 			fmt.Fprintf(p.w, " b%d", pred.ID)
     51 		}
     52 	}
     53 	if !reachable {
     54 		fmt.Fprint(p.w, " DEAD")
     55 	}
     56 	io.WriteString(p.w, "\n")
     57 }
     58 
     59 func (p stringFuncPrinter) endBlock(b *Block) {
     60 	fmt.Fprintln(p.w, "    "+b.LongString())
     61 }
     62 
     63 func (p stringFuncPrinter) value(v *Value, live bool) {
     64 	fmt.Fprint(p.w, "    ")
     65 	//fmt.Fprint(p.w, v.Block.Func.Config.fe.Line(v.Line))
     66 	//fmt.Fprint(p.w, ": ")
     67 	fmt.Fprint(p.w, v.LongString())
     68 	if !live {
     69 		fmt.Fprint(p.w, " DEAD")
     70 	}
     71 	fmt.Fprintln(p.w)
     72 }
     73 
     74 func (p stringFuncPrinter) startDepCycle() {
     75 	fmt.Fprintln(p.w, "dependency cycle!")
     76 }
     77 
     78 func (p stringFuncPrinter) endDepCycle() {}
     79 
     80 func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) {
     81 	fmt.Fprintf(p.w, "name %s: %v\n", n.Name(), vals)
     82 }
     83 
     84 func fprintFunc(p funcPrinter, f *Func) {
     85 	reachable, live := findlive(f)
     86 	p.header(f)
     87 	printed := make([]bool, f.NumValues())
     88 	for _, b := range f.Blocks {
     89 		p.startBlock(b, reachable[b.ID])
     90 
     91 		if f.scheduled {
     92 			// Order of Values has been decided - print in that order.
     93 			for _, v := range b.Values {
     94 				p.value(v, live[v.ID])
     95 				printed[v.ID] = true
     96 			}
     97 			p.endBlock(b)
     98 			continue
     99 		}
    100 
    101 		// print phis first since all value cycles contain a phi
    102 		n := 0
    103 		for _, v := range b.Values {
    104 			if v.Op != OpPhi {
    105 				continue
    106 			}
    107 			p.value(v, live[v.ID])
    108 			printed[v.ID] = true
    109 			n++
    110 		}
    111 
    112 		// print rest of values in dependency order
    113 		for n < len(b.Values) {
    114 			m := n
    115 		outer:
    116 			for _, v := range b.Values {
    117 				if printed[v.ID] {
    118 					continue
    119 				}
    120 				for _, w := range v.Args {
    121 					// w == nil shouldn't happen, but if it does,
    122 					// don't panic; we'll get a better diagnosis later.
    123 					if w != nil && w.Block == b && !printed[w.ID] {
    124 						continue outer
    125 					}
    126 				}
    127 				p.value(v, live[v.ID])
    128 				printed[v.ID] = true
    129 				n++
    130 			}
    131 			if m == n {
    132 				p.startDepCycle()
    133 				for _, v := range b.Values {
    134 					if printed[v.ID] {
    135 						continue
    136 					}
    137 					p.value(v, live[v.ID])
    138 					printed[v.ID] = true
    139 					n++
    140 				}
    141 				p.endDepCycle()
    142 			}
    143 		}
    144 
    145 		p.endBlock(b)
    146 	}
    147 	for _, name := range f.Names {
    148 		p.named(name, f.NamedValues[name])
    149 	}
    150 }
    151