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