1
2
3
4
5 package walk
6
7 import (
8 "go/constant"
9 "unicode/utf8"
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/src"
18 "cmd/internal/sys"
19 )
20
21 func cheapComputableIndex(width int64) bool {
22 switch ssagen.Arch.LinkArch.Family {
23
24
25
26 case sys.PPC64, sys.S390X:
27 return width == 1
28 case sys.AMD64, sys.I386, sys.ARM64, sys.ARM:
29 switch width {
30 case 1, 2, 4, 8:
31 return true
32 }
33 }
34 return false
35 }
36
37
38
39
40
41 func walkRange(nrange *ir.RangeStmt) ir.Node {
42 base.Assert(!nrange.DistinctVars)
43 if isMapClear(nrange) {
44 return mapRangeClear(nrange)
45 }
46
47 nfor := ir.NewForStmt(nrange.Pos(), nil, nil, nil, nil, nrange.DistinctVars)
48 nfor.SetInit(nrange.Init())
49 nfor.Label = nrange.Label
50
51
52
53
54
55
56
57
58 a := nrange.X
59 t := a.Type()
60 lno := ir.SetPos(a)
61
62 v1, v2 := nrange.Key, nrange.Value
63
64 if ir.IsBlank(v2) {
65 v2 = nil
66 }
67
68 if ir.IsBlank(v1) && v2 == nil {
69 v1 = nil
70 }
71
72 if v1 == nil && v2 != nil {
73 base.Fatalf("walkRange: v2 != nil while v1 == nil")
74 }
75
76 var body []ir.Node
77 var init []ir.Node
78 switch k := t.Kind(); {
79 default:
80 base.Fatalf("walkRange")
81
82 case types.IsInt[k]:
83 if nn := arrayRangeClear(nrange, v1, v2, a); nn != nil {
84 base.Pos = lno
85 return nn
86 }
87 hv1 := typecheck.TempAt(base.Pos, ir.CurFunc, t)
88 hn := typecheck.TempAt(base.Pos, ir.CurFunc, t)
89
90 init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
91 init = append(init, ir.NewAssignStmt(base.Pos, hn, a))
92
93 nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
94 nfor.Post = ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, ir.NewInt(base.Pos, 1)))
95
96 if v1 != nil {
97 body = []ir.Node{rangeAssign(nrange, hv1)}
98 }
99
100 case k == types.TARRAY, k == types.TSLICE, k == types.TPTR:
101 if nn := arrayRangeClear(nrange, v1, v2, a); nn != nil {
102 base.Pos = lno
103 return nn
104 }
105
106
107 var elem *types.Type
108 switch t.Kind() {
109 case types.TSLICE, types.TARRAY:
110 elem = t.Elem()
111 case types.TPTR:
112 elem = t.Elem().Elem()
113 }
114
115
116 ha := a
117
118 hv1 := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
119 hn := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
120
121 init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
122 init = append(init, ir.NewAssignStmt(base.Pos, hn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ha)))
123
124 nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
125 nfor.Post = ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, ir.NewInt(base.Pos, 1)))
126
127
128 if v1 == nil {
129 break
130 }
131
132
133 if v2 == nil {
134 body = []ir.Node{rangeAssign(nrange, hv1)}
135 break
136 }
137
138
139 if cheapComputableIndex(elem.Size()) {
140
141 tmp := ir.NewIndexExpr(base.Pos, ha, hv1)
142 tmp.SetBounded(true)
143 body = []ir.Node{rangeAssign2(nrange, hv1, tmp)}
144 break
145 }
146
147
148 var hs ir.Node
149 if t.IsSlice() {
150 hs = ha
151 } else {
152 var arr ir.Node
153 if t.IsPtr() {
154 arr = ha
155 } else {
156 arr = typecheck.NodAddr(ha)
157 arr.SetType(t.PtrTo())
158 arr.SetTypecheck(1)
159 }
160 hs = ir.NewSliceExpr(base.Pos, ir.OSLICEARR, arr, nil, nil, nil)
161
162 hs.SetType(types.NewSlice(elem))
163 hs.SetTypecheck(1)
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 ptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, hs)
215 ptr.SetBounded(true)
216 huVal := ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], ptr)
217 huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUINTPTR], huVal)
218 hu := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR])
219 init = append(init, ir.NewAssignStmt(base.Pos, hu, huVal))
220
221
222 hpVal := ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], hu)
223 hpVal.SetCheckPtr(true)
224 hpVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, elem.PtrTo(), hpVal)
225 hp := typecheck.TempAt(base.Pos, ir.CurFunc, elem.PtrTo())
226 body = append(body, ir.NewAssignStmt(base.Pos, hp, hpVal))
227
228
229 e := ir.NewStarExpr(base.Pos, hp)
230 e.SetBounded(true)
231 a := rangeAssign2(nrange, hv1, e)
232 body = append(body, a)
233
234
235
236 huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], hp)
237 huVal = ir.NewConvExpr(base.Pos, ir.OCONVNOP, types.Types[types.TUINTPTR], huVal)
238 as := ir.NewAssignStmt(base.Pos, hu, ir.NewBinaryExpr(base.Pos, ir.OADD, huVal, ir.NewInt(base.Pos, elem.Size())))
239 nfor.Post = ir.NewBlockStmt(base.Pos, []ir.Node{nfor.Post, as})
240
241 case k == types.TMAP:
242
243
244 ha := a
245
246 hit := nrange.Prealloc
247 th := hit.Type()
248
249
250 keysym := th.Field(0).Sym
251 elemsym := th.Field(1).Sym
252 iterInit := "mapIterStart"
253 iterNext := "mapIterNext"
254
255 fn := typecheck.LookupRuntime(iterInit, t.Key(), t.Elem(), th)
256 init = append(init, mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), ha, typecheck.NodAddr(hit)))
257 nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
258
259 fn = typecheck.LookupRuntime(iterNext, th)
260 nfor.Post = mkcallstmt1(fn, typecheck.NodAddr(hit))
261
262 key := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), types.NewPtr(t.Key())))
263 if v1 == nil {
264 body = nil
265 } else if v2 == nil {
266 body = []ir.Node{rangeAssign(nrange, key)}
267 } else {
268 elem := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, elemsym), types.NewPtr(t.Elem())))
269 body = []ir.Node{rangeAssign2(nrange, key, elem)}
270 }
271
272 case k == types.TCHAN:
273
274 ha := a
275
276 hv1 := typecheck.TempAt(base.Pos, ir.CurFunc, t.Elem())
277 hv1.SetTypecheck(1)
278 if t.Elem().HasPointers() {
279 init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
280 }
281 hb := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TBOOL])
282
283 nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, hb, ir.NewBool(base.Pos, false))
284 lhs := []ir.Node{hv1, hb}
285 rhs := []ir.Node{ir.NewUnaryExpr(base.Pos, ir.ORECV, ha)}
286 a := ir.NewAssignListStmt(base.Pos, ir.OAS2RECV, lhs, rhs)
287 a.SetTypecheck(1)
288 nfor.Cond = ir.InitExpr([]ir.Node{a}, nfor.Cond)
289 if v1 == nil {
290 body = nil
291 } else {
292 body = []ir.Node{rangeAssign(nrange, hv1)}
293 }
294
295
296
297 body = append(body, ir.NewAssignStmt(base.Pos, hv1, nil))
298
299 case k == types.TSTRING:
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 ha := a
317
318 hv1 := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
319 hv1t := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
320 hv2 := typecheck.TempAt(base.Pos, ir.CurFunc, types.RuneType)
321
322
323 init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
324
325
326 nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, ir.NewUnaryExpr(base.Pos, ir.OLEN, ha))
327
328 if v1 != nil {
329
330 body = append(body, ir.NewAssignStmt(base.Pos, hv1t, hv1))
331 }
332
333
334 nind := ir.NewIndexExpr(base.Pos, ha, hv1)
335 nind.SetBounded(true)
336 body = append(body, ir.NewAssignStmt(base.Pos, hv2, typecheck.Conv(nind, types.RuneType)))
337
338
339 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
340
341
342
343 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLE, hv2, ir.NewInt(base.Pos, utf8.RuneSelf-1))
344
345
346 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, ir.NewInt(base.Pos, 1)))}
347
348
349
350 fn := typecheck.LookupRuntime("decoderune")
351 call := mkcall1(fn, fn.Type().ResultsTuple(), &nif.Else, ha, hv1)
352 a := ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{hv2, hv1}, []ir.Node{call})
353 nif.Else.Append(a)
354
355 body = append(body, nif)
356
357 if v1 != nil {
358 if v2 != nil {
359
360 body = append(body, rangeAssign2(nrange, hv1t, hv2))
361 } else {
362
363 body = append(body, rangeAssign(nrange, hv1t))
364 }
365 }
366 }
367
368 typecheck.Stmts(init)
369
370 nfor.PtrInit().Append(init...)
371
372 typecheck.Stmts(nfor.Cond.Init())
373
374 nfor.Cond = typecheck.Expr(nfor.Cond)
375 nfor.Cond = typecheck.DefaultLit(nfor.Cond, nil)
376 nfor.Post = typecheck.Stmt(nfor.Post)
377 typecheck.Stmts(body)
378 nfor.Body.Append(body...)
379 nfor.Body.Append(nrange.Body...)
380
381 var n ir.Node = nfor
382
383 n = walkStmt(n)
384
385 base.Pos = lno
386 return n
387 }
388
389
390 func rangeAssign(n *ir.RangeStmt, key ir.Node) ir.Node {
391 key = rangeConvert(n, n.Key.Type(), key, n.KeyTypeWord, n.KeySrcRType)
392 return ir.NewAssignStmt(n.Pos(), n.Key, key)
393 }
394
395
396 func rangeAssign2(n *ir.RangeStmt, key, value ir.Node) ir.Node {
397
398
399 key = rangeConvert(n, n.Key.Type(), key, n.KeyTypeWord, n.KeySrcRType)
400 value = rangeConvert(n, n.Value.Type(), value, n.ValueTypeWord, n.ValueSrcRType)
401 return ir.NewAssignListStmt(n.Pos(), ir.OAS2, []ir.Node{n.Key, n.Value}, []ir.Node{key, value})
402 }
403
404
405
406
407 func rangeConvert(nrange *ir.RangeStmt, dst *types.Type, src, typeWord, srcRType ir.Node) ir.Node {
408 src = typecheck.Expr(src)
409 if dst.Kind() == types.TBLANK || types.Identical(dst, src.Type()) {
410 return src
411 }
412
413 n := ir.NewConvExpr(nrange.Pos(), ir.OCONV, dst, src)
414 n.TypeWord = typeWord
415 n.SrcRType = srcRType
416 return typecheck.Expr(n)
417 }
418
419
420
421
422
423
424
425
426 func isMapClear(n *ir.RangeStmt) bool {
427 if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting {
428 return false
429 }
430
431 t := n.X.Type()
432 if n.Op() != ir.ORANGE || t.Kind() != types.TMAP || n.Key == nil || n.Value != nil {
433 return false
434 }
435
436 k := n.Key
437
438 if !ir.DeclaredBy(k, n) {
439 return false
440 }
441
442 if len(n.Body) != 1 {
443 return false
444 }
445
446 stmt := n.Body[0]
447 if stmt == nil || stmt.Op() != ir.ODELETE {
448 return false
449 }
450
451 m := n.X
452 if delete := stmt.(*ir.CallExpr); !ir.SameSafeExpr(delete.Args[0], m) || !ir.SameSafeExpr(delete.Args[1], k) {
453 return false
454 }
455
456
457 if !types.IsReflexive(t.Key()) {
458 return false
459 }
460
461 return true
462 }
463
464
465 func mapRangeClear(nrange *ir.RangeStmt) ir.Node {
466 m := nrange.X
467 origPos := ir.SetPos(m)
468 defer func() { base.Pos = origPos }()
469
470 return mapClear(m, reflectdata.RangeMapRType(base.Pos, nrange))
471 }
472
473
474 func mapClear(m, rtyp ir.Node) ir.Node {
475 t := m.Type()
476
477
478 fn := typecheck.LookupRuntime("mapclear", t.Key(), t.Elem())
479 n := mkcallstmt1(fn, rtyp, m)
480 return walkStmt(typecheck.Stmt(n))
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494 func arrayRangeClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
495 if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting {
496 return nil
497 }
498
499 if v1 == nil || v2 != nil {
500 return nil
501 }
502
503 if len(loop.Body) != 1 || loop.Body[0] == nil {
504 return nil
505 }
506
507 stmt1 := loop.Body[0]
508 if stmt1.Op() != ir.OAS {
509 return nil
510 }
511 stmt := stmt1.(*ir.AssignStmt)
512 if stmt.X.Op() != ir.OINDEX {
513 return nil
514 }
515 lhs := stmt.X.(*ir.IndexExpr)
516 x := lhs.X
517
518
519 n := int64(-1)
520 if ir.IsConst(a, constant.Int) {
521 n = ir.Int64Val(a)
522 } else if a.Type().IsArray() {
523 n = a.Type().NumElem()
524 } else if a.Type().IsPtr() && a.Type().Elem().IsArray() {
525 n = a.Type().Elem().NumElem()
526 }
527
528 if n >= 0 {
529
530 if !x.Type().IsArray() {
531 return nil
532 }
533 if x.Type().NumElem() != n {
534 return nil
535 }
536 } else {
537
538 if !ir.SameSafeExpr(x, a) {
539 return nil
540 }
541 }
542
543 if !ir.SameSafeExpr(lhs.Index, v1) {
544 return nil
545 }
546
547 if !ir.IsZero(stmt.Y) {
548 return nil
549 }
550
551 return arrayClear(stmt.Pos(), x, loop)
552 }
553
554
555 func arrayClear(wbPos src.XPos, a ir.Node, nrange *ir.RangeStmt) ir.Node {
556 elemsize := typecheck.RangeExprType(a.Type()).Elem().Size()
557 if elemsize <= 0 {
558 return nil
559 }
560
561
562
563
564
565
566
567
568 n := ir.NewIfStmt(base.Pos, nil, nil, nil)
569 n.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(base.Pos, 0))
570
571
572 hp := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUNSAFEPTR])
573
574 ix := ir.NewIndexExpr(base.Pos, a, ir.NewInt(base.Pos, 0))
575 ix.SetBounded(true)
576 addr := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
577 n.Body.Append(ir.NewAssignStmt(base.Pos, hp, addr))
578
579
580 hn := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR])
581 mul := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(base.Pos, elemsize)), types.Types[types.TUINTPTR])
582 n.Body.Append(ir.NewAssignStmt(base.Pos, hn, mul))
583
584 var fn ir.Node
585 if a.Type().Elem().HasPointers() {
586
587 ir.CurFunc.SetWBPos(wbPos)
588 fn = mkcallstmt("memclrHasPointers", hp, hn)
589 } else {
590
591 fn = mkcallstmt("memclrNoHeapPointers", hp, hn)
592 }
593
594 n.Body.Append(fn)
595
596
597 if nrange != nil {
598 idx := ir.NewAssignStmt(base.Pos, nrange.Key, typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(base.Pos, 1)), nrange.Key.Type()))
599 n.Body.Append(idx)
600 }
601
602 n.Cond = typecheck.Expr(n.Cond)
603 n.Cond = typecheck.DefaultLit(n.Cond, nil)
604 typecheck.Stmts(n.Body)
605 return walkStmt(n)
606 }
607
View as plain text