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

View as plain text