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  }