1 // Copyright 2009 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.
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/reflectdata"
14 "cmd/compile/internal/ssagen"
15 "cmd/compile/internal/typecheck"
16 "cmd/compile/internal/types"
20 // walkConv walks an OCONV or OCONVNOP (but not OCONVIFACE) node.
21 func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
22 n.X = walkExpr(n.X, init)
23 if n.Op() == ir.OCONVNOP && n.Type() == n.X.Type() {
26 if n.Op() == ir.OCONVNOP && ir.ShouldCheckPtr(ir.CurFunc, 1) {
27 if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() { // uintptr to unsafe.Pointer
28 return walkCheckPtrArithmetic(n, init)
31 param, result := rtconvfn(n.X.Type(), n.Type())
32 if param == types.Txxx {
35 fn := types.BasicTypeNames[param] + "to" + types.BasicTypeNames[result]
36 return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
39 // walkConvInterface walks an OCONVIFACE node.
40 func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
42 n.X = walkExpr(n.X, init)
44 fromType := n.X.Type()
46 if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
47 // skip unnamed functions (func _())
48 if fromType.HasShape() {
49 // Unified IR uses OCONVIFACE for converting all derived types
50 // to interface type. Avoid assertion failure in
51 // MarkTypeUsedInInterface, because we've marked used types
54 reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
58 if !fromType.IsInterface() {
59 typeWord := reflectdata.ConvIfaceTypeWord(base.Pos, n)
60 l := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, dataWord(n, init))
62 l.SetTypecheck(n.Typecheck())
65 if fromType.IsEmptyInterface() {
66 base.Fatalf("OCONVIFACE can't operate on an empty interface")
69 // Evaluate the input interface.
70 c := typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
71 init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
74 itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
75 itab.SetType(types.Types[types.TUINTPTR].PtrTo())
77 data := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, c)
78 data.SetType(types.Types[types.TUINT8].PtrTo()) // Type is generic pointer - we're just passing it through.
82 if toType.IsEmptyInterface() {
83 // Implement interface to empty interface conversion:
86 // res = (*uint8)(unsafe.Pointer(itab))
90 typeWord = typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(types.Types[types.TUINT8]))
91 init.Append(ir.NewAssignStmt(base.Pos, typeWord, typecheck.Conv(typecheck.Conv(itab, types.Types[types.TUNSAFEPTR]), typeWord.Type())))
92 nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, typeWord, typecheck.NodNil())), nil, nil)
93 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, typeWord, itabType(typeWord))}
96 // Must be converting I2I (more specific to less specific interface).
97 // res = convI2I(toType, itab)
98 fn := typecheck.LookupRuntime("convI2I")
99 types.CalcSize(fn.Type())
100 call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
101 call.Args = []ir.Node{reflectdata.ConvIfaceTypeWord(base.Pos, n), itab}
102 typeWord = walkExpr(typecheck.Expr(call), init)
106 // e = iface{typeWord, data}
107 e := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, data)
108 e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
113 // Returns the data word (the second word) used to represent conv.X in
115 func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
116 pos, n := conv.Pos(), conv.X
119 // If it's a pointer, it is its own representation.
120 if types.IsDirectIface(fromType) {
124 isInteger := fromType.IsInteger()
125 isBool := fromType.IsBoolean()
126 if sc := fromType.SoleComponent(); sc != nil {
127 isInteger = sc.IsInteger()
128 isBool = sc.IsBoolean()
130 // Try a bunch of cases to avoid an allocation.
133 case fromType.Size() == 0:
134 // n is zero-sized. Use zerobase.
135 cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246.
136 value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
137 case isBool || fromType.Size() == 1 && isInteger:
138 // n is a bool/byte. Use staticuint64s[n * 8] on little-endian
139 // and staticuint64s[n * 8 + 7] on big-endian.
140 n = cheapExpr(n, init)
141 n = soleComponent(init, n)
142 // byteindex widens n so that the multiplication doesn't overflow.
143 index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(base.Pos, 3))
144 if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian {
145 index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(base.Pos, 7))
147 // The actual type is [256]uint64, but we use [256*8]uint8 so we can address
149 staticuint64s := ir.NewLinksymExpr(base.Pos, ir.Syms.Staticuint64s, types.NewArray(types.Types[types.TUINT8], 256*8))
150 xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
153 case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
154 // n is a readonly global; use it directly.
156 case conv.Esc() == ir.EscNone && fromType.Size() <= 1024:
157 // n does not escape. Use a stack temporary initialized to n.
158 value = typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
159 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
162 // The interface data word is &value.
163 return typecheck.Expr(typecheck.NodAddr(value))
166 // Time to do an allocation. We'll call into the runtime for that.
167 fnname, argType, needsaddr := dataWordFuncName(fromType)
172 // Types of large or unknown size are passed by reference.
173 // Orderexpr arranged for n to be a temporary for all
174 // the conversions it could see. Comparison of an interface
175 // with a non-interface, especially in a switch on interface value
176 // with non-interface cases, is not visible to order.stmt, so we
177 // have to fall back on allocating a temp here.
178 if !ir.IsAddressable(n) {
179 n = copyExpr(n, fromType, init)
181 fn = typecheck.LookupRuntime(fnname, fromType)
182 args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
184 // Use a specialized conversion routine that takes the type being
185 // converted by value, not by pointer.
186 fn = typecheck.LookupRuntime(fnname)
189 case fromType == argType:
190 // already in the right type, nothing to do
192 case fromType.Kind() == argType.Kind(),
193 fromType.IsPtrShaped() && argType.IsPtrShaped():
194 // can directly convert (e.g. named type to underlying type, or one pointer to another)
195 // TODO: never happens because pointers are directIface?
196 arg = ir.NewConvExpr(pos, ir.OCONVNOP, argType, n)
197 case fromType.IsInteger() && argType.IsInteger():
198 // can directly convert (e.g. int32 to uint32)
199 arg = ir.NewConvExpr(pos, ir.OCONV, argType, n)
201 // unsafe cast through memory
202 arg = copyExpr(n, fromType, init)
203 var addr ir.Node = typecheck.NodAddr(arg)
204 addr = ir.NewConvExpr(pos, ir.OCONVNOP, argType.PtrTo(), addr)
205 arg = ir.NewStarExpr(pos, addr)
208 args = []ir.Node{arg}
210 call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
212 return safeExpr(walkExpr(typecheck.Expr(call), init), init)
215 // walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node.
216 func walkBytesRunesToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
217 a := typecheck.NodNil()
218 if n.Esc() == ir.EscNone {
219 // Create temporary buffer for string on stack.
220 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
222 if n.Op() == ir.ORUNES2STR {
223 // slicerunetostring(*[32]byte, []rune) string
224 return mkcall("slicerunetostring", n.Type(), init, a, n.X)
226 // slicebytetostring(*[32]byte, ptr *byte, n int) string
227 n.X = cheapExpr(n.X, init)
228 ptr, len := backingArrayPtrLen(n.X)
229 return mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
232 // walkBytesToStringTemp walks an OBYTES2STRTMP node.
233 func walkBytesToStringTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
234 n.X = walkExpr(n.X, init)
235 if !base.Flag.Cfg.Instrumenting {
236 // Let the backend handle OBYTES2STRTMP directly
237 // to avoid a function call to slicebytetostringtmp.
240 // slicebytetostringtmp(ptr *byte, n int) string
241 n.X = cheapExpr(n.X, init)
242 ptr, len := backingArrayPtrLen(n.X)
243 return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
246 // walkRuneToString walks an ORUNESTR node.
247 func walkRuneToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
248 a := typecheck.NodNil()
249 if n.Esc() == ir.EscNone {
250 a = stackBufAddr(4, types.Types[types.TUINT8])
252 // intstring(*[4]byte, rune)
253 return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
256 // walkStringToBytes walks an OSTR2BYTES node.
257 func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
259 if ir.IsConst(s, constant.String) {
260 sc := ir.StringVal(s)
262 // Allocate a [n]byte of the right size.
263 t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
265 if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
266 a = stackBufAddr(t.NumElem(), t.Elem())
269 a = ir.NewUnaryExpr(base.Pos, ir.ONEW, nil)
270 a.SetType(types.NewPtr(t))
274 p := typecheck.TempAt(base.Pos, ir.CurFunc, t.PtrTo()) // *[n]byte
275 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
277 // Copy from the static string data to the [n]byte.
279 sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
280 sptr.SetBounded(true)
281 as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
282 appendWalkStmt(init, as)
285 // Slice the [n]byte to a []byte.
286 slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
287 slice.SetType(n.Type())
288 slice.SetTypecheck(1)
289 return walkExpr(slice, init)
292 a := typecheck.NodNil()
293 if n.Esc() == ir.EscNone {
294 // Create temporary buffer for slice on stack.
295 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
297 // stringtoslicebyte(*32[byte], string) []byte
298 return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
301 // walkStringToBytesTemp walks an OSTR2BYTESTMP node.
302 func walkStringToBytesTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
303 // []byte(string) conversion that creates a slice
304 // referring to the actual string bytes.
305 // This conversion is handled later by the backend and
306 // is only for use by internal compiler optimizations
307 // that know that the slice won't be mutated.
308 // The only such case today is:
309 // for i, c := range []byte(string)
310 n.X = walkExpr(n.X, init)
314 // walkStringToRunes walks an OSTR2RUNES node.
315 func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
316 a := typecheck.NodNil()
317 if n.Esc() == ir.EscNone {
318 // Create temporary buffer for slice on stack.
319 a = stackBufAddr(tmpstringbufsize, types.Types[types.TINT32])
321 // stringtoslicerune(*[32]rune, string) []rune
322 return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
325 // dataWordFuncName returns the name of the function used to convert a value of type "from"
326 // to the data word of an interface.
327 // argType is the type the argument needs to be coerced to.
328 // needsaddr reports whether the value should be passed (needaddr==false) or its address (needsaddr==true).
329 func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
330 if from.IsInterface() {
331 base.Fatalf("can only handle non-interfaces")
334 case from.Size() == 2 && uint8(from.Alignment()) == 2:
335 return "convT16", types.Types[types.TUINT16], false
336 case from.Size() == 4 && uint8(from.Alignment()) == 4 && !from.HasPointers():
337 return "convT32", types.Types[types.TUINT32], false
338 case from.Size() == 8 && uint8(from.Alignment()) == uint8(types.Types[types.TUINT64].Alignment()) && !from.HasPointers():
339 return "convT64", types.Types[types.TUINT64], false
341 if sc := from.SoleComponent(); sc != nil {
344 return "convTstring", types.Types[types.TSTRING], false
346 return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
350 if from.HasPointers() {
351 return "convT", types.Types[types.TUNSAFEPTR], true
353 return "convTnoptr", types.Types[types.TUNSAFEPTR], true
356 // rtconvfn returns the parameter and result types that will be used by a
357 // runtime function to convert from type src to type dst. The runtime function
358 // name can be derived from the names of the returned types.
360 // If no such function is necessary, it returns (Txxx, Txxx).
361 func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
362 if ssagen.Arch.SoftFloat {
363 return types.Txxx, types.Txxx
366 switch ssagen.Arch.LinkArch.Family {
367 case sys.ARM, sys.MIPS:
370 case types.TINT64, types.TUINT64:
371 return types.TFLOAT64, dst.Kind()
376 case types.TINT64, types.TUINT64:
377 return src.Kind(), dst.Kind()
384 case types.TINT64, types.TUINT64:
385 return types.TFLOAT64, dst.Kind()
386 case types.TUINT32, types.TUINT, types.TUINTPTR:
387 return types.TFLOAT64, types.TUINT32
392 case types.TINT64, types.TUINT64:
393 return src.Kind(), dst.Kind()
394 case types.TUINT32, types.TUINT, types.TUINTPTR:
395 return types.TUINT32, types.TFLOAT64
399 return types.Txxx, types.Txxx
402 func soleComponent(init *ir.Nodes, n ir.Node) ir.Node {
403 if n.Type().SoleComponent() == nil {
406 // Keep in sync with cmd/compile/internal/types/type.go:Type.SoleComponent.
409 case n.Type().IsStruct():
410 if n.Type().Field(0).Sym.IsBlank() {
411 // Treat blank fields as the zero value as the Go language requires.
412 n = typecheck.TempAt(base.Pos, ir.CurFunc, n.Type().Field(0).Type)
413 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil))
416 n = typecheck.DotField(n.Pos(), n, 0)
417 case n.Type().IsArray():
418 n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(base.Pos, 0)))
425 // byteindex converts n, which is byte-sized, to an int used to index into an array.
426 // We cannot use conv, because we allow converting bool to int here,
427 // which is forbidden in user code.
428 func byteindex(n ir.Node) ir.Node {
429 // We cannot convert from bool to int directly.
430 // While converting from int8 to int is possible, it would yield
431 // the wrong result for negative values.
432 // Reinterpreting the value as an unsigned byte solves both cases.
433 if !types.Identical(n.Type(), types.Types[types.TUINT8]) {
434 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
435 n.SetType(types.Types[types.TUINT8])
438 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
439 n.SetType(types.Types[types.TINT])
444 func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
445 // Calling cheapExpr(n, init) below leads to a recursive call to
446 // walkExpr, which leads us back here again. Use n.Checkptr to
447 // prevent infinite loops.
452 defer n.SetCheckPtr(false)
454 // TODO(mdempsky): Make stricter. We only need to exempt
455 // reflect.Value.Pointer and reflect.Value.UnsafeAddr.
458 base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
459 case ir.OCALLFUNC, ir.OCALLINTER:
463 if n.X.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(n.X) {
467 // Find original unsafe.Pointer operands involved in this
468 // arithmetic expression.
470 // "It is valid both to add and to subtract offsets from a
471 // pointer in this way. It is also valid to use &^ to round
472 // pointers, usually for alignment."
473 var originals []ir.Node
474 var walk func(n ir.Node)
475 walk = func(n ir.Node) {
478 n := n.(*ir.BinaryExpr)
481 case ir.OSUB, ir.OANDNOT:
482 n := n.(*ir.BinaryExpr)
485 n := n.(*ir.ConvExpr)
486 if n.X.Type().IsUnsafePtr() {
487 n.X = cheapExpr(n.X, init)
488 originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
494 cheap := cheapExpr(n, init)
496 slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
497 slice.SetEsc(ir.EscNone)
499 init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
500 // TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
501 // the backing store for multiple calls to checkptrArithmetic.
506 // walkSliceToArray walks an OSLICE2ARR expression.
507 func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
508 // Replace T(x) with *(*T)(x).
509 conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr)
510 deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr)
512 // The OSLICE2ARRPTR conversion handles checking the slice length,
513 // so the dereference can't fail.
515 // However, this is more than just an optimization: if T is a
516 // zero-length array, then x (and thus (*T)(x)) can be nil, but T(x)
517 // should *not* panic. So suppressing the nil check here is
518 // necessary for correctness in that case.
519 deref.SetBounded(true)
521 return walkExpr(deref, init)