Source file src/pkg/cmd/compile/internal/gc/range.go
1
2
3
4
5 package gc
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/sys"
10 "unicode/utf8"
11 )
12
13
14 func typecheckrange(n *Node) {
15
16
17
18
19
20
21
22
23
24 typecheckrangeExpr(n)
25
26
27 n.SetTypecheck(1)
28 ls := n.List.Slice()
29 for i1, n1 := range ls {
30 if n1.Typecheck() == 0 {
31 ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
32 }
33 }
34
35 decldepth++
36 typecheckslice(n.Nbody.Slice(), ctxStmt)
37 decldepth--
38 }
39
40 func typecheckrangeExpr(n *Node) {
41 n.Right = typecheck(n.Right, ctxExpr)
42
43 t := n.Right.Type
44 if t == nil {
45 return
46 }
47
48 ls := n.List.Slice()
49 for i1, n1 := range ls {
50 if n1.Name == nil || n1.Name.Defn != n {
51 ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
52 }
53 }
54
55 if t.IsPtr() && t.Elem().IsArray() {
56 t = t.Elem()
57 }
58 n.Type = t
59
60 var t1, t2 *types.Type
61 toomany := false
62 switch t.Etype {
63 default:
64 yyerrorl(n.Pos, "cannot range over %L", n.Right)
65 return
66
67 case TARRAY, TSLICE:
68 t1 = types.Types[TINT]
69 t2 = t.Elem()
70
71 case TMAP:
72 t1 = t.Key()
73 t2 = t.Elem()
74
75 case TCHAN:
76 if !t.ChanDir().CanRecv() {
77 yyerrorl(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
78 return
79 }
80
81 t1 = t.Elem()
82 t2 = nil
83 if n.List.Len() == 2 {
84 toomany = true
85 }
86
87 case TSTRING:
88 t1 = types.Types[TINT]
89 t2 = types.Runetype
90 }
91
92 if n.List.Len() > 2 || toomany {
93 yyerrorl(n.Pos, "too many variables in range")
94 }
95
96 var v1, v2 *Node
97 if n.List.Len() != 0 {
98 v1 = n.List.First()
99 }
100 if n.List.Len() > 1 {
101 v2 = n.List.Second()
102 }
103
104
105
106
107
108 if v2.isBlank() {
109 if v1 != nil {
110 n.List.Set1(v1)
111 }
112 v2 = nil
113 }
114
115 var why string
116 if v1 != nil {
117 if v1.Name != nil && v1.Name.Defn == n {
118 v1.Type = t1
119 } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
120 yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
121 }
122 checkassign(n, v1)
123 }
124
125 if v2 != nil {
126 if v2.Name != nil && v2.Name.Defn == n {
127 v2.Type = t2
128 } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
129 yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
130 }
131 checkassign(n, v2)
132 }
133 }
134
135 func cheapComputableIndex(width int64) bool {
136 switch thearch.LinkArch.Family {
137
138
139
140 case sys.PPC64, sys.S390X:
141 return width == 1
142 case sys.AMD64, sys.I386, sys.ARM64, sys.ARM:
143 switch width {
144 case 1, 2, 4, 8:
145 return true
146 }
147 }
148 return false
149 }
150
151
152
153
154
155 func walkrange(n *Node) *Node {
156 if isMapClear(n) {
157 m := n.Right
158 lno := setlineno(m)
159 n = mapClear(m)
160 lineno = lno
161 return n
162 }
163
164
165
166
167
168
169
170
171 t := n.Type
172
173 a := n.Right
174 lno := setlineno(a)
175 n.Right = nil
176
177 var v1, v2 *Node
178 l := n.List.Len()
179 if l > 0 {
180 v1 = n.List.First()
181 }
182
183 if l > 1 {
184 v2 = n.List.Second()
185 }
186
187 if v2.isBlank() {
188 v2 = nil
189 }
190
191 if v1.isBlank() && v2 == nil {
192 v1 = nil
193 }
194
195 if v1 == nil && v2 != nil {
196 Fatalf("walkrange: v2 != nil while v1 == nil")
197 }
198
199
200
201 n.List.Set(nil)
202
203 var ifGuard *Node
204
205 translatedLoopOp := OFOR
206
207 var body []*Node
208 var init []*Node
209 switch t.Etype {
210 default:
211 Fatalf("walkrange")
212
213 case TARRAY, TSLICE:
214 if arrayClear(n, v1, v2, a) {
215 lineno = lno
216 return n
217 }
218
219
220 ha := a
221
222 hv1 := temp(types.Types[TINT])
223 hn := temp(types.Types[TINT])
224
225 init = append(init, nod(OAS, hv1, nil))
226 init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
227
228 n.Left = nod(OLT, hv1, hn)
229 n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
230
231
232 if v1 == nil {
233 break
234 }
235
236
237 if v2 == nil {
238 body = []*Node{nod(OAS, v1, hv1)}
239 break
240 }
241
242
243 if cheapComputableIndex(n.Type.Elem().Width) {
244
245 tmp := nod(OINDEX, ha, hv1)
246 tmp.SetBounded(true)
247
248
249 a := nod(OAS2, nil, nil)
250 a.List.Set2(v1, v2)
251 a.Rlist.Set2(hv1, tmp)
252 body = []*Node{a}
253 break
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267
268 ifGuard = nod(OIF, nil, nil)
269 ifGuard.Left = nod(OLT, hv1, hn)
270 translatedLoopOp = OFORUNTIL
271
272 hp := temp(types.NewPtr(n.Type.Elem()))
273 tmp := nod(OINDEX, ha, nodintconst(0))
274 tmp.SetBounded(true)
275 init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
276
277
278
279 a := nod(OAS2, nil, nil)
280 a.List.Set2(v1, v2)
281 a.Rlist.Set2(hv1, nod(ODEREF, hp, nil))
282 body = append(body, a)
283
284
285
286
287
288
289 a = nod(OAS, hp, addptr(hp, t.Elem().Width))
290 a = typecheck(a, ctxStmt)
291 n.List.Set1(a)
292
293 case TMAP:
294
295
296 ha := a
297
298 hit := prealloc[n]
299 th := hit.Type
300 n.Left = nil
301 keysym := th.Field(0).Sym
302 elemsym := th.Field(1).Sym
303
304 fn := syslook("mapiterinit")
305
306 fn = substArgTypes(fn, t.Key(), t.Elem(), th)
307 init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
308 n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
309
310 fn = syslook("mapiternext")
311 fn = substArgTypes(fn, th)
312 n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
313
314 key := nodSym(ODOT, hit, keysym)
315 key = nod(ODEREF, key, nil)
316 if v1 == nil {
317 body = nil
318 } else if v2 == nil {
319 body = []*Node{nod(OAS, v1, key)}
320 } else {
321 elem := nodSym(ODOT, hit, elemsym)
322 elem = nod(ODEREF, elem, nil)
323 a := nod(OAS2, nil, nil)
324 a.List.Set2(v1, v2)
325 a.Rlist.Set2(key, elem)
326 body = []*Node{a}
327 }
328
329 case TCHAN:
330
331 ha := a
332
333 n.Left = nil
334
335 hv1 := temp(t.Elem())
336 hv1.SetTypecheck(1)
337 if types.Haspointers(t.Elem()) {
338 init = append(init, nod(OAS, hv1, nil))
339 }
340 hb := temp(types.Types[TBOOL])
341
342 n.Left = nod(ONE, hb, nodbool(false))
343 a := nod(OAS2RECV, nil, nil)
344 a.SetTypecheck(1)
345 a.List.Set2(hv1, hb)
346 a.Rlist.Set1(nod(ORECV, ha, nil))
347 n.Left.Ninit.Set1(a)
348 if v1 == nil {
349 body = nil
350 } else {
351 body = []*Node{nod(OAS, v1, hv1)}
352 }
353
354
355
356 body = append(body, nod(OAS, hv1, nil))
357
358 case TSTRING:
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 ha := a
376
377 hv1 := temp(types.Types[TINT])
378 hv1t := temp(types.Types[TINT])
379 hv2 := temp(types.Runetype)
380
381
382 init = append(init, nod(OAS, hv1, nil))
383
384
385 n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
386
387 if v1 != nil {
388
389 body = append(body, nod(OAS, hv1t, hv1))
390 }
391
392
393 nind := nod(OINDEX, ha, hv1)
394 nind.SetBounded(true)
395 body = append(body, nod(OAS, hv2, conv(nind, types.Runetype)))
396
397
398 nif := nod(OIF, nil, nil)
399 nif.Left = nod(OLT, hv2, nodintconst(utf8.RuneSelf))
400
401
402 nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
403
404
405 eif := nod(OAS2, nil, nil)
406 nif.Rlist.Set1(eif)
407
408
409 eif.List.Set2(hv2, hv1)
410 fn := syslook("decoderune")
411 eif.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
412
413 body = append(body, nif)
414
415 if v1 != nil {
416 if v2 != nil {
417
418 a := nod(OAS2, nil, nil)
419 a.List.Set2(v1, v2)
420 a.Rlist.Set2(hv1t, hv2)
421 body = append(body, a)
422 } else {
423
424 body = append(body, nod(OAS, v1, hv1t))
425 }
426 }
427 }
428
429 n.Op = translatedLoopOp
430 typecheckslice(init, ctxStmt)
431
432 if ifGuard != nil {
433 ifGuard.Ninit.Append(init...)
434 ifGuard = typecheck(ifGuard, ctxStmt)
435 } else {
436 n.Ninit.Append(init...)
437 }
438
439 typecheckslice(n.Left.Ninit.Slice(), ctxStmt)
440
441 n.Left = typecheck(n.Left, ctxExpr)
442 n.Left = defaultlit(n.Left, nil)
443 n.Right = typecheck(n.Right, ctxStmt)
444 typecheckslice(body, ctxStmt)
445 n.Nbody.Prepend(body...)
446
447 if ifGuard != nil {
448 ifGuard.Nbody.Set1(n)
449 n = ifGuard
450 }
451
452 n = walkstmt(n)
453
454 lineno = lno
455 return n
456 }
457
458
459
460
461
462
463
464
465 func isMapClear(n *Node) bool {
466 if Debug['N'] != 0 || instrumenting {
467 return false
468 }
469
470 if n.Op != ORANGE || n.Type.Etype != TMAP || n.List.Len() != 1 {
471 return false
472 }
473
474 k := n.List.First()
475 if k == nil || k.isBlank() {
476 return false
477 }
478
479
480 if k.Name == nil || k.Name.Defn != n {
481 return false
482 }
483
484 if n.Nbody.Len() != 1 {
485 return false
486 }
487
488 stmt := n.Nbody.First()
489 if stmt == nil || stmt.Op != ODELETE {
490 return false
491 }
492
493 m := n.Right
494 if !samesafeexpr(stmt.List.First(), m) || !samesafeexpr(stmt.List.Second(), k) {
495 return false
496 }
497
498
499 if !isreflexive(m.Type.Key()) {
500 return false
501 }
502
503 return true
504 }
505
506
507 func mapClear(m *Node) *Node {
508 t := m.Type
509
510
511 fn := syslook("mapclear")
512 fn = substArgTypes(fn, t.Key(), t.Elem())
513 n := mkcall1(fn, nil, nil, typename(t), m)
514
515 n = typecheck(n, ctxStmt)
516 n = walkstmt(n)
517
518 return n
519 }
520
521
522
523
524
525
526
527
528
529
530
531
532 func arrayClear(n, v1, v2, a *Node) bool {
533 if Debug['N'] != 0 || instrumenting {
534 return false
535 }
536
537 if v1 == nil || v2 != nil {
538 return false
539 }
540
541 if n.Nbody.Len() != 1 || n.Nbody.First() == nil {
542 return false
543 }
544
545 stmt := n.Nbody.First()
546 if stmt.Op != OAS || stmt.Left.Op != OINDEX {
547 return false
548 }
549
550 if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
551 return false
552 }
553
554 elemsize := n.Type.Elem().Width
555 if elemsize <= 0 || !isZero(stmt.Right) {
556 return false
557 }
558
559
560
561
562
563
564
565
566 n.Op = OIF
567
568 n.Nbody.Set(nil)
569 n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
570
571
572 hp := temp(types.Types[TUNSAFEPTR])
573
574 tmp := nod(OINDEX, a, nodintconst(0))
575 tmp.SetBounded(true)
576 tmp = nod(OADDR, tmp, nil)
577 tmp = convnop(tmp, types.Types[TUNSAFEPTR])
578 n.Nbody.Append(nod(OAS, hp, tmp))
579
580
581 hn := temp(types.Types[TUINTPTR])
582
583 tmp = nod(OLEN, a, nil)
584 tmp = nod(OMUL, tmp, nodintconst(elemsize))
585 tmp = conv(tmp, types.Types[TUINTPTR])
586 n.Nbody.Append(nod(OAS, hn, tmp))
587
588 var fn *Node
589 if a.Type.Elem().HasHeapPointer() {
590
591 Curfn.Func.setWBPos(stmt.Pos)
592 fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
593 } else {
594
595 fn = mkcall("memclrNoHeapPointers", nil, nil, hp, hn)
596 }
597
598 n.Nbody.Append(fn)
599
600
601 v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, nil), nodintconst(1)))
602
603 n.Nbody.Append(v1)
604
605 n.Left = typecheck(n.Left, ctxExpr)
606 n.Left = defaultlit(n.Left, nil)
607 typecheckslice(n.Nbody.Slice(), ctxStmt)
608 n = walkstmt(n)
609 return true
610 }
611
612
613 func addptr(p *Node, n int64) *Node {
614 t := p.Type
615
616 p = nod(OCONVNOP, p, nil)
617 p.Type = types.Types[TUINTPTR]
618
619 p = nod(OADD, p, nodintconst(n))
620
621 p = nod(OCONVNOP, p, nil)
622 p.Type = t
623
624 return p
625 }
626
View as plain text