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 5package ssa 6 7import ( 8 "fmt" 9 "io" 10 "strings" 11 12 "cmd/internal/notsha256" 13 "cmd/internal/src" 14) 15 16func printFunc(f *Func) { 17 f.Logf("%s", f) 18} 19 20func 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 27func (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. 35func (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 42type 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 52type stringFuncPrinter struct { 53 w io.Writer 54 printDead bool 55} 56 57func (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 63func (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 81func (p stringFuncPrinter) endBlock(b *Block, reachable bool) { 82 if !p.printDead && !reachable { 83 return 84 } 85 fmt.Fprintln(p.w, " "+b.LongString()) 86} 87 88func 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 103func (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 115func (p stringFuncPrinter) startDepCycle() { 116 fmt.Fprintln(p.w, "dependency cycle!") 117} 118 119func (p stringFuncPrinter) endDepCycle() {} 120 121func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) { 122 fmt.Fprintf(p.w, "name %s: %v\n", n, vals) 123} 124 125func 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