Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / exp / ssa / print.go
1 package ssa
2
3 // This file implements the String() methods for all Value and
4 // Instruction types.
5
6 import (
7         "bytes"
8         "fmt"
9         "go/ast"
10         "go/types"
11 )
12
13 func (id Id) String() string {
14         if id.Pkg == nil {
15                 return id.Name
16         }
17         return fmt.Sprintf("%s/%s", id.Pkg.Path, id.Name)
18 }
19
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.
24 //
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()
30                 }
31                 return v.FullName()
32         case *Function:
33                 if v.Pkg == nil || v.Pkg == i.Block().Func.Pkg {
34                         return v.Name()
35                 }
36                 return v.FullName()
37         }
38         return v.Name()
39 }
40
41 // Value.String()
42 //
43 // This method is provided only for debugging.
44 // It never appears in disassembly, which uses Value.Name().
45
46 func (v *Literal) String() string {
47         return fmt.Sprintf("literal %s rep=%T", v.Name(), v.Value)
48 }
49
50 func (v *Parameter) String() string {
51         return fmt.Sprintf("parameter %s : %s", v.Name(), v.Type())
52 }
53
54 func (v *Capture) String() string {
55         return fmt.Sprintf("capture %s : %s", v.Name(), v.Type())
56 }
57
58 func (v *Global) String() string {
59         return fmt.Sprintf("global %s : %s", v.Name(), v.Type())
60 }
61
62 func (v *Builtin) String() string {
63         return fmt.Sprintf("builtin %s : %s", v.Name(), v.Type())
64 }
65
66 func (r *Function) String() string {
67         return fmt.Sprintf("function %s : %s", r.Name(), r.Type())
68 }
69
70 // FullName returns the name of this function qualified by the
71 // package name, unless it is anonymous or synthetic.
72 //
73 // TODO(adonovan): move to func.go when it's submitted.
74 //
75 func (f *Function) FullName() string {
76         if f.Enclosing != nil || f.Pkg == nil {
77                 return f.Name_ // anonymous or synthetic
78         }
79         return fmt.Sprintf("%s.%s", f.Pkg.ImportPath, f.Name_)
80 }
81
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_)
85 }
86
87 // Instruction.String()
88
89 func (v *Alloc) String() string {
90         op := "local"
91         if v.Heap {
92                 op = "new"
93         }
94         return fmt.Sprintf("%s %s", op, indirectType(v.Type()))
95 }
96
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(", ")
103                 }
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
108                 }
109                 b.WriteString(blockname)
110                 b.WriteString(": ")
111                 b.WriteString(relName(edge, v))
112         }
113         b.WriteString("]")
114         return b.String()
115 }
116
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)
125         }
126         b.WriteString("(")
127         for i, arg := range v.Args {
128                 if i > 0 {
129                         b.WriteString(", ")
130                 }
131                 b.WriteString(relName(arg, instr))
132         }
133         if v.HasEllipsis {
134                 b.WriteString("...")
135         }
136         b.WriteString(")")
137         return b.String()
138 }
139
140 func (v *Call) String() string {
141         return printCall(&v.CallCommon, "", v)
142 }
143
144 func (v *BinOp) String() string {
145         return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v))
146 }
147
148 func (v *UnOp) String() string {
149         return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk))
150 }
151
152 func (v *Conv) String() string {
153         return fmt.Sprintf("convert %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
154 }
155
156 func (v *ChangeInterface) String() string {
157         return fmt.Sprintf("change interface %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
158 }
159
160 func (v *MakeInterface) String() string {
161         return fmt.Sprintf("make interface %s <- %s (%s)", v.Type(), v.X.Type(), relName(v.X, v))
162 }
163
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(", ")
172                         }
173                         b.WriteString(relName(c, v))
174                 }
175                 b.WriteString("]")
176         }
177         return b.String()
178 }
179
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()
189 }
190
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))
198         }
199         b.WriteString(":")
200         if v.High != nil {
201                 b.WriteString(relName(v.High, 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         return fmt.Sprintf("make %s %s", v.Type(), res)
213 }
214
215 func (v *MakeChan) String() string {
216         return fmt.Sprintf("make %s %s", v.Type(), relName(v.Size, v))
217 }
218
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
225         }
226         return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
227 }
228
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
235         }
236         return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
237 }
238
239 func (v *IndexAddr) String() string {
240         return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v))
241 }
242
243 func (v *Index) String() string {
244         return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v))
245 }
246
247 func (v *Lookup) String() string {
248         return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk))
249 }
250
251 func (v *Range) String() string {
252         return "range " + relName(v.X, v)
253 }
254
255 func (v *Next) String() string {
256         return "next " + relName(v.Iter, v)
257 }
258
259 func (v *TypeAssert) String() string {
260         return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), v.AssertedType)
261 }
262
263 func (v *Extract) String() string {
264         return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index)
265 }
266
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
272         }
273         return fmt.Sprintf("jump %s", blockname)
274 }
275
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
282         }
283         return fmt.Sprintf("if %s goto %s else %s", relName(s.Cond, s), tblockname, fblockname)
284 }
285
286 func (s *Go) String() string {
287         return printCall(&s.CallCommon, "go ", s)
288 }
289
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(", ")
298                 }
299                 b.WriteString(relName(r, s))
300         }
301         return b.String()
302 }
303
304 func (s *Send) String() string {
305         return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s))
306 }
307
308 func (s *Defer) String() string {
309         return printCall(&s.CallCommon, "defer ", s)
310 }
311
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(", ")
317                 }
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))
325                 }
326         }
327         non := ""
328         if !s.Blocking {
329                 non = "non"
330         }
331         return fmt.Sprintf("select %sblocking [%s]", non, b.String())
332 }
333
334 func (s *Store) String() string {
335         return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s))
336 }
337
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))
340 }
341
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())
346
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
352                 }
353         }
354
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())
359
360                 case *Function:
361                         fmt.Fprintf(&b, " func  %-*s %s\n", maxname, name, mem.Type())
362
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)
368                         }
369
370                 case *Global:
371                         fmt.Fprintf(&b, " var   %-*s %s\n", maxname, name, mem.Type())
372
373                 }
374         }
375         return b.String()
376 }
377
378 func commaOk(x bool) string {
379         if x {
380                 return ",ok"
381         }
382         return ""
383 }