github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/print.go (about) 1 // Copyright 2013 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 // This file implements the String() methods for all Value and 8 // Instruction types. 9 10 import ( 11 "bytes" 12 "fmt" 13 "io" 14 "reflect" 15 "sort" 16 17 "llvm.org/llgo/third_party/gotools/go/types" 18 "llvm.org/llgo/third_party/gotools/go/types/typeutil" 19 ) 20 21 // relName returns the name of v relative to i. 22 // In most cases, this is identical to v.Name(), but references to 23 // Functions (including methods) and Globals use RelString and 24 // all types are displayed with relType, so that only cross-package 25 // references are package-qualified. 26 // 27 func relName(v Value, i Instruction) string { 28 var from *types.Package 29 if i != nil { 30 from = i.Parent().pkgobj() 31 } 32 switch v := v.(type) { 33 case Member: // *Function or *Global 34 return v.RelString(from) 35 case *Const: 36 return v.RelString(from) 37 } 38 return v.Name() 39 } 40 41 func relType(t types.Type, from *types.Package) string { 42 return types.TypeString(from, t) 43 } 44 45 func relString(m Member, from *types.Package) string { 46 // NB: not all globals have an Object (e.g. init$guard), 47 // so use Package().Object not Object.Package(). 48 if obj := m.Package().Object; obj != nil && obj != from { 49 return fmt.Sprintf("%s.%s", obj.Path(), m.Name()) 50 } 51 return m.Name() 52 } 53 54 // Value.String() 55 // 56 // This method is provided only for debugging. 57 // It never appears in disassembly, which uses Value.Name(). 58 59 func (v *Parameter) String() string { 60 from := v.Parent().pkgobj() 61 return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from)) 62 } 63 64 func (v *FreeVar) String() string { 65 from := v.Parent().pkgobj() 66 return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from)) 67 } 68 69 func (v *Builtin) String() string { 70 return fmt.Sprintf("builtin %s", v.Name()) 71 } 72 73 // Instruction.String() 74 75 func (v *Alloc) String() string { 76 op := "local" 77 if v.Heap { 78 op = "new" 79 } 80 from := v.Parent().pkgobj() 81 return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment) 82 } 83 84 func (v *Phi) String() string { 85 var b bytes.Buffer 86 b.WriteString("phi [") 87 for i, edge := range v.Edges { 88 if i > 0 { 89 b.WriteString(", ") 90 } 91 // Be robust against malformed CFG. 92 block := -1 93 if v.block != nil && i < len(v.block.Preds) { 94 block = v.block.Preds[i].Index 95 } 96 fmt.Fprintf(&b, "%d: ", block) 97 edgeVal := "<nil>" // be robust 98 if edge != nil { 99 edgeVal = relName(edge, v) 100 } 101 b.WriteString(edgeVal) 102 } 103 b.WriteString("]") 104 if v.Comment != "" { 105 b.WriteString(" #") 106 b.WriteString(v.Comment) 107 } 108 return b.String() 109 } 110 111 func printCall(v *CallCommon, prefix string, instr Instruction) string { 112 var b bytes.Buffer 113 b.WriteString(prefix) 114 if !v.IsInvoke() { 115 b.WriteString(relName(v.Value, instr)) 116 } else { 117 fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name()) 118 } 119 b.WriteString("(") 120 for i, arg := range v.Args { 121 if i > 0 { 122 b.WriteString(", ") 123 } 124 b.WriteString(relName(arg, instr)) 125 } 126 if v.Signature().Variadic() { 127 b.WriteString("...") 128 } 129 b.WriteString(")") 130 return b.String() 131 } 132 133 func (c *CallCommon) String() string { 134 return printCall(c, "", nil) 135 } 136 137 func (v *Call) String() string { 138 return printCall(&v.Call, "", v) 139 } 140 141 func (v *BinOp) String() string { 142 return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v)) 143 } 144 145 func (v *UnOp) String() string { 146 return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk)) 147 } 148 149 func printConv(prefix string, v, x Value) string { 150 from := v.Parent().pkgobj() 151 return fmt.Sprintf("%s %s <- %s (%s)", 152 prefix, 153 relType(v.Type(), from), 154 relType(x.Type(), from), 155 relName(x, v.(Instruction))) 156 } 157 158 func (v *ChangeType) String() string { return printConv("changetype", v, v.X) } 159 func (v *Convert) String() string { return printConv("convert", v, v.X) } 160 func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) } 161 func (v *MakeInterface) String() string { return printConv("make", v, v.X) } 162 163 func (v *MakeClosure) String() string { 164 var b bytes.Buffer 165 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v)) 166 if v.Bindings != nil { 167 b.WriteString(" [") 168 for i, c := range v.Bindings { 169 if i > 0 { 170 b.WriteString(", ") 171 } 172 b.WriteString(relName(c, v)) 173 } 174 b.WriteString("]") 175 } 176 return b.String() 177 } 178 179 func (v *MakeSlice) String() string { 180 from := v.Parent().pkgobj() 181 return fmt.Sprintf("make %s %s %s", 182 relType(v.Type(), from), 183 relName(v.Len, v), 184 relName(v.Cap, v)) 185 } 186 187 func (v *Slice) String() string { 188 var b bytes.Buffer 189 b.WriteString("slice ") 190 b.WriteString(relName(v.X, v)) 191 b.WriteString("[") 192 if v.Low != nil { 193 b.WriteString(relName(v.Low, v)) 194 } 195 b.WriteString(":") 196 if v.High != nil { 197 b.WriteString(relName(v.High, v)) 198 } 199 if v.Max != nil { 200 b.WriteString(":") 201 b.WriteString(relName(v.Max, v)) 202 } 203 b.WriteString("]") 204 return b.String() 205 } 206 207 func (v *MakeMap) String() string { 208 res := "" 209 if v.Reserve != nil { 210 res = relName(v.Reserve, v) 211 } 212 from := v.Parent().pkgobj() 213 return fmt.Sprintf("make %s %s", relType(v.Type(), from), res) 214 } 215 216 func (v *MakeChan) String() string { 217 from := v.Parent().pkgobj() 218 return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v)) 219 } 220 221 func (v *FieldAddr) String() string { 222 st := deref(v.X.Type()).Underlying().(*types.Struct) 223 // Be robust against a bad index. 224 name := "?" 225 if 0 <= v.Field && v.Field < st.NumFields() { 226 name = st.Field(v.Field).Name() 227 } 228 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) 229 } 230 231 func (v *Field) String() string { 232 st := v.X.Type().Underlying().(*types.Struct) 233 // Be robust against a bad index. 234 name := "?" 235 if 0 <= v.Field && v.Field < st.NumFields() { 236 name = st.Field(v.Field).Name() 237 } 238 return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) 239 } 240 241 func (v *IndexAddr) String() string { 242 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v)) 243 } 244 245 func (v *Index) String() string { 246 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) 247 } 248 249 func (v *Lookup) String() string { 250 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk)) 251 } 252 253 func (v *Range) String() string { 254 return "range " + relName(v.X, v) 255 } 256 257 func (v *Next) String() string { 258 return "next " + relName(v.Iter, v) 259 } 260 261 func (v *TypeAssert) String() string { 262 from := v.Parent().pkgobj() 263 return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from)) 264 } 265 266 func (v *Extract) String() string { 267 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index) 268 } 269 270 func (s *Jump) String() string { 271 // Be robust against malformed CFG. 272 block := -1 273 if s.block != nil && len(s.block.Succs) == 1 { 274 block = s.block.Succs[0].Index 275 } 276 return fmt.Sprintf("jump %d", block) 277 } 278 279 func (s *If) String() string { 280 // Be robust against malformed CFG. 281 tblock, fblock := -1, -1 282 if s.block != nil && len(s.block.Succs) == 2 { 283 tblock = s.block.Succs[0].Index 284 fblock = s.block.Succs[1].Index 285 } 286 return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock) 287 } 288 289 func (s *Go) String() string { 290 return printCall(&s.Call, "go ", s) 291 } 292 293 func (s *Panic) String() string { 294 return "panic " + relName(s.X, s) 295 } 296 297 func (s *Return) String() string { 298 var b bytes.Buffer 299 b.WriteString("return") 300 for i, r := range s.Results { 301 if i == 0 { 302 b.WriteString(" ") 303 } else { 304 b.WriteString(", ") 305 } 306 b.WriteString(relName(r, s)) 307 } 308 return b.String() 309 } 310 311 func (*RunDefers) String() string { 312 return "rundefers" 313 } 314 315 func (s *Send) String() string { 316 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s)) 317 } 318 319 func (s *Defer) String() string { 320 return printCall(&s.Call, "defer ", s) 321 } 322 323 func (s *Select) String() string { 324 var b bytes.Buffer 325 for i, st := range s.States { 326 if i > 0 { 327 b.WriteString(", ") 328 } 329 if st.Dir == types.RecvOnly { 330 b.WriteString("<-") 331 b.WriteString(relName(st.Chan, s)) 332 } else { 333 b.WriteString(relName(st.Chan, s)) 334 b.WriteString("<-") 335 b.WriteString(relName(st.Send, s)) 336 } 337 } 338 non := "" 339 if !s.Blocking { 340 non = "non" 341 } 342 return fmt.Sprintf("select %sblocking [%s]", non, b.String()) 343 } 344 345 func (s *Store) String() string { 346 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s)) 347 } 348 349 func (s *MapUpdate) String() string { 350 return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) 351 } 352 353 func (s *DebugRef) String() string { 354 p := s.Parent().Prog.Fset.Position(s.Pos()) 355 var descr interface{} 356 if s.object != nil { 357 descr = s.object // e.g. "var x int" 358 } else { 359 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr" 360 } 361 var addr string 362 if s.IsAddr { 363 addr = "address of " 364 } 365 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name()) 366 } 367 368 func (p *Package) String() string { 369 return "package " + p.Object.Path() 370 } 371 372 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer 373 374 func (p *Package) WriteTo(w io.Writer) (int64, error) { 375 var buf bytes.Buffer 376 WritePackage(&buf, p) 377 n, err := w.Write(buf.Bytes()) 378 return int64(n), err 379 } 380 381 // WritePackage writes to buf a human-readable summary of p. 382 func WritePackage(buf *bytes.Buffer, p *Package) { 383 fmt.Fprintf(buf, "%s:\n", p) 384 385 var names []string 386 maxname := 0 387 for name := range p.Members { 388 if l := len(name); l > maxname { 389 maxname = l 390 } 391 names = append(names, name) 392 } 393 394 from := p.Object 395 sort.Strings(names) 396 for _, name := range names { 397 switch mem := p.Members[name].(type) { 398 case *NamedConst: 399 fmt.Fprintf(buf, " const %-*s %s = %s\n", 400 maxname, name, mem.Name(), mem.Value.RelString(from)) 401 402 case *Function: 403 fmt.Fprintf(buf, " func %-*s %s\n", 404 maxname, name, relType(mem.Type(), from)) 405 406 case *Type: 407 fmt.Fprintf(buf, " type %-*s %s\n", 408 maxname, name, relType(mem.Type().Underlying(), from)) 409 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) { 410 fmt.Fprintf(buf, " %s\n", types.SelectionString(from, meth)) 411 } 412 413 case *Global: 414 fmt.Fprintf(buf, " var %-*s %s\n", 415 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) 416 } 417 } 418 419 fmt.Fprintf(buf, "\n") 420 } 421 422 func commaOk(x bool) string { 423 if x { 424 return ",ok" 425 } 426 return "" 427 }