blob: 0beee4e49274531d1ed0bcb2e6cda3413a078f39 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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
5package gc
6
7import "cmd/internal/obj"
8
9/*
10 * range
11 */
12func typecheckrange(n *Node) {
13 var toomany int
14 var why string
Russ Cox8c195bd2015-02-13 14:40:36 -050015 var t1 *Type
16 var t2 *Type
17 var v1 *Node
18 var v2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -050019
20 // Typechecking order is important here:
21 // 0. first typecheck range expression (slice/map/chan),
22 // it is evaluated only once and so logically it is not part of the loop.
23 // 1. typcheck produced values,
24 // this part can declare new vars and so it must be typechecked before body,
25 // because body can contain a closure that captures the vars.
26 // 2. decldepth++ to denote loop body.
27 // 3. typecheck body.
28 // 4. decldepth--.
29
30 typecheck(&n.Right, Erv)
31
Russ Cox382b44e2015-02-23 16:07:24 -050032 t := n.Right.Type
Russ Cox8c195bd2015-02-13 14:40:36 -050033 if t == nil {
34 goto out
35 }
36
37 // delicate little dance. see typecheckas2
Russ Cox382b44e2015-02-23 16:07:24 -050038 for ll := n.List; ll != nil; ll = ll.Next {
Russ Cox4fdd5362015-05-26 22:19:27 -040039 if ll.N.Name == nil || ll.N.Name.Defn != n {
Russ Cox8c195bd2015-02-13 14:40:36 -050040 typecheck(&ll.N, Erv|Easgn)
41 }
42 }
43
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +000044 if Isptr[t.Etype] && Isfixedarray(t.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -050045 t = t.Type
46 }
47 n.Type = t
48
49 toomany = 0
50 switch t.Etype {
51 default:
52 Yyerror("cannot range over %v", Nconv(n.Right, obj.FmtLong))
53 goto out
54
55 case TARRAY:
56 t1 = Types[TINT]
57 t2 = t.Type
58
59 case TMAP:
60 t1 = t.Down
61 t2 = t.Type
62
63 case TCHAN:
Russ Coxdc7b54b2015-02-17 22:13:49 -050064 if t.Chan&Crecv == 0 {
Russ Cox17228f42015-04-17 12:03:22 -040065 Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -050066 goto out
67 }
68
69 t1 = t.Type
70 t2 = nil
71 if count(n.List) == 2 {
72 toomany = 1
73 }
74
75 case TSTRING:
76 t1 = Types[TINT]
77 t2 = runetype
78 }
79
80 if count(n.List) > 2 || toomany != 0 {
81 Yyerror("too many variables in range")
82 }
83
84 v1 = nil
85 if n.List != nil {
86 v1 = n.List.N
87 }
88 v2 = nil
89 if n.List != nil && n.List.Next != nil {
90 v2 = n.List.Next.N
91 }
92
93 // this is not only a optimization but also a requirement in the spec.
94 // "if the second iteration variable is the blank identifier, the range
95 // clause is equivalent to the same clause with only the first variable
96 // present."
97 if isblank(v2) {
98 if v1 != nil {
99 n.List = list1(v1)
100 }
101 v2 = nil
102 }
103
104 if v1 != nil {
Russ Cox4fdd5362015-05-26 22:19:27 -0400105 if v1.Name != nil && v1.Name.Defn == n {
Russ Cox8c195bd2015-02-13 14:40:36 -0500106 v1.Type = t1
107 } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
Russ Cox17228f42015-04-17 12:03:22 -0400108 Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why)
Russ Cox8c195bd2015-02-13 14:40:36 -0500109 }
110 checkassign(n, v1)
111 }
112
113 if v2 != nil {
Russ Cox4fdd5362015-05-26 22:19:27 -0400114 if v2.Name != nil && v2.Name.Defn == n {
Russ Cox8c195bd2015-02-13 14:40:36 -0500115 v2.Type = t2
116 } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
Russ Cox17228f42015-04-17 12:03:22 -0400117 Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why)
Russ Cox8c195bd2015-02-13 14:40:36 -0500118 }
119 checkassign(n, v2)
120 }
121
122 // second half of dance
123out:
124 n.Typecheck = 1
125
Russ Cox382b44e2015-02-23 16:07:24 -0500126 for ll := n.List; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500127 if ll.N.Typecheck == 0 {
128 typecheck(&ll.N, Erv|Easgn)
129 }
130 }
131
132 decldepth++
133 typechecklist(n.Nbody, Etop)
134 decldepth--
135}
136
137func walkrange(n *Node) {
Russ Coxcdb7d7d2015-03-05 13:57:36 -0500138 // variable name conventions:
139 // ohv1, hv1, hv2: hidden (old) val 1, 2
140 // ha, hit: hidden aggregate, iterator
141 // hn, hp: hidden len, pointer
142 // hb: hidden bool
143 // a, v1, v2: not hidden aggregate, val 1, 2
144
Russ Cox382b44e2015-02-23 16:07:24 -0500145 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500146
Russ Cox382b44e2015-02-23 16:07:24 -0500147 a := n.Right
148 lno := int(setlineno(a))
Russ Coxffef1802015-05-22 01:16:52 -0400149 n.Right = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500150
Russ Cox175929b2015-03-02 14:22:05 -0500151 var v1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500152 if n.List != nil {
153 v1 = n.List.N
154 }
Russ Cox175929b2015-03-02 14:22:05 -0500155 var v2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500156 if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) {
157 v2 = n.List.Next.N
158 }
159
160 // n->list has no meaning anymore, clear it
161 // to avoid erroneous processing by racewalk.
162 n.List = nil
163
Russ Cox382b44e2015-02-23 16:07:24 -0500164 var body *NodeList
Russ Cox44928112015-03-02 20:34:22 -0500165 var init *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500166 switch t.Etype {
167 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200168 Fatalf("walkrange")
Russ Cox8c195bd2015-02-13 14:40:36 -0500169
Russ Cox8c195bd2015-02-13 14:40:36 -0500170 case TARRAY:
Matthew Dempsky7eb94db2015-10-15 11:08:09 -0700171 if memclrrange(n, v1, v2, a) {
172 lineno = int32(lno)
173 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500174 }
175
176 // orderstmt arranged for a copy of the array/slice variable if needed.
Russ Cox382b44e2015-02-23 16:07:24 -0500177 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500178
Russ Cox382b44e2015-02-23 16:07:24 -0500179 hv1 := temp(Types[TINT])
180 hn := temp(Types[TINT])
Russ Cox175929b2015-03-02 14:22:05 -0500181 var hp *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500182
183 init = list(init, Nod(OAS, hv1, nil))
184 init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
185 if v2 != nil {
186 hp = temp(Ptrto(n.Type.Type))
Russ Cox382b44e2015-02-23 16:07:24 -0500187 tmp := Nod(OINDEX, ha, Nodintconst(0))
Russ Coxdc7b54b2015-02-17 22:13:49 -0500188 tmp.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500189 init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
190 }
191
Russ Cox66be1482015-05-26 21:30:20 -0400192 n.Left = Nod(OLT, hv1, hn)
Russ Coxffef1802015-05-22 01:16:52 -0400193 n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1)))
Russ Cox8c195bd2015-02-13 14:40:36 -0500194 if v1 == nil {
195 body = nil
196 } else if v2 == nil {
197 body = list1(Nod(OAS, v1, hv1))
198 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500199 a := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500200 a.List = list(list1(v1), v2)
201 a.Rlist = list(list1(hv1), Nod(OIND, hp, nil))
202 body = list1(a)
203
204 // Advance pointer as part of increment.
205 // We used to advance the pointer before executing the loop body,
206 // but doing so would make the pointer point past the end of the
207 // array during the final iteration, possibly causing another unrelated
208 // piece of memory not to be garbage collected until the loop finished.
209 // Advancing during the increment ensures that the pointer p only points
210 // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
211 // after which p is dead, so it cannot confuse the collector.
Russ Cox382b44e2015-02-23 16:07:24 -0500212 tmp := Nod(OADD, hp, Nodintconst(t.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -0500213
214 tmp.Type = hp.Type
215 tmp.Typecheck = 1
216 tmp.Right.Type = Types[Tptr]
217 tmp.Right.Typecheck = 1
218 a = Nod(OAS, hp, tmp)
219 typecheck(&a, Etop)
Russ Coxffef1802015-05-22 01:16:52 -0400220 n.Right.Ninit = list1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500221 }
222
223 // orderstmt allocated the iterator for us.
224 // we only use a once, so no copy needed.
225 case TMAP:
Russ Cox382b44e2015-02-23 16:07:24 -0500226 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500227
Russ Cox382b44e2015-02-23 16:07:24 -0500228 th := hiter(t)
Russ Cox60e5f5b2015-05-26 23:05:35 -0400229 hit := prealloc[n]
Russ Cox8c195bd2015-02-13 14:40:36 -0500230 hit.Type = th
231 n.Left = nil
Keith Randallcd5b1442015-03-11 12:58:47 -0700232 keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter
Russ Cox382b44e2015-02-23 16:07:24 -0500233 valname := newname(th.Type.Down.Sym) // ditto
Russ Cox8c195bd2015-02-13 14:40:36 -0500234
Russ Cox382b44e2015-02-23 16:07:24 -0500235 fn := syslook("mapiterinit", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500236
Russ Cox13f9c8b2015-03-08 13:33:49 -0400237 substArgTypes(fn, t.Down, t.Type, th)
Russ Cox8c195bd2015-02-13 14:40:36 -0500238 init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
Russ Cox66be1482015-05-26 21:30:20 -0400239 n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
Russ Cox8c195bd2015-02-13 14:40:36 -0500240
241 fn = syslook("mapiternext", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400242 substArgTypes(fn, th)
Russ Coxffef1802015-05-22 01:16:52 -0400243 n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500244
Russ Cox382b44e2015-02-23 16:07:24 -0500245 key := Nod(ODOT, hit, keyname)
Russ Cox8c195bd2015-02-13 14:40:36 -0500246 key = Nod(OIND, key, nil)
247 if v1 == nil {
248 body = nil
249 } else if v2 == nil {
250 body = list1(Nod(OAS, v1, key))
251 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500252 val := Nod(ODOT, hit, valname)
Russ Cox8c195bd2015-02-13 14:40:36 -0500253 val = Nod(OIND, val, nil)
Russ Cox382b44e2015-02-23 16:07:24 -0500254 a := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500255 a.List = list(list1(v1), v2)
256 a.Rlist = list(list1(key), val)
257 body = list1(a)
258 }
259
260 // orderstmt arranged for a copy of the channel variable.
261 case TCHAN:
Russ Cox382b44e2015-02-23 16:07:24 -0500262 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500263
Russ Cox66be1482015-05-26 21:30:20 -0400264 n.Left = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500265
Russ Cox382b44e2015-02-23 16:07:24 -0500266 hv1 := temp(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500267 hv1.Typecheck = 1
268 if haspointers(t.Type) {
269 init = list(init, Nod(OAS, hv1, nil))
270 }
Russ Cox382b44e2015-02-23 16:07:24 -0500271 hb := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -0500272
Russ Cox66be1482015-05-26 21:30:20 -0400273 n.Left = Nod(ONE, hb, Nodbool(false))
Russ Cox382b44e2015-02-23 16:07:24 -0500274 a := Nod(OAS2RECV, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500275 a.Typecheck = 1
276 a.List = list(list1(hv1), hb)
277 a.Rlist = list1(Nod(ORECV, ha, nil))
Russ Cox66be1482015-05-26 21:30:20 -0400278 n.Left.Ninit = list1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500279 if v1 == nil {
280 body = nil
281 } else {
282 body = list1(Nod(OAS, v1, hv1))
283 }
284
285 // orderstmt arranged for a copy of the string variable.
286 case TSTRING:
Russ Cox382b44e2015-02-23 16:07:24 -0500287 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500288
Russ Cox382b44e2015-02-23 16:07:24 -0500289 ohv1 := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -0500290
Russ Cox382b44e2015-02-23 16:07:24 -0500291 hv1 := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -0500292 init = list(init, Nod(OAS, hv1, nil))
293
Russ Cox382b44e2015-02-23 16:07:24 -0500294 var a *Node
Russ Cox44928112015-03-02 20:34:22 -0500295 var hv2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500296 if v2 == nil {
297 a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1))
298 } else {
299 hv2 = temp(runetype)
300 a = Nod(OAS2, nil, nil)
301 a.List = list(list1(hv1), hv2)
Russ Cox382b44e2015-02-23 16:07:24 -0500302 fn := syslook("stringiter2", 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500303 a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1))
304 }
305
Russ Cox66be1482015-05-26 21:30:20 -0400306 n.Left = Nod(ONE, hv1, Nodintconst(0))
307 n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500308
309 body = nil
310 if v1 != nil {
311 body = list1(Nod(OAS, v1, ohv1))
312 }
313 if v2 != nil {
314 body = list(body, Nod(OAS, v2, hv2))
315 }
316 }
317
318 n.Op = OFOR
319 typechecklist(init, Etop)
320 n.Ninit = concat(n.Ninit, init)
Russ Cox66be1482015-05-26 21:30:20 -0400321 typechecklist(n.Left.Ninit, Etop)
322 typecheck(&n.Left, Erv)
Russ Coxffef1802015-05-22 01:16:52 -0400323 typecheck(&n.Right, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500324 typechecklist(body, Etop)
325 n.Nbody = concat(body, n.Nbody)
326 walkstmt(&n)
327
328 lineno = int32(lno)
329}
Matthew Dempsky7eb94db2015-10-15 11:08:09 -0700330
331// Lower n into runtime·memclr if possible, for
332// fast zeroing of slices and arrays (issue 5373).
333// Look for instances of
334//
335// for i := range a {
336// a[i] = zero
337// }
338//
339// in which the evaluation of a is side-effect-free.
340//
341// Parameters are as in walkrange: "for v1, v2 = range a".
342func memclrrange(n, v1, v2, a *Node) bool {
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700343 if Debug['N'] != 0 || instrumenting {
Matthew Dempsky7eb94db2015-10-15 11:08:09 -0700344 return false
345 }
346 if v1 == nil || v2 != nil {
347 return false
348 }
349 if n.Nbody == nil || n.Nbody.N == nil || n.Nbody.Next != nil {
350 return false
351 }
352 stmt := n.Nbody.N // only stmt in body
353 if stmt.Op != OAS || stmt.Left.Op != OINDEX {
354 return false
355 }
356 if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
357 return false
358 }
359 elemsize := n.Type.Type.Width
360 if elemsize <= 0 || !iszero(stmt.Right) {
361 return false
362 }
363
364 // Convert to
365 // if len(a) != 0 {
366 // hp = &a[0]
367 // hn = len(a)*sizeof(elem(a))
368 // memclr(hp, hn)
369 // i = len(a) - 1
370 // }
371 n.Op = OIF
372
373 n.Nbody = nil
374 n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
375
376 // hp = &a[0]
377 hp := temp(Ptrto(Types[TUINT8]))
378
379 tmp := Nod(OINDEX, a, Nodintconst(0))
380 tmp.Bounded = true
381 tmp = Nod(OADDR, tmp, nil)
382 tmp = Nod(OCONVNOP, tmp, nil)
383 tmp.Type = Ptrto(Types[TUINT8])
384 n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
385
386 // hn = len(a) * sizeof(elem(a))
387 hn := temp(Types[TUINTPTR])
388
389 tmp = Nod(OLEN, a, nil)
390 tmp = Nod(OMUL, tmp, Nodintconst(elemsize))
391 tmp = conv(tmp, Types[TUINTPTR])
392 n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
393
394 // memclr(hp, hn)
395 fn := mkcall("memclr", nil, nil, hp, hn)
396
397 n.Nbody = list(n.Nbody, fn)
398
399 // i = len(a) - 1
400 v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
401
402 n.Nbody = list(n.Nbody, v1)
403
404 typecheck(&n.Left, Erv)
405 typechecklist(n.Nbody, Etop)
406 walkstmt(&n)
407 return true
408}