]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/walk/convert.go
99ca2522cf9217238a47bca262f4131c548f6d76
[gostls13.git] / src / cmd / compile / internal / walk / convert.go
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.
4
5 package walk
6
7 import (
8         "encoding/binary"
9         "go/constant"
10
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"
17         "cmd/internal/sys"
18 )
19
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() {
24                 return n.X
25         }
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)
29                 }
30         }
31         param, result := rtconvfn(n.X.Type(), n.Type())
32         if param == types.Txxx {
33                 return n
34         }
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())
37 }
38
39 // walkConvInterface walks an OCONVIFACE node.
40 func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
41
42         n.X = walkExpr(n.X, init)
43
44         fromType := n.X.Type()
45         toType := n.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
52                         // separately anyway.
53                 } else {
54                         reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
55                 }
56         }
57
58         if !fromType.IsInterface() {
59                 typeWord := reflectdata.ConvIfaceTypeWord(base.Pos, n)
60                 l := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, dataWord(n, init))
61                 l.SetType(toType)
62                 l.SetTypecheck(n.Typecheck())
63                 return l
64         }
65         if fromType.IsEmptyInterface() {
66                 base.Fatalf("OCONVIFACE can't operate on an empty interface")
67         }
68
69         // Evaluate the input interface.
70         c := typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
71         init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
72
73         // Grab its parts.
74         itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
75         itab.SetType(types.Types[types.TUINTPTR].PtrTo())
76         itab.SetTypecheck(1)
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.
79         data.SetTypecheck(1)
80
81         var typeWord ir.Node
82         if toType.IsEmptyInterface() {
83                 // Implement interface to empty interface conversion:
84                 //
85                 // var res *uint8
86                 // res = (*uint8)(unsafe.Pointer(itab))
87                 // if res != nil {
88                 //    res = res.type
89                 // }
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))}
94                 init.Append(nif)
95         } else {
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)
103         }
104
105         // Build the result.
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.
109         e.SetTypecheck(1)
110         return e
111 }
112
113 // Returns the data word (the second word) used to represent conv.X in
114 // an interface.
115 func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
116         pos, n := conv.Pos(), conv.X
117         fromType := n.Type()
118
119         // If it's a pointer, it is its own representation.
120         if types.IsDirectIface(fromType) {
121                 return n
122         }
123
124         isInteger := fromType.IsInteger()
125         isBool := fromType.IsBoolean()
126         if sc := fromType.SoleComponent(); sc != nil {
127                 isInteger = sc.IsInteger()
128                 isBool = sc.IsBoolean()
129         }
130         // Try a bunch of cases to avoid an allocation.
131         var value ir.Node
132         switch {
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))
146                 }
147                 // The actual type is [256]uint64, but we use [256*8]uint8 so we can address
148                 // individual bytes.
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)
151                 xe.SetBounded(true)
152                 value = xe
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.
155                 value = n
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)))
160         }
161         if value != nil {
162                 // The interface data word is &value.
163                 return typecheck.Expr(typecheck.NodAddr(value))
164         }
165
166         // Time to do an allocation. We'll call into the runtime for that.
167         fnname, argType, needsaddr := dataWordFuncName(fromType)
168         var fn *ir.Name
169
170         var args []ir.Node
171         if needsaddr {
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)
180                 }
181                 fn = typecheck.LookupRuntime(fnname, fromType)
182                 args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
183         } else {
184                 // Use a specialized conversion routine that takes the type being
185                 // converted by value, not by pointer.
186                 fn = typecheck.LookupRuntime(fnname)
187                 var arg ir.Node
188                 switch {
189                 case fromType == argType:
190                         // already in the right type, nothing to do
191                         arg = n
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)
200                 default:
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)
206                         arg.SetType(argType)
207                 }
208                 args = []ir.Node{arg}
209         }
210         call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
211         call.Args = args
212         return safeExpr(walkExpr(typecheck.Expr(call), init), init)
213 }
214
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])
221         }
222         if n.Op() == ir.ORUNES2STR {
223                 // slicerunetostring(*[32]byte, []rune) string
224                 return mkcall("slicerunetostring", n.Type(), init, a, n.X)
225         }
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)
230 }
231
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.
238                 return n
239         }
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)
244 }
245
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])
251         }
252         // intstring(*[4]byte, rune)
253         return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
254 }
255
256 // walkStringToBytes walks an OSTR2BYTES node.
257 func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
258         s := n.X
259         if ir.IsConst(s, constant.String) {
260                 sc := ir.StringVal(s)
261
262                 // Allocate a [n]byte of the right size.
263                 t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
264                 var a ir.Node
265                 if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
266                         a = stackBufAddr(t.NumElem(), t.Elem())
267                 } else {
268                         types.CalcSize(t)
269                         a = ir.NewUnaryExpr(base.Pos, ir.ONEW, nil)
270                         a.SetType(types.NewPtr(t))
271                         a.SetTypecheck(1)
272                         a.MarkNonNil()
273                 }
274                 p := typecheck.TempAt(base.Pos, ir.CurFunc, t.PtrTo()) // *[n]byte
275                 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
276
277                 // Copy from the static string data to the [n]byte.
278                 if len(sc) > 0 {
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)
283                 }
284
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)
290         }
291
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])
296         }
297         // stringtoslicebyte(*32[byte], string) []byte
298         return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
299 }
300
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)
311         return n
312 }
313
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])
320         }
321         // stringtoslicerune(*[32]rune, string) []rune
322         return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
323 }
324
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")
332         }
333         switch {
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
340         }
341         if sc := from.SoleComponent(); sc != nil {
342                 switch {
343                 case sc.IsString():
344                         return "convTstring", types.Types[types.TSTRING], false
345                 case sc.IsSlice():
346                         return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
347                 }
348         }
349
350         if from.HasPointers() {
351                 return "convT", types.Types[types.TUNSAFEPTR], true
352         }
353         return "convTnoptr", types.Types[types.TUNSAFEPTR], true
354 }
355
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.
359 //
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
364         }
365
366         switch ssagen.Arch.LinkArch.Family {
367         case sys.ARM, sys.MIPS:
368                 if src.IsFloat() {
369                         switch dst.Kind() {
370                         case types.TINT64, types.TUINT64:
371                                 return types.TFLOAT64, dst.Kind()
372                         }
373                 }
374                 if dst.IsFloat() {
375                         switch src.Kind() {
376                         case types.TINT64, types.TUINT64:
377                                 return src.Kind(), dst.Kind()
378                         }
379                 }
380
381         case sys.I386:
382                 if src.IsFloat() {
383                         switch 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
388                         }
389                 }
390                 if dst.IsFloat() {
391                         switch src.Kind() {
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
396                         }
397                 }
398         }
399         return types.Txxx, types.Txxx
400 }
401
402 func soleComponent(init *ir.Nodes, n ir.Node) ir.Node {
403         if n.Type().SoleComponent() == nil {
404                 return n
405         }
406         // Keep in sync with cmd/compile/internal/types/type.go:Type.SoleComponent.
407         for {
408                 switch {
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))
414                                 continue
415                         }
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)))
419                 default:
420                         return n
421                 }
422         }
423 }
424
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])
436                 n.SetTypecheck(1)
437         }
438         n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
439         n.SetType(types.Types[types.TINT])
440         n.SetTypecheck(1)
441         return n
442 }
443
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.
448         if n.CheckPtr() {
449                 return n
450         }
451         n.SetCheckPtr(true)
452         defer n.SetCheckPtr(false)
453
454         // TODO(mdempsky): Make stricter. We only need to exempt
455         // reflect.Value.Pointer and reflect.Value.UnsafeAddr.
456         switch n.X.Op() {
457         case ir.OCALLMETH:
458                 base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
459         case ir.OCALLFUNC, ir.OCALLINTER:
460                 return n
461         }
462
463         if n.X.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(n.X) {
464                 return n
465         }
466
467         // Find original unsafe.Pointer operands involved in this
468         // arithmetic expression.
469         //
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) {
476                 switch n.Op() {
477                 case ir.OADD:
478                         n := n.(*ir.BinaryExpr)
479                         walk(n.X)
480                         walk(n.Y)
481                 case ir.OSUB, ir.OANDNOT:
482                         n := n.(*ir.BinaryExpr)
483                         walk(n.X)
484                 case ir.OCONVNOP:
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]))
489                         }
490                 }
491         }
492         walk(n.X)
493
494         cheap := cheapExpr(n, init)
495
496         slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
497         slice.SetEsc(ir.EscNone)
498
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.
502
503         return cheap
504 }
505
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)
511
512         // The OSLICE2ARRPTR conversion handles checking the slice length,
513         // so the dereference can't fail.
514         //
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)
520
521         return walkExpr(deref, init)
522 }