Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // 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 | |
| 5 | package gc |
| 6 | |
| 7 | import "cmd/internal/obj" |
| 8 | |
| 9 | /* |
| 10 | * range |
| 11 | */ |
| 12 | func typecheckrange(n *Node) { |
| 13 | var toomany int |
| 14 | var why string |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 15 | var t1 *Type |
| 16 | var t2 *Type |
| 17 | var v1 *Node |
| 18 | var v2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 19 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 32 | t := n.Right.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 33 | if t == nil { |
| 34 | goto out |
| 35 | } |
| 36 | |
| 37 | // delicate little dance. see typecheckas2 |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 38 | for ll := n.List; ll != nil; ll = ll.Next { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 39 | if ll.N.Name == nil || ll.N.Name.Defn != n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 40 | typecheck(&ll.N, Erv|Easgn) |
| 41 | } |
| 42 | } |
| 43 | |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 44 | if Isptr[t.Etype] && Isfixedarray(t.Type) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 45 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 64 | if t.Chan&Crecv == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 65 | Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 66 | 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 Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 105 | if v1.Name != nil && v1.Name.Defn == n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 106 | v1.Type = t1 |
| 107 | } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 108 | Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 109 | } |
| 110 | checkassign(n, v1) |
| 111 | } |
| 112 | |
| 113 | if v2 != nil { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 114 | if v2.Name != nil && v2.Name.Defn == n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 115 | v2.Type = t2 |
| 116 | } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 117 | Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 118 | } |
| 119 | checkassign(n, v2) |
| 120 | } |
| 121 | |
| 122 | // second half of dance |
| 123 | out: |
| 124 | n.Typecheck = 1 |
| 125 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 126 | for ll := n.List; ll != nil; ll = ll.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 127 | 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 | |
| 137 | func walkrange(n *Node) { |
Russ Cox | cdb7d7d | 2015-03-05 13:57:36 -0500 | [diff] [blame] | 138 | // 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 145 | t := n.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 146 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 147 | a := n.Right |
| 148 | lno := int(setlineno(a)) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 149 | n.Right = nil |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 150 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 151 | var v1 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 152 | if n.List != nil { |
| 153 | v1 = n.List.N |
| 154 | } |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 155 | var v2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 156 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 164 | var body *NodeList |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 165 | var init *NodeList |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 166 | switch t.Etype { |
| 167 | default: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 168 | Fatalf("walkrange") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 169 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 170 | case TARRAY: |
Matthew Dempsky | 7eb94db | 2015-10-15 11:08:09 -0700 | [diff] [blame] | 171 | if memclrrange(n, v1, v2, a) { |
| 172 | lineno = int32(lno) |
| 173 | return |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | // orderstmt arranged for a copy of the array/slice variable if needed. |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 177 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 178 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 179 | hv1 := temp(Types[TINT]) |
| 180 | hn := temp(Types[TINT]) |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 181 | var hp *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 182 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 187 | tmp := Nod(OINDEX, ha, Nodintconst(0)) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 188 | tmp.Bounded = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 189 | init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil))) |
| 190 | } |
| 191 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 192 | n.Left = Nod(OLT, hv1, hn) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 193 | n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1))) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 194 | if v1 == nil { |
| 195 | body = nil |
| 196 | } else if v2 == nil { |
| 197 | body = list1(Nod(OAS, v1, hv1)) |
| 198 | } else { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 199 | a := Nod(OAS2, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 200 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 212 | tmp := Nod(OADD, hp, Nodintconst(t.Type.Width)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 213 | |
| 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 Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 220 | n.Right.Ninit = list1(a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | // orderstmt allocated the iterator for us. |
| 224 | // we only use a once, so no copy needed. |
| 225 | case TMAP: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 226 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 227 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 228 | th := hiter(t) |
Russ Cox | 60e5f5b | 2015-05-26 23:05:35 -0400 | [diff] [blame] | 229 | hit := prealloc[n] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 230 | hit.Type = th |
| 231 | n.Left = nil |
Keith Randall | cd5b144 | 2015-03-11 12:58:47 -0700 | [diff] [blame] | 232 | keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 233 | valname := newname(th.Type.Down.Sym) // ditto |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 234 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 235 | fn := syslook("mapiterinit", 1) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 236 | |
Russ Cox | 13f9c8b | 2015-03-08 13:33:49 -0400 | [diff] [blame] | 237 | substArgTypes(fn, t.Down, t.Type, th) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 238 | init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 239 | n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 240 | |
| 241 | fn = syslook("mapiternext", 1) |
Russ Cox | 13f9c8b | 2015-03-08 13:33:49 -0400 | [diff] [blame] | 242 | substArgTypes(fn, th) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 243 | n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 244 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 245 | key := Nod(ODOT, hit, keyname) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 246 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 252 | val := Nod(ODOT, hit, valname) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 253 | val = Nod(OIND, val, nil) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 254 | a := Nod(OAS2, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 255 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 262 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 263 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 264 | n.Left = nil |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 265 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 266 | hv1 := temp(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 267 | hv1.Typecheck = 1 |
| 268 | if haspointers(t.Type) { |
| 269 | init = list(init, Nod(OAS, hv1, nil)) |
| 270 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 271 | hb := temp(Types[TBOOL]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 272 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 273 | n.Left = Nod(ONE, hb, Nodbool(false)) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 274 | a := Nod(OAS2RECV, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 275 | a.Typecheck = 1 |
| 276 | a.List = list(list1(hv1), hb) |
| 277 | a.Rlist = list1(Nod(ORECV, ha, nil)) |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 278 | n.Left.Ninit = list1(a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 279 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 287 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 288 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 289 | ohv1 := temp(Types[TINT]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 290 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 291 | hv1 := temp(Types[TINT]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 292 | init = list(init, Nod(OAS, hv1, nil)) |
| 293 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 294 | var a *Node |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 295 | var hv2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 296 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 302 | fn := syslook("stringiter2", 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 303 | a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1)) |
| 304 | } |
| 305 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 306 | n.Left = Nod(ONE, hv1, Nodintconst(0)) |
| 307 | n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 308 | |
| 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 Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 321 | typechecklist(n.Left.Ninit, Etop) |
| 322 | typecheck(&n.Left, Erv) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 323 | typecheck(&n.Right, Etop) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 324 | typechecklist(body, Etop) |
| 325 | n.Nbody = concat(body, n.Nbody) |
| 326 | walkstmt(&n) |
| 327 | |
| 328 | lineno = int32(lno) |
| 329 | } |
Matthew Dempsky | 7eb94db | 2015-10-15 11:08:09 -0700 | [diff] [blame] | 330 | |
| 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". |
| 342 | func memclrrange(n, v1, v2, a *Node) bool { |
Ian Lance Taylor | 9e902f0 | 2015-10-20 10:00:07 -0700 | [diff] [blame] | 343 | if Debug['N'] != 0 || instrumenting { |
Matthew Dempsky | 7eb94db | 2015-10-15 11:08:09 -0700 | [diff] [blame] | 344 | 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 | } |