Source file src/cmd/compile/internal/ssa/print.go

     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  	"fmt"
     9  	"io"
    10  	"strings"
    11  
    12  	"cmd/internal/notsha256"
    13  	"cmd/internal/src"
    14  )
    15  
    16  func printFunc(f *Func) {
    17  	f.Logf("%s", f)
    18  }
    19  
    20  func hashFunc(f *Func) []byte {
    21  	h := notsha256.New()
    22  	p := stringFuncPrinter{w: h, printDead: true}
    23  	fprintFunc(p, f)
    24  	return h.Sum(nil)
    25  }
    26  
    27  func (f *Func) String() string {
    28  	var buf strings.Builder
    29  	p := stringFuncPrinter{w: &buf, printDead: true}
    30  	fprintFunc(p, f)
    31  	return buf.String()
    32  }
    33  
    34  // rewriteHash returns a hash of f suitable for detecting rewrite cycles.
    35  func (f *Func) rewriteHash() string {
    36  	h := notsha256.New()
    37  	p := stringFuncPrinter{w: h, printDead: false}
    38  	fprintFunc(p, f)
    39  	return fmt.Sprintf("%x", h.Sum(nil))
    40  }
    41  
    42  type funcPrinter interface {
    43  	header(f *Func)
    44  	startBlock(b *Block, reachable bool)
    45  	endBlock(b *Block, reachable bool)
    46  	value(v *Value, live bool)
    47  	startDepCycle()
    48  	endDepCycle()
    49  	named(n LocalSlot, vals []*Value)
    50  }
    51  
    52  type stringFuncPrinter struct {
    53  	w         io.Writer
    54  	printDead bool
    55  }
    56  
    57  func (p stringFuncPrinter) header(f *Func) {
    58  	fmt.Fprint(p.w, f.Name)
    59  	fmt.Fprint(p.w, " ")
    60  	fmt.Fprintln(p.w, f.Type)
    61  }
    62  
    63  func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
    64  	if !p.printDead && !reachable {
    65  		return
    66  	}
    67  	fmt.Fprintf(p.w, "  b%d:", b.ID)
    68  	if len(b.Preds) > 0 {
    69  		io.WriteString(p.w, " <-")
    70  		for _, e := range b.Preds {
    71  			pred := e.b
    72  			fmt.Fprintf(p.w, " b%d", pred.ID)
    73  		}
    74  	}
    75  	if !reachable {
    76  		fmt.Fprint(p.w, " DEAD")
    77  	}
    78  	io.WriteString(p.w, "\n")
    79  }
    80  
    81  func (p stringFuncPrinter) endBlock(b *Block, reachable bool) {
    82  	if !p.printDead && !reachable {
    83  		return
    84  	}
    85  	fmt.Fprintln(p.w, "    "+b.LongString())
    86  }
    87  
    88  func StmtString(p src.XPos) string {
    89  	linenumber := "(?) "
    90  	if p.IsKnown() {
    91  		pfx := ""
    92  		if p.IsStmt() == src.PosIsStmt {
    93  			pfx = "+"
    94  		}
    95  		if p.IsStmt() == src.PosNotStmt {
    96  			pfx = "-"
    97  		}
    98  		linenumber = fmt.Sprintf("(%s%d) ", pfx, p.Line())
    99  	}
   100  	return linenumber
   101  }
   102  
   103  func (p stringFuncPrinter) value(v *Value, live bool) {
   104  	if !p.printDead && !live {
   105  		return
   106  	}
   107  	fmt.Fprintf(p.w, "    %s", StmtString(v.Pos))
   108  	fmt.Fprint(p.w, v.LongString())
   109  	if !live {
   110  		fmt.Fprint(p.w, " DEAD")
   111  	}
   112  	fmt.Fprintln(p.w)
   113  }
   114  
   115  func (p stringFuncPrinter) startDepCycle() {
   116  	fmt.Fprintln(p.w, "dependency cycle!")
   117  }
   118  
   119  func (p stringFuncPrinter) endDepCycle() {}
   120  
   121  func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) {
   122  	fmt.Fprintf(p.w, "name %s: %v\n", n, vals)
   123  }
   124  
   125  func fprintFunc(p funcPrinter, f *Func) {
   126  	reachable, live := findlive(f)
   127  	defer f.Cache.freeBoolSlice(live)
   128  	p.header(f)
   129  	printed := make([]bool, f.NumValues())
   130  	for _, b := range f.Blocks {
   131  		p.startBlock(b, reachable[b.ID])
   132  
   133  		if f.scheduled {
   134  			// Order of Values has been decided - print in that order.
   135  			for _, v := range b.Values {
   136  				p.value(v, live[v.ID])
   137  				printed[v.ID] = true
   138  			}
   139  			p.endBlock(b, reachable[b.ID])
   140  			continue
   141  		}
   142  
   143  		// print phis first since all value cycles contain a phi
   144  		n := 0
   145  		for _, v := range b.Values {
   146  			if v.Op != OpPhi {
   147  				continue
   148  			}
   149  			p.value(v, live[v.ID])
   150  			printed[v.ID] = true
   151  			n++
   152  		}
   153  
   154  		// print rest of values in dependency order
   155  		for n < len(b.Values) {
   156  			m := n
   157  		outer:
   158  			for _, v := range b.Values {
   159  				if printed[v.ID] {
   160  					continue
   161  				}
   162  				for _, w := range v.Args {
   163  					// w == nil shouldn't happen, but if it does,
   164  					// don't panic; we'll get a better diagnosis later.
   165  					if w != nil && w.Block == b && !printed[w.ID] {
   166  						continue outer
   167  					}
   168  				}
   169  				p.value(v, live[v.ID])
   170  				printed[v.ID] = true
   171  				n++
   172  			}
   173  			if m == n {
   174  				p.startDepCycle()
   175  				for _, v := range b.Values {
   176  					if printed[v.ID] {
   177  						continue
   178  					}
   179  					p.value(v, live[v.ID])
   180  					printed[v.ID] = true
   181  					n++
   182  				}
   183  				p.endDepCycle()
   184  			}
   185  		}
   186  
   187  		p.endBlock(b, reachable[b.ID])
   188  	}
   189  	for _, name := range f.Names {
   190  		p.named(*name, f.NamedValues[*name])
   191  	}
   192  }
   193  

View as plain text