github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/noder/helpers.go (about)

     1  // Copyright 2021 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 noder
     6  
     7  import (
     8  	"go/constant"
     9  
    10  	"github.com/go-asm/go/cmd/compile/ir"
    11  	"github.com/go-asm/go/cmd/compile/syntax"
    12  	"github.com/go-asm/go/cmd/compile/typecheck"
    13  	"github.com/go-asm/go/cmd/compile/types"
    14  	"github.com/go-asm/go/cmd/compile/types2"
    15  	"github.com/go-asm/go/cmd/src"
    16  )
    17  
    18  // Helpers for constructing typed IR nodes.
    19  //
    20  // TODO(mdempsky): Move into their own package so they can be easily
    21  // reused by iimport and frontend optimizations.
    22  
    23  type ImplicitNode interface {
    24  	ir.Node
    25  	SetImplicit(x bool)
    26  }
    27  
    28  // Implicit returns n after marking it as Implicit.
    29  func Implicit(n ImplicitNode) ImplicitNode {
    30  	n.SetImplicit(true)
    31  	return n
    32  }
    33  
    34  // typed returns n after setting its type to typ.
    35  func typed(typ *types.Type, n ir.Node) ir.Node {
    36  	n.SetType(typ)
    37  	n.SetTypecheck(1)
    38  	return n
    39  }
    40  
    41  // Values
    42  
    43  // FixValue returns val after converting and truncating it as
    44  // appropriate for typ.
    45  func FixValue(typ *types.Type, val constant.Value) constant.Value {
    46  	assert(typ.Kind() != types.TFORW)
    47  	switch {
    48  	case typ.IsInteger():
    49  		val = constant.ToInt(val)
    50  	case typ.IsFloat():
    51  		val = constant.ToFloat(val)
    52  	case typ.IsComplex():
    53  		val = constant.ToComplex(val)
    54  	}
    55  	if !typ.IsUntyped() {
    56  		val = typecheck.ConvertVal(val, typ, false)
    57  	}
    58  	ir.AssertValidTypeForConst(typ, val)
    59  	return val
    60  }
    61  
    62  // Expressions
    63  
    64  func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
    65  	n := typecheck.NodAddrAt(pos, x)
    66  	typed(types.NewPtr(x.Type()), n)
    67  	return n
    68  }
    69  
    70  func Deref(pos src.XPos, typ *types.Type, x ir.Node) *ir.StarExpr {
    71  	n := ir.NewStarExpr(pos, x)
    72  	typed(typ, n)
    73  	return n
    74  }
    75  
    76  // Statements
    77  
    78  func idealType(tv syntax.TypeAndValue) types2.Type {
    79  	// The gc backend expects all expressions to have a concrete type, and
    80  	// types2 mostly satisfies this expectation already. But there are a few
    81  	// cases where the Go spec doesn't require converting to concrete type,
    82  	// and so types2 leaves them untyped. So we need to fix those up here.
    83  	typ := types2.Unalias(tv.Type)
    84  	if basic, ok := typ.(*types2.Basic); ok && basic.Info()&types2.IsUntyped != 0 {
    85  		switch basic.Kind() {
    86  		case types2.UntypedNil:
    87  			// ok; can appear in type switch case clauses
    88  			// TODO(mdempsky): Handle as part of type switches instead?
    89  		case types2.UntypedInt, types2.UntypedFloat, types2.UntypedComplex:
    90  			typ = types2.Typ[types2.Uint]
    91  			if tv.Value != nil {
    92  				s := constant.ToInt(tv.Value)
    93  				assert(s.Kind() == constant.Int)
    94  				if constant.Sign(s) < 0 {
    95  					typ = types2.Typ[types2.Int]
    96  				}
    97  			}
    98  		case types2.UntypedBool:
    99  			typ = types2.Typ[types2.Bool] // expression in "if" or "for" condition
   100  		case types2.UntypedString:
   101  			typ = types2.Typ[types2.String] // argument to "append" or "copy" calls
   102  		case types2.UntypedRune:
   103  			typ = types2.Typ[types2.Int32] // range over rune
   104  		default:
   105  			return nil
   106  		}
   107  	}
   108  	return typ
   109  }
   110  
   111  func isTypeParam(t types2.Type) bool {
   112  	_, ok := types2.Unalias(t).(*types2.TypeParam)
   113  	return ok
   114  }
   115  
   116  // isNotInHeap reports whether typ is or contains an element of type
   117  // runtime/github.com/go-asm/go/sys.NotInHeap.
   118  func isNotInHeap(typ types2.Type) bool {
   119  	typ = types2.Unalias(typ)
   120  	if named, ok := typ.(*types2.Named); ok {
   121  		if obj := named.Obj(); obj.Name() == "nih" && obj.Pkg().Path() == "runtime/github.com/go-asm/go/sys" {
   122  			return true
   123  		}
   124  		typ = named.Underlying()
   125  	}
   126  
   127  	switch typ := typ.(type) {
   128  	case *types2.Array:
   129  		return isNotInHeap(typ.Elem())
   130  	case *types2.Struct:
   131  		for i := 0; i < typ.NumFields(); i++ {
   132  			if isNotInHeap(typ.Field(i).Type()) {
   133  				return true
   134  			}
   135  		}
   136  		return false
   137  	default:
   138  		return false
   139  	}
   140  }