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 }