1
2
3
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
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() {
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
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
48 if fromType.HasShape() {
49
50
51
52
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
70 c := typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
71 init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
72
73 if toType.IsEmptyInterface() {
74
75
76
77
78
79
80
81
82
83 itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
84 itab.SetType(types.Types[types.TUINTPTR].PtrTo())
85 itab.SetTypecheck(1)
86 data := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, c)
87 data.SetType(types.Types[types.TUINT8].PtrTo())
88 data.SetTypecheck(1)
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
96
97
98 e := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, data)
99 e.SetType(toType)
100 e.SetTypecheck(1)
101 return e
102 }
103
104
105
106 var rhs ir.Node
107 if n.TypeWord == nil || n.TypeWord.Op() == ir.OADDR && n.TypeWord.(*ir.AddrExpr).X.Op() == ir.OLINKSYMOFFSET {
108
109 ta := ir.NewTypeAssertExpr(base.Pos, c, toType)
110 ta.SetOp(ir.ODOTTYPE2)
111
112 ta.Descriptor = makeTypeAssertDescriptor(toType, true)
113 rhs = ta
114 } else {
115 ta := ir.NewDynamicTypeAssertExpr(base.Pos, ir.ODYNAMICDOTTYPE2, c, n.TypeWord)
116 rhs = ta
117 }
118 rhs.SetType(toType)
119 rhs.SetTypecheck(1)
120
121 res := typecheck.TempAt(base.Pos, ir.CurFunc, toType)
122 as := ir.NewAssignListStmt(base.Pos, ir.OAS2DOTTYPE, []ir.Node{res, ir.BlankNode}, []ir.Node{rhs})
123 init.Append(as)
124 return res
125 }
126
127
128
129 func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
130 pos, n := conv.Pos(), conv.X
131 fromType := n.Type()
132
133
134 if types.IsDirectIface(fromType) {
135 return n
136 }
137
138 isInteger := fromType.IsInteger()
139 isBool := fromType.IsBoolean()
140 if sc := fromType.SoleComponent(); sc != nil {
141 isInteger = sc.IsInteger()
142 isBool = sc.IsBoolean()
143 }
144
145 var value ir.Node
146 switch {
147 case fromType.Size() == 0:
148
149 cheapExpr(n, init)
150 value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
151 case isBool || fromType.Size() == 1 && isInteger:
152
153
154 n = cheapExpr(n, init)
155 n = soleComponent(init, n)
156
157 index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(base.Pos, 3))
158 if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian {
159 index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(base.Pos, 7))
160 }
161
162
163 staticuint64s := ir.NewLinksymExpr(base.Pos, ir.Syms.Staticuint64s, types.NewArray(types.Types[types.TUINT8], 256*8))
164 xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
165 xe.SetBounded(true)
166 value = xe
167 case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
168
169 value = n
170 case conv.Esc() == ir.EscNone && fromType.Size() <= 1024:
171
172 value = typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
173 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
174 }
175 if value != nil {
176
177 return typecheck.Expr(typecheck.NodAddr(value))
178 }
179
180
181 fnname, argType, needsaddr := dataWordFuncName(fromType)
182 var fn *ir.Name
183
184 var args []ir.Node
185 if needsaddr {
186
187
188
189
190
191
192 if !ir.IsAddressable(n) {
193 n = copyExpr(n, fromType, init)
194 }
195 fn = typecheck.LookupRuntime(fnname, fromType)
196 args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
197 } else {
198
199
200 fn = typecheck.LookupRuntime(fnname)
201 var arg ir.Node
202 switch {
203 case fromType == argType:
204
205 arg = n
206 case fromType.Kind() == argType.Kind(),
207 fromType.IsPtrShaped() && argType.IsPtrShaped():
208
209
210 arg = ir.NewConvExpr(pos, ir.OCONVNOP, argType, n)
211 case fromType.IsInteger() && argType.IsInteger():
212
213 arg = ir.NewConvExpr(pos, ir.OCONV, argType, n)
214 default:
215
216 arg = copyExpr(n, fromType, init)
217 var addr ir.Node = typecheck.NodAddr(arg)
218 addr = ir.NewConvExpr(pos, ir.OCONVNOP, argType.PtrTo(), addr)
219 arg = ir.NewStarExpr(pos, addr)
220 arg.SetType(argType)
221 }
222 args = []ir.Node{arg}
223 }
224 call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
225 call.Args = args
226 return safeExpr(walkExpr(typecheck.Expr(call), init), init)
227 }
228
229
230 func walkBytesRunesToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
231 a := typecheck.NodNil()
232 if n.Esc() == ir.EscNone {
233
234 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
235 }
236 if n.Op() == ir.ORUNES2STR {
237
238 return mkcall("slicerunetostring", n.Type(), init, a, n.X)
239 }
240
241 n.X = cheapExpr(n.X, init)
242 ptr, len := backingArrayPtrLen(n.X)
243 return mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
244 }
245
246
247 func walkBytesToStringTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
248 n.X = walkExpr(n.X, init)
249 if !base.Flag.Cfg.Instrumenting {
250
251
252 return n
253 }
254
255 n.X = cheapExpr(n.X, init)
256 ptr, len := backingArrayPtrLen(n.X)
257 return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
258 }
259
260
261 func walkRuneToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
262 a := typecheck.NodNil()
263 if n.Esc() == ir.EscNone {
264 a = stackBufAddr(4, types.Types[types.TUINT8])
265 }
266
267 return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
268 }
269
270
271 func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
272 s := n.X
273 if ir.IsConst(s, constant.String) {
274 sc := ir.StringVal(s)
275
276
277 t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
278 var a ir.Node
279 if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
280 a = stackBufAddr(t.NumElem(), t.Elem())
281 } else {
282 types.CalcSize(t)
283 a = ir.NewUnaryExpr(base.Pos, ir.ONEW, nil)
284 a.SetType(types.NewPtr(t))
285 a.SetTypecheck(1)
286 a.MarkNonNil()
287 }
288 p := typecheck.TempAt(base.Pos, ir.CurFunc, t.PtrTo())
289 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
290
291
292 if len(sc) > 0 {
293 sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
294 sptr.SetBounded(true)
295 as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
296 appendWalkStmt(init, as)
297 }
298
299
300 slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
301 slice.SetType(n.Type())
302 slice.SetTypecheck(1)
303 return walkExpr(slice, init)
304 }
305
306 a := typecheck.NodNil()
307 if n.Esc() == ir.EscNone {
308
309 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
310 }
311
312 return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
313 }
314
315
316 func walkStringToBytesTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
317
318
319
320
321
322
323
324 n.X = walkExpr(n.X, init)
325 return n
326 }
327
328
329 func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
330 a := typecheck.NodNil()
331 if n.Esc() == ir.EscNone {
332
333 a = stackBufAddr(tmpstringbufsize, types.Types[types.TINT32])
334 }
335
336 return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
337 }
338
339
340
341
342
343 func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
344 if from.IsInterface() {
345 base.Fatalf("can only handle non-interfaces")
346 }
347 switch {
348 case from.Size() == 2 && uint8(from.Alignment()) == 2:
349 return "convT16", types.Types[types.TUINT16], false
350 case from.Size() == 4 && uint8(from.Alignment()) == 4 && !from.HasPointers():
351 return "convT32", types.Types[types.TUINT32], false
352 case from.Size() == 8 && uint8(from.Alignment()) == uint8(types.Types[types.TUINT64].Alignment()) && !from.HasPointers():
353 return "convT64", types.Types[types.TUINT64], false
354 }
355 if sc := from.SoleComponent(); sc != nil {
356 switch {
357 case sc.IsString():
358 return "convTstring", types.Types[types.TSTRING], false
359 case sc.IsSlice():
360 return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false
361 }
362 }
363
364 if from.HasPointers() {
365 return "convT", types.Types[types.TUNSAFEPTR], true
366 }
367 return "convTnoptr", types.Types[types.TUNSAFEPTR], true
368 }
369
370
371
372
373
374
375 func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
376 if ssagen.Arch.SoftFloat {
377 return types.Txxx, types.Txxx
378 }
379
380 switch ssagen.Arch.LinkArch.Family {
381 case sys.ARM, sys.MIPS:
382 if src.IsFloat() {
383 switch dst.Kind() {
384 case types.TINT64, types.TUINT64:
385 return types.TFLOAT64, dst.Kind()
386 }
387 }
388 if dst.IsFloat() {
389 switch src.Kind() {
390 case types.TINT64, types.TUINT64:
391 return src.Kind(), dst.Kind()
392 }
393 }
394
395 case sys.I386:
396 if src.IsFloat() {
397 switch dst.Kind() {
398 case types.TINT64, types.TUINT64:
399 return types.TFLOAT64, dst.Kind()
400 case types.TUINT32, types.TUINT, types.TUINTPTR:
401 return types.TFLOAT64, types.TUINT32
402 }
403 }
404 if dst.IsFloat() {
405 switch src.Kind() {
406 case types.TINT64, types.TUINT64:
407 return src.Kind(), dst.Kind()
408 case types.TUINT32, types.TUINT, types.TUINTPTR:
409 return types.TUINT32, types.TFLOAT64
410 }
411 }
412 }
413 return types.Txxx, types.Txxx
414 }
415
416 func soleComponent(init *ir.Nodes, n ir.Node) ir.Node {
417 if n.Type().SoleComponent() == nil {
418 return n
419 }
420
421 for {
422 switch {
423 case n.Type().IsStruct():
424 if n.Type().Field(0).Sym.IsBlank() {
425
426 n = typecheck.TempAt(base.Pos, ir.CurFunc, n.Type().Field(0).Type)
427 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil))
428 continue
429 }
430 n = typecheck.DotField(n.Pos(), n, 0)
431 case n.Type().IsArray():
432 n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(base.Pos, 0)))
433 default:
434 return n
435 }
436 }
437 }
438
439
440
441
442 func byteindex(n ir.Node) ir.Node {
443
444
445
446
447 if !types.Identical(n.Type(), types.Types[types.TUINT8]) {
448 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
449 n.SetType(types.Types[types.TUINT8])
450 n.SetTypecheck(1)
451 }
452 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
453 n.SetType(types.Types[types.TINT])
454 n.SetTypecheck(1)
455 return n
456 }
457
458 func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
459
460
461
462 if n.CheckPtr() {
463 return n
464 }
465 n.SetCheckPtr(true)
466 defer n.SetCheckPtr(false)
467
468
469
470 switch n.X.Op() {
471 case ir.OCALLMETH:
472 base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
473 case ir.OCALLFUNC, ir.OCALLINTER:
474 return n
475 }
476
477 if n.X.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(n.X) {
478 return n
479 }
480
481
482
483
484
485
486
487 var originals []ir.Node
488 var walk func(n ir.Node)
489 walk = func(n ir.Node) {
490 switch n.Op() {
491 case ir.OADD:
492 n := n.(*ir.BinaryExpr)
493 walk(n.X)
494 walk(n.Y)
495 case ir.OSUB, ir.OANDNOT:
496 n := n.(*ir.BinaryExpr)
497 walk(n.X)
498 case ir.OCONVNOP:
499 n := n.(*ir.ConvExpr)
500 if n.X.Type().IsUnsafePtr() {
501 n.X = cheapExpr(n.X, init)
502 originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
503 }
504 }
505 }
506 walk(n.X)
507
508 cheap := cheapExpr(n, init)
509
510 slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
511 slice.SetEsc(ir.EscNone)
512
513 init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
514
515
516
517 return cheap
518 }
519
520
521 func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
522
523 conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr)
524 deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr)
525
526
527
528
529
530
531
532
533 deref.SetBounded(true)
534
535 return walkExpr(deref, init)
536 }
537
View as plain text