Backport revision 203977 from trunk.
[official-gcc.git] / main / libgo / go / exp / ssa / print.go
blobb8708b6ede46a2bf7e0d9238135acb9d50df43d3
1 package ssa
3 // This file implements the String() methods for all Value and
4 // Instruction types.
6 import (
7 "bytes"
8 "fmt"
9 "go/ast"
10 "go/types"
13 func (id Id) String() string {
14 if id.Pkg == nil {
15 return id.Name
17 return fmt.Sprintf("%s/%s", id.Pkg.Path, id.Name)
20 // relName returns the name of v relative to i.
21 // In most cases, this is identical to v.Name(), but for cross-package
22 // references to Functions (including methods) and Globals, the
23 // package-qualified FullName is used instead.
25 func relName(v Value, i Instruction) string {
26 switch v := v.(type) {
27 case *Global:
28 if v.Pkg == i.Block().Func.Pkg {
29 return v.Name()
31 return v.FullName()
32 case *Function:
33 if v.Pkg == nil || v.Pkg == i.Block().Func.Pkg {
34 return v.Name()
36 return v.FullName()
38 return v.Name()
41 // Value.String()
43 // This method is provided only for debugging.
44 // It never appears in disassembly, which uses Value.Name().
46 func (v *Literal) String() string {
47 return fmt.Sprintf("literal %s rep=%T", v.Name(), v.Value)
50 func (v *Parameter) String() string {
51 return fmt.Sprintf("parameter %s : %s", v.Name(), v.Type())
54 func (v *Capture) String() string {
55 return fmt.Sprintf("capture %s : %s", v.Name(), v.Type())
58 func (v *Global) String() string {
59 return fmt.Sprintf("global %s : %s", v.Name(), v.Type())
62 func (v *Builtin) String() string {
63 return fmt.Sprintf("builtin %s : %s", v.Name(), v.Type())
66 func (r *Function) String() string {
67 return fmt.Sprintf("function %s : %s", r.Name(), r.Type())
70 // FullName returns the name of this function qualified by the
71 // package name, unless it is anonymous or synthetic.
73 // TODO(adonovan): move to func.go when it's submitted.
75 func (f *Function) FullName() string {
76 if f.Enclosing != nil || f.Pkg == nil {
77 return f.Name_ // anonymous or synthetic
79 return fmt.Sprintf("%s.%s", f.Pkg.ImportPath, f.Name_)
82 // FullName returns g's package-qualified name.
83 func (g *Global) FullName() string {
84 return fmt.Sprintf("%s.%s", g.Pkg.ImportPath, g.Name_)
87 // Instruction.String()
89 func (v *Alloc) String() string {
90 op := "local"
91 if v.Heap {
92 op = "new"
94 return fmt.Sprintf("%s %s", op, indirectType(v.Type()))
97 func (v *Phi) String() string {
98 var b bytes.Buffer
99 b.WriteString("phi [")
100 for i, edge := range v.Edges {
101 if i > 0 {
102 b.WriteString(", ")
104 // Be robust against malformed CFG.
105 blockname := "?"
106 if v.Block_ != nil && i < len(v.Block_.Preds) {
107 blockname = v.Block_.Preds[i].Name
109 b.WriteString(blockname)
110 b.WriteString(": ")
111 b.WriteString(relName(edge, v))
113 b.WriteString("]")
114 return b.String()
117 func printCall(v *CallCommon, prefix string, instr Instruction) string {
118 var b bytes.Buffer
119 b.WriteString(prefix)
120 if v.Func != nil {
121 b.WriteString(relName(v.Func, instr))
122 } else {
123 name := underlyingType(v.Recv.Type()).(*types.Interface).Methods[v.Method].Name
124 fmt.Fprintf(&b, "invoke %s.%s [#%d]", relName(v.Recv, instr), name, v.Method)
126 b.WriteString("(")
127 for i, arg := range v.Args {
128 if i > 0 {
129 b.WriteString(", ")
131 b.WriteString(relName(arg, instr))
133 if v.HasEllipsis {
134 b.WriteString("...")
136 b.WriteString(")")
137 return b.String()
140 func (v *Call) String() string {
141 return printCall(&v.CallCommon, "", v)
144 func (v *BinOp) String() string {
145 return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v))
148 func (v *UnOp) String() string {
149 return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk))
152 func (v *Conv) String() string {
153 return fmt.Sprintf("convert %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
156 func (v *ChangeInterface) String() string {
157 return fmt.Sprintf("change interface %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
160 func (v *MakeInterface) String() string {
161 return fmt.Sprintf("make interface %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
164 func (v *MakeClosure) String() string {
165 var b bytes.Buffer
166 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v))
167 if v.Bindings != nil {
168 b.WriteString(" [")
169 for i, c := range v.Bindings {
170 if i > 0 {
171 b.WriteString(", ")
173 b.WriteString(relName(c, v))
175 b.WriteString("]")
177 return b.String()
180 func (v *MakeSlice) String() string {
181 var b bytes.Buffer
182 b.WriteString("make slice ")
183 b.WriteString(v.Type().String())
184 b.WriteString(" ")
185 b.WriteString(relName(v.Len, v))
186 b.WriteString(" ")
187 b.WriteString(relName(v.Cap, v))
188 return b.String()
191 func (v *Slice) String() string {
192 var b bytes.Buffer
193 b.WriteString("slice ")
194 b.WriteString(relName(v.X, v))
195 b.WriteString("[")
196 if v.Low != nil {
197 b.WriteString(relName(v.Low, v))
199 b.WriteString(":")
200 if v.High != nil {
201 b.WriteString(relName(v.High, v))
203 b.WriteString("]")
204 return b.String()
207 func (v *MakeMap) String() string {
208 res := ""
209 if v.Reserve != nil {
210 res = relName(v.Reserve, v)
212 return fmt.Sprintf("make %s %s", v.Type(), res)
215 func (v *MakeChan) String() string {
216 return fmt.Sprintf("make %s %s", v.Type(), relName(v.Size, v))
219 func (v *FieldAddr) String() string {
220 fields := underlyingType(indirectType(v.X.Type())).(*types.Struct).Fields
221 // Be robust against a bad index.
222 name := "?"
223 if v.Field >= 0 && v.Field < len(fields) {
224 name = fields[v.Field].Name
226 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
229 func (v *Field) String() string {
230 fields := underlyingType(v.X.Type()).(*types.Struct).Fields
231 // Be robust against a bad index.
232 name := "?"
233 if v.Field >= 0 && v.Field < len(fields) {
234 name = fields[v.Field].Name
236 return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
239 func (v *IndexAddr) String() string {
240 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v))
243 func (v *Index) String() string {
244 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v))
247 func (v *Lookup) String() string {
248 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk))
251 func (v *Range) String() string {
252 return "range " + relName(v.X, v)
255 func (v *Next) String() string {
256 return "next " + relName(v.Iter, v)
259 func (v *TypeAssert) String() string {
260 return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), v.AssertedType)
263 func (v *Extract) String() string {
264 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index)
267 func (s *Jump) String() string {
268 // Be robust against malformed CFG.
269 blockname := "?"
270 if s.Block_ != nil && len(s.Block_.Succs) == 1 {
271 blockname = s.Block_.Succs[0].Name
273 return fmt.Sprintf("jump %s", blockname)
276 func (s *If) String() string {
277 // Be robust against malformed CFG.
278 tblockname, fblockname := "?", "?"
279 if s.Block_ != nil && len(s.Block_.Succs) == 2 {
280 tblockname = s.Block_.Succs[0].Name
281 fblockname = s.Block_.Succs[1].Name
283 return fmt.Sprintf("if %s goto %s else %s", relName(s.Cond, s), tblockname, fblockname)
286 func (s *Go) String() string {
287 return printCall(&s.CallCommon, "go ", s)
290 func (s *Ret) String() string {
291 var b bytes.Buffer
292 b.WriteString("ret")
293 for i, r := range s.Results {
294 if i == 0 {
295 b.WriteString(" ")
296 } else {
297 b.WriteString(", ")
299 b.WriteString(relName(r, s))
301 return b.String()
304 func (s *Send) String() string {
305 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s))
308 func (s *Defer) String() string {
309 return printCall(&s.CallCommon, "defer ", s)
312 func (s *Select) String() string {
313 var b bytes.Buffer
314 for i, st := range s.States {
315 if i > 0 {
316 b.WriteString(", ")
318 if st.Dir == ast.RECV {
319 b.WriteString("<-")
320 b.WriteString(relName(st.Chan, s))
321 } else {
322 b.WriteString(relName(st.Chan, s))
323 b.WriteString("<-")
324 b.WriteString(relName(st.Send, s))
327 non := ""
328 if !s.Blocking {
329 non = "non"
331 return fmt.Sprintf("select %sblocking [%s]", non, b.String())
334 func (s *Store) String() string {
335 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s))
338 func (s *MapUpdate) String() string {
339 return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
342 func (p *Package) String() string {
343 // TODO(adonovan): prettify output.
344 var b bytes.Buffer
345 fmt.Fprintf(&b, "Package %s at %s:\n", p.ImportPath, p.Prog.Files.File(p.Pos).Name())
347 // TODO(adonovan): make order deterministic.
348 maxname := 0
349 for name := range p.Members {
350 if l := len(name); l > maxname {
351 maxname = l
355 for name, mem := range p.Members {
356 switch mem := mem.(type) {
357 case *Literal:
358 fmt.Fprintf(&b, " const %-*s %s\n", maxname, name, mem.Name())
360 case *Function:
361 fmt.Fprintf(&b, " func %-*s %s\n", maxname, name, mem.Type())
363 case *Type:
364 fmt.Fprintf(&b, " type %-*s %s\n", maxname, name, mem.NamedType.Underlying)
365 // TODO(adonovan): make order deterministic.
366 for name, method := range mem.Methods {
367 fmt.Fprintf(&b, " method %s %s\n", name, method.Signature)
370 case *Global:
371 fmt.Fprintf(&b, " var %-*s %s\n", maxname, name, mem.Type())
375 return b.String()
378 func commaOk(x bool) string {
379 if x {
380 return ",ok"
382 return ""