github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/ir/emit.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 ir
     6  
     7  // Helpers for emitting IR instructions.
     8  
     9  import (
    10  	"fmt"
    11  	"go/ast"
    12  	"go/constant"
    13  	"go/token"
    14  	"go/types"
    15  
    16  	"github.com/amarpal/go-tools/go/types/typeutil"
    17  
    18  	"golang.org/x/exp/typeparams"
    19  )
    20  
    21  // emitNew emits to f a new (heap Alloc) instruction allocating an
    22  // object of type typ.  pos is the optional source location.
    23  func emitNew(f *Function, typ types.Type, source ast.Node) *Alloc {
    24  	v := &Alloc{Heap: true}
    25  	v.setType(types.NewPointer(typ))
    26  	f.emit(v, source)
    27  	return v
    28  }
    29  
    30  // emitLoad emits to f an instruction to load the address addr into a
    31  // new temporary, and returns the value so defined.
    32  func emitLoad(f *Function, addr Value, source ast.Node) *Load {
    33  	v := &Load{X: addr}
    34  	v.setType(deref(addr.Type()))
    35  	f.emit(v, source)
    36  	return v
    37  }
    38  
    39  func emitRecv(f *Function, ch Value, commaOk bool, typ types.Type, source ast.Node) Value {
    40  	recv := &Recv{
    41  		Chan:    ch,
    42  		CommaOk: commaOk,
    43  	}
    44  	recv.setType(typ)
    45  	return f.emit(recv, source)
    46  }
    47  
    48  // emitDebugRef emits to f a DebugRef pseudo-instruction associating
    49  // expression e with value v.
    50  func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
    51  	ref := makeDebugRef(f, e, v, isAddr)
    52  	if ref == nil {
    53  		return
    54  	}
    55  	f.emit(ref, nil)
    56  }
    57  
    58  func makeDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) *DebugRef {
    59  	if !f.debugInfo() {
    60  		return nil // debugging not enabled
    61  	}
    62  	if v == nil || e == nil {
    63  		panic("nil")
    64  	}
    65  	var obj types.Object
    66  	e = unparen(e)
    67  	if id, ok := e.(*ast.Ident); ok {
    68  		if isBlankIdent(id) {
    69  			return nil
    70  		}
    71  		obj = f.Pkg.objectOf(id)
    72  		switch obj.(type) {
    73  		case *types.Nil, *types.Const, *types.Builtin:
    74  			return nil
    75  		}
    76  	}
    77  	return &DebugRef{
    78  		X:      v,
    79  		Expr:   e,
    80  		IsAddr: isAddr,
    81  		object: obj,
    82  	}
    83  }
    84  
    85  // emitArith emits to f code to compute the binary operation op(x, y)
    86  // where op is an eager shift, logical or arithmetic operation.
    87  // (Use emitCompare() for comparisons and Builder.logicalBinop() for
    88  // non-eager operations.)
    89  func emitArith(f *Function, op token.Token, x, y Value, t types.Type, source ast.Node) Value {
    90  	switch op {
    91  	case token.SHL, token.SHR:
    92  		x = emitConv(f, x, t, source)
    93  		// y may be signed or an 'untyped' constant.
    94  		// There is a runtime panic if y is signed and <0. Instead of inserting a check for y<0
    95  		// and converting to an unsigned value (like the compiler) leave y as is.
    96  		if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
    97  			// Untyped conversion:
    98  			// Spec https://go.dev/ref/spec#Operators:
    99  			// The right operand in a shift expression must have integer type or be an untyped constant
   100  			// representable by a value of type uint.
   101  			y = emitConv(f, y, types.Typ[types.Uint], source)
   102  		}
   103  
   104  	case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
   105  		x = emitConv(f, x, t, source)
   106  		y = emitConv(f, y, t, source)
   107  
   108  	default:
   109  		panic("illegal op in emitArith: " + op.String())
   110  
   111  	}
   112  	v := &BinOp{
   113  		Op: op,
   114  		X:  x,
   115  		Y:  y,
   116  	}
   117  	v.setType(t)
   118  	return f.emit(v, source)
   119  }
   120  
   121  // emitCompare emits to f code compute the boolean result of
   122  // comparison comparison 'x op y'.
   123  func emitCompare(f *Function, op token.Token, x, y Value, source ast.Node) Value {
   124  	xt := x.Type().Underlying()
   125  	yt := y.Type().Underlying()
   126  
   127  	// Special case to optimise a tagless SwitchStmt so that
   128  	// these are equivalent
   129  	//   switch { case e: ...}
   130  	//   switch true { case e: ... }
   131  	//   if e==true { ... }
   132  	// even in the case when e's type is an interface.
   133  	// TODO(adonovan): opt: generalise to x==true, false!=y, etc.
   134  	if x, ok := x.(*Const); ok && op == token.EQL && x.Value != nil && x.Value.Kind() == constant.Bool && constant.BoolVal(x.Value) {
   135  		if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 {
   136  			return y
   137  		}
   138  	}
   139  
   140  	if types.Identical(xt, yt) {
   141  		// no conversion necessary
   142  	} else if _, ok := xt.(*types.Interface); ok && !typeparams.IsTypeParam(x.Type()) {
   143  		y = emitConv(f, y, x.Type(), source)
   144  	} else if _, ok := yt.(*types.Interface); ok && !typeparams.IsTypeParam(y.Type()) {
   145  		x = emitConv(f, x, y.Type(), source)
   146  	} else if _, ok := x.(*Const); ok {
   147  		x = emitConv(f, x, y.Type(), source)
   148  	} else if _, ok := y.(*Const); ok {
   149  		y = emitConv(f, y, x.Type(), source)
   150  		//lint:ignore SA9003 no-op
   151  	} else {
   152  		// other cases, e.g. channels.  No-op.
   153  	}
   154  
   155  	v := &BinOp{
   156  		Op: op,
   157  		X:  x,
   158  		Y:  y,
   159  	}
   160  	v.setType(tBool)
   161  	return f.emit(v, source)
   162  }
   163  
   164  // isValuePreserving returns true if a conversion from ut_src to
   165  // ut_dst is value-preserving, i.e. just a change of type.
   166  // Precondition: neither argument is a named type.
   167  func isValuePreserving(ut_src, ut_dst types.Type) bool {
   168  	// Identical underlying types?
   169  	if types.IdenticalIgnoreTags(ut_dst, ut_src) {
   170  		return true
   171  	}
   172  
   173  	switch ut_dst.(type) {
   174  	case *types.Chan:
   175  		// Conversion between channel types?
   176  		_, ok := ut_src.(*types.Chan)
   177  		return ok
   178  
   179  	case *types.Pointer:
   180  		// Conversion between pointers with identical base types?
   181  		_, ok := ut_src.(*types.Pointer)
   182  		return ok
   183  	}
   184  	return false
   185  }
   186  
   187  // emitConv emits to f code to convert Value val to exactly type typ,
   188  // and returns the converted value.  Implicit conversions are required
   189  // by language assignability rules in assignments, parameter passing,
   190  // etc.
   191  func emitConv(f *Function, val Value, t_dst types.Type, source ast.Node) Value {
   192  	t_src := val.Type()
   193  
   194  	// Identical types?  Conversion is a no-op.
   195  	if types.Identical(t_src, t_dst) {
   196  		return val
   197  	}
   198  
   199  	ut_dst := t_dst.Underlying()
   200  	ut_src := t_src.Underlying()
   201  
   202  	tset_dst := typeutil.NewTypeSet(ut_dst)
   203  	tset_src := typeutil.NewTypeSet(ut_src)
   204  
   205  	// Just a change of type, but not value or representation?
   206  	if tset_src.All(func(termSrc *types.Term) bool {
   207  		return tset_dst.All(func(termDst *types.Term) bool {
   208  			return isValuePreserving(termSrc.Type().Underlying(), termDst.Type().Underlying())
   209  		})
   210  	}) {
   211  		c := &ChangeType{X: val}
   212  		c.setType(t_dst)
   213  		return f.emit(c, source)
   214  	}
   215  
   216  	// Conversion to, or construction of a value of, an interface type?
   217  	if _, ok := ut_dst.(*types.Interface); ok && !typeparams.IsTypeParam(t_dst) {
   218  		// Assignment from one interface type to another?
   219  		if _, ok := ut_src.(*types.Interface); ok && !typeparams.IsTypeParam(t_src) {
   220  			c := &ChangeInterface{X: val}
   221  			c.setType(t_dst)
   222  			return f.emit(c, source)
   223  		}
   224  
   225  		// Untyped nil constant?  Return interface-typed nil constant.
   226  		if ut_src == tUntypedNil {
   227  			return emitConst(f, nilConst(t_dst, source))
   228  		}
   229  
   230  		// Convert (non-nil) "untyped" literals to their default type.
   231  		if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 {
   232  			val = emitConv(f, val, types.Default(ut_src), source)
   233  		}
   234  
   235  		f.Pkg.Prog.needMethodsOf(val.Type())
   236  		mi := &MakeInterface{X: val}
   237  		mi.setType(t_dst)
   238  		return f.emit(mi, source)
   239  	}
   240  
   241  	// Conversion of a compile-time constant value? Note that converting a constant to a type parameter never results in
   242  	// a constant value.
   243  	if c, ok := val.(*Const); ok {
   244  		if _, ok := ut_dst.(*types.Basic); ok || c.IsNil() {
   245  			// Conversion of a compile-time constant to
   246  			// another constant type results in a new
   247  			// constant of the destination type and
   248  			// (initially) the same abstract value.
   249  			// We don't truncate the value yet.
   250  			return emitConst(f, NewConst(c.Value, t_dst, source))
   251  		}
   252  
   253  		// We're converting from constant to non-constant type,
   254  		// e.g. string -> []byte/[]rune.
   255  	}
   256  
   257  	// Conversion from slice to array pointer?
   258  	if tset_src.All(func(termSrc *types.Term) bool {
   259  		return tset_dst.All(func(termDst *types.Term) bool {
   260  			if slice, ok := termSrc.Type().Underlying().(*types.Slice); ok {
   261  				if ptr, ok := termDst.Type().Underlying().(*types.Pointer); ok {
   262  					if arr, ok := ptr.Elem().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
   263  						return true
   264  					}
   265  				}
   266  			}
   267  			return false
   268  		})
   269  	}) {
   270  		c := &SliceToArrayPointer{X: val}
   271  		c.setType(t_dst)
   272  		return f.emit(c, source)
   273  	}
   274  
   275  	// Conversion from slice to array. This is almost the same as converting from slice to array pointer, then
   276  	// dereferencing the pointer. Except that a nil slice can be converted to [0]T, whereas converting a nil slice to
   277  	// (*[0]T) results in a nil pointer, dereferencing which would panic. To hide the extra branching we use a dedicated
   278  	// instruction, SliceToArray.
   279  	if tset_src.All(func(termSrc *types.Term) bool {
   280  		return tset_dst.All(func(termDst *types.Term) bool {
   281  			if slice, ok := termSrc.Type().Underlying().(*types.Slice); ok {
   282  				if arr, ok := termDst.Type().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
   283  					return true
   284  				}
   285  			}
   286  			return false
   287  		})
   288  	}) {
   289  		c := &SliceToArray{X: val}
   290  		c.setType(t_dst)
   291  		return f.emit(c, source)
   292  	}
   293  
   294  	// A representation-changing conversion?
   295  	// At least one of {ut_src,ut_dst} must be *Basic.
   296  	// (The other may be []byte or []rune.)
   297  	ok1 := tset_src.Any(func(term *types.Term) bool { _, ok := term.Type().Underlying().(*types.Basic); return ok })
   298  	ok2 := tset_dst.Any(func(term *types.Term) bool { _, ok := term.Type().Underlying().(*types.Basic); return ok })
   299  	if ok1 || ok2 {
   300  		c := &Convert{X: val}
   301  		c.setType(t_dst)
   302  		return f.emit(c, source)
   303  	}
   304  
   305  	panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), t_dst))
   306  }
   307  
   308  // emitStore emits to f an instruction to store value val at location
   309  // addr, applying implicit conversions as required by assignability rules.
   310  func emitStore(f *Function, addr, val Value, source ast.Node) *Store {
   311  	s := &Store{
   312  		Addr: addr,
   313  		Val:  emitConv(f, val, deref(addr.Type()), source),
   314  	}
   315  	f.emit(s, source)
   316  	return s
   317  }
   318  
   319  // emitJump emits to f a jump to target, and updates the control-flow graph.
   320  // Postcondition: f.currentBlock is nil.
   321  func emitJump(f *Function, target *BasicBlock, source ast.Node) *Jump {
   322  	b := f.currentBlock
   323  	j := new(Jump)
   324  	b.emit(j, source)
   325  	addEdge(b, target)
   326  	f.currentBlock = nil
   327  	return j
   328  }
   329  
   330  // emitIf emits to f a conditional jump to tblock or fblock based on
   331  // cond, and updates the control-flow graph.
   332  // Postcondition: f.currentBlock is nil.
   333  func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock, source ast.Node) *If {
   334  	b := f.currentBlock
   335  	stmt := &If{Cond: cond}
   336  	b.emit(stmt, source)
   337  	addEdge(b, tblock)
   338  	addEdge(b, fblock)
   339  	f.currentBlock = nil
   340  	return stmt
   341  }
   342  
   343  // emitExtract emits to f an instruction to extract the index'th
   344  // component of tuple.  It returns the extracted value.
   345  func emitExtract(f *Function, tuple Value, index int, source ast.Node) Value {
   346  	e := &Extract{Tuple: tuple, Index: index}
   347  	e.setType(tuple.Type().(*types.Tuple).At(index).Type())
   348  	return f.emit(e, source)
   349  }
   350  
   351  // emitTypeAssert emits to f a type assertion value := x.(t) and
   352  // returns the value.  x.Type() must be an interface.
   353  func emitTypeAssert(f *Function, x Value, t types.Type, source ast.Node) Value {
   354  	a := &TypeAssert{X: x, AssertedType: t}
   355  	a.setType(t)
   356  	return f.emit(a, source)
   357  }
   358  
   359  // emitTypeTest emits to f a type test value,ok := x.(t) and returns
   360  // a (value, ok) tuple.  x.Type() must be an interface.
   361  func emitTypeTest(f *Function, x Value, t types.Type, source ast.Node) Value {
   362  	a := &TypeAssert{
   363  		X:            x,
   364  		AssertedType: t,
   365  		CommaOk:      true,
   366  	}
   367  	a.setType(types.NewTuple(
   368  		newVar("value", t),
   369  		varOk,
   370  	))
   371  	return f.emit(a, source)
   372  }
   373  
   374  // emitTailCall emits to f a function call in tail position.  The
   375  // caller is responsible for all fields of 'call' except its type.
   376  // Intended for wrapper methods.
   377  // Precondition: f does/will not use deferred procedure calls.
   378  // Postcondition: f.currentBlock is nil.
   379  func emitTailCall(f *Function, call *Call, source ast.Node) {
   380  	tresults := f.Signature.Results()
   381  	nr := tresults.Len()
   382  	if nr == 1 {
   383  		call.typ = tresults.At(0).Type()
   384  	} else {
   385  		call.typ = tresults
   386  	}
   387  	tuple := f.emit(call, source)
   388  	var ret Return
   389  	switch nr {
   390  	case 0:
   391  		// no-op
   392  	case 1:
   393  		ret.Results = []Value{tuple}
   394  	default:
   395  		for i := 0; i < nr; i++ {
   396  			v := emitExtract(f, tuple, i, source)
   397  			// TODO(adonovan): in principle, this is required:
   398  			//   v = emitConv(f, o.Type, f.Signature.Results[i].Type)
   399  			// but in practice emitTailCall is only used when
   400  			// the types exactly match.
   401  			ret.Results = append(ret.Results, v)
   402  		}
   403  	}
   404  
   405  	f.Exit = f.newBasicBlock("exit")
   406  	emitJump(f, f.Exit, source)
   407  	f.currentBlock = f.Exit
   408  	f.emit(&ret, source)
   409  	f.currentBlock = nil
   410  }
   411  
   412  // emitImplicitSelections emits to f code to apply the sequence of
   413  // implicit field selections specified by indices to base value v, and
   414  // returns the selected value.
   415  //
   416  // If v is the address of a struct, the result will be the address of
   417  // a field; if it is the value of a struct, the result will be the
   418  // value of a field.
   419  func emitImplicitSelections(f *Function, v Value, indices []int, source ast.Node) Value {
   420  	for _, index := range indices {
   421  		// We may have a generic type containing a pointer, or a pointer to a generic type containing a struct. A
   422  		// pointer to a generic containing a pointer to a struct shouldn't be possible because the outer pointer gets
   423  		// dereferenced implicitly before we get here.
   424  		fld := typeutil.CoreType(deref(v.Type())).Underlying().(*types.Struct).Field(index)
   425  
   426  		if isPointer(v.Type()) {
   427  			instr := &FieldAddr{
   428  				X:     v,
   429  				Field: index,
   430  			}
   431  			instr.setType(types.NewPointer(fld.Type()))
   432  			v = f.emit(instr, source)
   433  			// Load the field's value iff indirectly embedded.
   434  			if isPointer(fld.Type()) {
   435  				v = emitLoad(f, v, source)
   436  			}
   437  		} else {
   438  			instr := &Field{
   439  				X:     v,
   440  				Field: index,
   441  			}
   442  			instr.setType(fld.Type())
   443  			v = f.emit(instr, source)
   444  		}
   445  	}
   446  	return v
   447  }
   448  
   449  // emitFieldSelection emits to f code to select the index'th field of v.
   450  //
   451  // If wantAddr, the input must be a pointer-to-struct and the result
   452  // will be the field's address; otherwise the result will be the
   453  // field's value.
   454  // Ident id is used for position and debug info.
   455  func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
   456  	// We may have a generic type containing a pointer, or a pointer to a generic type containing a struct. A
   457  	// pointer to a generic containing a pointer to a struct shouldn't be possible because the outer pointer gets
   458  	// dereferenced implicitly before we get here.
   459  	vut := typeutil.CoreType(deref(v.Type())).Underlying().(*types.Struct)
   460  	fld := vut.Field(index)
   461  	if isPointer(v.Type()) {
   462  		instr := &FieldAddr{
   463  			X:     v,
   464  			Field: index,
   465  		}
   466  		instr.setSource(id)
   467  		instr.setType(types.NewPointer(fld.Type()))
   468  		v = f.emit(instr, id)
   469  		// Load the field's value iff we don't want its address.
   470  		if !wantAddr {
   471  			v = emitLoad(f, v, id)
   472  		}
   473  	} else {
   474  		instr := &Field{
   475  			X:     v,
   476  			Field: index,
   477  		}
   478  		instr.setSource(id)
   479  		instr.setType(fld.Type())
   480  		v = f.emit(instr, id)
   481  	}
   482  	emitDebugRef(f, id, v, wantAddr)
   483  	return v
   484  }
   485  
   486  // zeroValue emits to f code to produce a zero value of type t,
   487  // and returns it.
   488  func zeroValue(f *Function, t types.Type, source ast.Node) Value {
   489  	return emitConst(f, zeroConst(t, source))
   490  }
   491  
   492  type constKey struct {
   493  	typ    types.Type
   494  	value  constant.Value
   495  	source ast.Node
   496  }
   497  
   498  func emitConst(f *Function, c Constant) Constant {
   499  	if f.consts == nil {
   500  		f.consts = map[constKey]constValue{}
   501  	}
   502  
   503  	typ := c.Type()
   504  	var val constant.Value
   505  	switch c := c.(type) {
   506  	case *Const:
   507  		val = c.Value
   508  	case *ArrayConst, *GenericConst:
   509  		// These can only represent zero values, so all we need is the type
   510  	case *AggregateConst:
   511  		candidates, _ := f.aggregateConsts.At(c.typ)
   512  		for _, candidate := range candidates {
   513  			if c.equal(candidate) {
   514  				return candidate
   515  			}
   516  		}
   517  
   518  		for i := range c.Values {
   519  			c.Values[i] = emitConst(f, c.Values[i].(Constant))
   520  		}
   521  
   522  		c.setBlock(f.Blocks[0])
   523  		rands := c.Operands(nil)
   524  		updateOperandsReferrers(c, rands)
   525  		candidates = append(candidates, c)
   526  		f.aggregateConsts.Set(c.typ, candidates)
   527  		return c
   528  
   529  	default:
   530  		panic(fmt.Sprintf("unexpected type %T", c))
   531  	}
   532  	k := constKey{
   533  		typ:    typ,
   534  		value:  val,
   535  		source: c.Source(),
   536  	}
   537  	dup, ok := f.consts[k]
   538  	if ok {
   539  		return dup.c
   540  	} else {
   541  		c.setBlock(f.Blocks[0])
   542  		f.consts[k] = constValue{
   543  			c:   c,
   544  			idx: len(f.consts),
   545  		}
   546  		rands := c.Operands(nil)
   547  		updateOperandsReferrers(c, rands)
   548  		return c
   549  	}
   550  }