blob: c845f783e50b9c4264ac0ea9662e5de3c4e82234 [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 (
8 "cmd/internal/obj"
9 "fmt"
10 "strings"
11)
12
13var mpzero Mpint
14
15// The constant is known to runtime.
16const (
17 tmpstringbufsize = 32
18)
19
20func walk(fn *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -050021 Curfn = fn
22
23 if Debug['W'] != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -050024 s := fmt.Sprintf("\nbefore %v", Sconv(Curfn.Nname.Sym, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050025 dumplist(s, Curfn.Nbody)
26 }
27
Russ Cox382b44e2015-02-23 16:07:24 -050028 lno := int(lineno)
Russ Cox8c195bd2015-02-13 14:40:36 -050029
30 // Final typecheck for any unused variables.
31 // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070032 for l := fn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050033 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
34 typecheck(&l.N, Erv|Easgn)
35 }
36 }
37
38 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070039 for l := fn.Func.Dcl; l != nil; l = l.Next {
Dave Cheney44e90312015-03-06 21:18:41 +110040 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Defn != nil && l.N.Defn.Op == OTYPESW && l.N.Used {
41 l.N.Defn.Left.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -050042 }
43 }
44
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070045 for l := fn.Func.Dcl; l != nil; l = l.Next {
Dave Cheney44e90312015-03-06 21:18:41 +110046 if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050047 continue
48 }
49 if l.N.Defn != nil && l.N.Defn.Op == OTYPESW {
Dave Cheney44e90312015-03-06 21:18:41 +110050 if l.N.Defn.Left.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050051 continue
52 }
53 lineno = l.N.Defn.Left.Lineno
54 Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
Dave Cheney44e90312015-03-06 21:18:41 +110055 l.N.Defn.Left.Used = true // suppress repeats
Russ Cox8c195bd2015-02-13 14:40:36 -050056 } else {
57 lineno = l.N.Lineno
58 Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
59 }
60 }
61
62 lineno = int32(lno)
63 if nerrors != 0 {
64 return
65 }
66 walkstmtlist(Curfn.Nbody)
67 if Debug['W'] != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -050068 s := fmt.Sprintf("after walk %v", Sconv(Curfn.Nname.Sym, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050069 dumplist(s, Curfn.Nbody)
70 }
71
72 heapmoves()
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070073 if Debug['W'] != 0 && Curfn.Func.Enter != nil {
Russ Cox382b44e2015-02-23 16:07:24 -050074 s := fmt.Sprintf("enter %v", Sconv(Curfn.Nname.Sym, 0))
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070075 dumplist(s, Curfn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050076 }
77}
78
79func walkstmtlist(l *NodeList) {
80 for ; l != nil; l = l.Next {
81 walkstmt(&l.N)
82 }
83}
84
Russ Coxdc7b54b2015-02-17 22:13:49 -050085func samelist(a *NodeList, b *NodeList) bool {
Russ Coxd7f6d462015-03-09 00:31:13 -040086 for ; a != nil && b != nil; a, b = a.Next, b.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050087 if a.N != b.N {
Russ Coxdc7b54b2015-02-17 22:13:49 -050088 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050089 }
90 }
Russ Coxdc7b54b2015-02-17 22:13:49 -050091 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -050092}
93
Dave Cheneyb006d382015-03-06 18:42:58 +110094func paramoutheap(fn *Node) bool {
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070095 for l := fn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050096 switch l.N.Class {
97 case PPARAMOUT,
98 PPARAMOUT | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +110099 return l.N.Addrtaken
Russ Cox8c195bd2015-02-13 14:40:36 -0500100
101 // stop early - parameters are over
102 case PAUTO,
103 PAUTO | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +1100104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500105 }
106 }
107
Dave Cheneyb006d382015-03-06 18:42:58 +1100108 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500109}
110
111// adds "adjust" to all the argument locations for the call n.
112// n must be a defer or go node that has already been walked.
113func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500114 var arg *Node
115 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500116
Russ Cox382b44e2015-02-23 16:07:24 -0500117 callfunc := n.Left
118 for args := callfunc.List; args != nil; args = args.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500119 arg = args.N
120 if arg.Op != OAS {
121 Yyerror("call arg not assignment")
122 }
123 lhs = arg.Left
124 if lhs.Op == ONAME {
125 // This is a temporary introduced by reorder1.
126 // The real store to the stack appears later in the arg list.
127 continue
128 }
129
130 if lhs.Op != OINDREG {
131 Yyerror("call argument store does not use OINDREG")
132 }
133
134 // can't really check this in machine-indep code.
135 //if(lhs->val.u.reg != D_SP)
136 // yyerror("call arg assign not indreg(SP)");
137 lhs.Xoffset += int64(adjust)
138 }
139}
140
141func walkstmt(np **Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500142 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500143 if n == nil {
144 return
145 }
146 if n.Dodata == 2 { // don't walk, generated by anylit.
147 return
148 }
149
150 setlineno(n)
151
152 walkstmtlist(n.Ninit)
153
154 switch n.Op {
155 default:
156 if n.Op == ONAME {
157 Yyerror("%v is not a top level statement", Sconv(n.Sym, 0))
158 } else {
159 Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0))
160 }
161 Dump("nottop", n)
162
163 case OAS,
164 OASOP,
165 OAS2,
166 OAS2DOTTYPE,
167 OAS2RECV,
168 OAS2FUNC,
169 OAS2MAPR,
170 OCLOSE,
171 OCOPY,
172 OCALLMETH,
173 OCALLINTER,
174 OCALL,
175 OCALLFUNC,
176 ODELETE,
177 OSEND,
178 OPRINT,
179 OPRINTN,
180 OPANIC,
181 OEMPTY,
182 ORECOVER:
183 if n.Typecheck == 0 {
184 Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
185 }
Russ Cox382b44e2015-02-23 16:07:24 -0500186 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500187 n.Ninit = nil
188 walkexpr(&n, &init)
189 addinit(&n, init)
190 if (*np).Op == OCOPY && n.Op == OCONVNOP {
191 n.Op = OEMPTY // don't leave plain values as statements.
192 }
193
194 // special case for a receive where we throw away
195 // the value received.
196 case ORECV:
197 if n.Typecheck == 0 {
198 Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
199 }
Russ Cox382b44e2015-02-23 16:07:24 -0500200 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500201 n.Ninit = nil
202
203 walkexpr(&n.Left, &init)
204 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
205 walkexpr(&n, &init)
206
207 addinit(&n, init)
208
209 case OBREAK,
210 ODCL,
211 OCONTINUE,
212 OFALL,
213 OGOTO,
214 OLABEL,
215 ODCLCONST,
216 ODCLTYPE,
217 OCHECKNIL,
218 OVARKILL:
219 break
220
221 case OBLOCK:
222 walkstmtlist(n.List)
223
224 case OXCASE:
225 Yyerror("case statement out of place")
226 n.Op = OCASE
227 fallthrough
228
229 case OCASE:
230 walkstmt(&n.Right)
231
232 case ODEFER:
233 Hasdefer = 1
234 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700235 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500236 walkprintfunc(&n.Left, &n.Ninit)
237
238 case OCOPY:
239 n.Left = copyany(n.Left, &n.Ninit, 1)
240
241 default:
242 walkexpr(&n.Left, &n.Ninit)
243 }
244
245 // make room for size & fn arguments.
246 adjustargs(n, 2*Widthptr)
247
248 case OFOR:
249 if n.Ntest != nil {
250 walkstmtlist(n.Ntest.Ninit)
Russ Cox382b44e2015-02-23 16:07:24 -0500251 init := n.Ntest.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500252 n.Ntest.Ninit = nil
253 walkexpr(&n.Ntest, &init)
254 addinit(&n.Ntest, init)
255 }
256
257 walkstmt(&n.Nincr)
258 walkstmtlist(n.Nbody)
259
260 case OIF:
261 walkexpr(&n.Ntest, &n.Ninit)
262 walkstmtlist(n.Nbody)
263 walkstmtlist(n.Nelse)
264
265 case OPROC:
266 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700267 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500268 walkprintfunc(&n.Left, &n.Ninit)
269
270 case OCOPY:
271 n.Left = copyany(n.Left, &n.Ninit, 1)
272
273 default:
274 walkexpr(&n.Left, &n.Ninit)
275 }
276
277 // make room for size & fn arguments.
278 adjustargs(n, 2*Widthptr)
279
280 case ORETURN:
281 walkexprlist(n.List, &n.Ninit)
282 if n.List == nil {
283 break
284 }
Dave Cheneyb006d382015-03-06 18:42:58 +1100285 if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500286 // assign to the function out parameters,
287 // so that reorder3 can fix up conflicts
Russ Cox175929b2015-03-02 14:22:05 -0500288 var rl *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500289
Josh Bleecher Snyder102b8062015-03-27 12:00:07 -0700290 var cl uint8
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700291 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
Josh Bleecher Snyder102b8062015-03-27 12:00:07 -0700292 cl = ll.N.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500293 if cl == PAUTO {
294 break
295 }
296 if cl == PPARAMOUT {
297 rl = list(rl, ll.N)
298 }
299 }
300
Russ Coxdc7b54b2015-02-17 22:13:49 -0500301 if samelist(rl, n.List) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500302 // special return in disguise
303 n.List = nil
304
305 break
306 }
307
308 if count(n.List) == 1 && count(rl) > 1 {
309 // OAS2FUNC in disguise
Russ Cox382b44e2015-02-23 16:07:24 -0500310 f := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500311
312 if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
313 Fatal("expected return of call, have %v", Nconv(f, 0))
314 }
315 n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
316 break
317 }
318
319 // move function calls out, to make reorder3's job easier.
320 walkexprlistsafe(n.List, &n.Ninit)
321
Russ Cox382b44e2015-02-23 16:07:24 -0500322 ll := ascompatee(int(n.Op), rl, n.List, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500323 n.List = reorder3(ll)
324 break
325 }
326
Dave Cheneyd3287562015-03-09 16:24:07 +1100327 ll := ascompatte(int(n.Op), nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500328 n.List = ll
329
330 case ORETJMP:
331 break
332
333 case OSELECT:
334 walkselect(n)
335
336 case OSWITCH:
337 walkswitch(n)
338
339 case ORANGE:
340 walkrange(n)
341
342 case OXFALL:
343 Yyerror("fallthrough statement out of place")
344 n.Op = OFALL
345 }
346
347 if n.Op == ONAME {
348 Fatal("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
349 }
350
351 *np = n
352}
353
354/*
355 * walk the whole tree of the body of an
356 * expression or simple statement.
357 * the types expressions are calculated.
358 * compile-time constants are evaluated.
359 * complex side effects like statements are appended to init
360 */
361func walkexprlist(l *NodeList, init **NodeList) {
362 for ; l != nil; l = l.Next {
363 walkexpr(&l.N, init)
364 }
365}
366
367func walkexprlistsafe(l *NodeList, init **NodeList) {
368 for ; l != nil; l = l.Next {
369 l.N = safeexpr(l.N, init)
370 walkexpr(&l.N, init)
371 }
372}
373
374func walkexprlistcheap(l *NodeList, init **NodeList) {
375 for ; l != nil; l = l.Next {
376 l.N = cheapexpr(l.N, init)
377 walkexpr(&l.N, init)
378 }
379}
380
381func walkexpr(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -0500382 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500383
384 if n == nil {
385 return
386 }
387
388 if init == &n.Ninit {
389 // not okay to use n->ninit when walking n,
390 // because we might replace n with some other node
391 // and would lose the init list.
392 Fatal("walkexpr init == &n->ninit")
393 }
394
395 if n.Ninit != nil {
396 walkstmtlist(n.Ninit)
397 *init = concat(*init, n.Ninit)
398 n.Ninit = nil
399 }
400
401 // annoying case - not typechecked
402 if n.Op == OKEY {
403 walkexpr(&n.Left, init)
404 walkexpr(&n.Right, init)
405 return
406 }
407
Russ Cox382b44e2015-02-23 16:07:24 -0500408 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500409
410 if Debug['w'] > 1 {
411 Dump("walk-before", n)
412 }
413
414 if n.Typecheck != 1 {
415 Fatal("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
416 }
417
418 switch n.Op {
419 default:
420 Dump("walk", n)
421 Fatal("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
422
423 case OTYPE,
424 ONONAME,
425 OINDREG,
426 OEMPTY,
427 OPARAM:
428 goto ret
429
430 case ONOT,
431 OMINUS,
432 OPLUS,
433 OCOM,
434 OREAL,
435 OIMAG,
436 ODOTMETH,
437 ODOTINTER:
438 walkexpr(&n.Left, init)
439 goto ret
440
441 case OIND:
442 walkexpr(&n.Left, init)
443 goto ret
444
445 case ODOT:
446 usefield(n)
447 walkexpr(&n.Left, init)
448 goto ret
449
450 case ODOTPTR:
451 usefield(n)
452 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
453 // No actual copy will be generated, so emit an explicit nil check.
454 n.Left = cheapexpr(n.Left, init)
455
456 checknil(n.Left, init)
457 }
458
459 walkexpr(&n.Left, init)
460 goto ret
461
462 case OEFACE:
463 walkexpr(&n.Left, init)
464 walkexpr(&n.Right, init)
465 goto ret
466
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700467 case OSPTR, OITAB:
Russ Cox8c195bd2015-02-13 14:40:36 -0500468 walkexpr(&n.Left, init)
469 goto ret
470
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700471 case OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500472 walkexpr(&n.Left, init)
473
474 // replace len(*[10]int) with 10.
475 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500476 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500477
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000478 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500479 t = t.Type
480 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500481 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500482 safeexpr(n.Left, init)
483 Nodconst(n, n.Type, t.Bound)
484 n.Typecheck = 1
485 }
486
487 goto ret
488
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700489 case OLSH, ORSH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500490 walkexpr(&n.Left, init)
491 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500492 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500493 n.Bounded = bounded(n.Right, 8*t.Width)
494 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500495 Warn("shift bounds check elided")
496 }
497 goto ret
498
499 // Use results from call expression as arguments for complex.
500 case OAND,
501 OSUB,
502 OHMUL,
503 OLT,
504 OLE,
505 OGE,
506 OGT,
507 OADD,
508 OCOMPLEX,
509 OLROT:
510 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
511 n.Left = n.List.N
512 n.Right = n.List.Next.N
513 }
514
515 walkexpr(&n.Left, init)
516 walkexpr(&n.Right, init)
517 goto ret
518
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700519 case OOR, OXOR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500520 walkexpr(&n.Left, init)
521 walkexpr(&n.Right, init)
522 walkrotate(&n)
523 goto ret
524
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700525 case OEQ, ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500526 walkexpr(&n.Left, init)
527 walkexpr(&n.Right, init)
528
529 // Disable safemode while compiling this code: the code we
530 // generate internally can refer to unsafe.Pointer.
531 // In this case it can happen if we need to generate an ==
532 // for a struct containing a reflect.Value, which itself has
533 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500534 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500535
536 safemode = 0
537 walkcompare(&n, init)
538 safemode = old_safemode
539 goto ret
540
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700541 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500542 walkexpr(&n.Left, init)
543
David Chaseffe7fbf2015-03-27 12:34:45 -0400544 // cannot put side effects from n.Right on init,
545 // because they cannot run before n.Left is checked.
546 // save elsewhere and store on the eventual n.Right.
Russ Cox175929b2015-03-02 14:22:05 -0500547 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500548
549 walkexpr(&n.Right, &ll)
550 addinit(&n.Right, ll)
551 goto ret
552
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700553 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500554 walkexprlist(n.List, init)
555 n = walkprint(n, init)
556 goto ret
557
558 case OPANIC:
559 n = mkcall("gopanic", nil, init, n.Left)
560 goto ret
561
562 case ORECOVER:
563 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
564 goto ret
565
566 case OLITERAL:
567 n.Addable = 1
568 goto ret
569
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700570 case OCLOSUREVAR, OCFUNC:
Russ Cox8c195bd2015-02-13 14:40:36 -0500571 n.Addable = 1
572 goto ret
573
574 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500575 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Russ Cox8c195bd2015-02-13 14:40:36 -0500576 n.Addable = 1
577 }
578 goto ret
579
580 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500581 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500582 if n.List != nil && n.List.N.Op == OAS {
583 goto ret
584 }
585 walkexpr(&n.Left, init)
586 walkexprlist(n.List, init)
Dave Cheneyd3287562015-03-09 16:24:07 +1100587 ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500588 n.List = reorder1(ll)
589 goto ret
590
591 case OCALLFUNC:
592 if n.Left.Op == OCLOSURE {
593 // Transform direct call of a closure to call of a normal function.
594 // transformclosure already did all preparation work.
595
596 // Append captured variables to argument list.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700597 n.List = concat(n.List, n.Left.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -0500598
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700599 n.Left.Func.Enter = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500600
601 // Replace OCLOSURE with ONAME/PFUNC.
602 n.Left = n.Left.Closure.Nname
603
604 // Update type of OCALLFUNC node.
605 // Output arguments had not changed, but their offsets could.
606 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500607 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500608 if t.Etype == TFIELD {
609 t = t.Type
610 }
611 n.Type = t
612 } else {
613 n.Type = getoutargx(n.Left.Type)
614 }
615 }
616
Russ Cox382b44e2015-02-23 16:07:24 -0500617 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500618 if n.List != nil && n.List.N.Op == OAS {
619 goto ret
620 }
621
622 walkexpr(&n.Left, init)
623 walkexprlist(n.List, init)
624
Russ Cox92dba0d2015-04-01 16:02:34 -0400625 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
626 switch Thearch.Thechar {
Shenghou Ma764c7512015-04-03 18:15:26 -0400627 case '5', '6', '7':
Russ Cox92dba0d2015-04-01 16:02:34 -0400628 n.Op = OSQRT
629 n.Left = n.List.N
630 n.List = nil
631 goto ret
632 }
633 }
634
Dave Cheneyd3287562015-03-09 16:24:07 +1100635 ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500636 n.List = reorder1(ll)
637 goto ret
638
639 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500640 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500641 if n.List != nil && n.List.N.Op == OAS {
642 goto ret
643 }
644 walkexpr(&n.Left, init)
645 walkexprlist(n.List, init)
Dave Cheneyd3287562015-03-09 16:24:07 +1100646 ll := ascompatte(int(n.Op), n, false, getthis(t), list1(n.Left.Left), 0, init)
647 lr := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500648 ll = concat(ll, lr)
649 n.Left.Left = nil
650 ullmancalc(n.Left)
651 n.List = reorder1(ll)
652 goto ret
653
654 case OAS:
655 *init = concat(*init, n.Ninit)
656 n.Ninit = nil
657
658 walkexpr(&n.Left, init)
659 n.Left = safeexpr(n.Left, init)
660
Russ Coxdc7b54b2015-02-17 22:13:49 -0500661 if oaslit(n, init) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500662 goto ret
663 }
664
Russ Coxdc7b54b2015-02-17 22:13:49 -0500665 if n.Right == nil || iszero(n.Right) && flag_race == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500666 goto ret
667 }
668
669 switch n.Right.Op {
670 default:
671 walkexpr(&n.Right, init)
672
Russ Cox8c195bd2015-02-13 14:40:36 -0500673 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400674 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
675 // It needs to be removed in all three places.
676 // That would allow inlining x.(struct{*int}) the same as x.(*int).
677 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && flag_race == 0 {
678 // handled directly during cgen
679 walkexpr(&n.Right, init)
680 break
681 }
682
David Chaseffe7fbf2015-03-27 12:34:45 -0400683 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400684 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500685 walkexpr(&n.Right.Left, init)
686
Russ Cox382b44e2015-02-23 16:07:24 -0500687 n1 := Nod(OADDR, n.Left, nil)
688 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500689
Russ Cox4224d812015-03-20 00:06:10 -0400690 if Debug_typeassert > 0 {
691 Warn("type assertion not inlined")
692 }
693
Russ Cox01af7272015-03-19 23:38:24 +0000694 buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
Russ Cox382b44e2015-02-23 16:07:24 -0500695 fn := syslook(buf, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400696 substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500697
698 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
699 walkexpr(&n, init)
700 goto ret
701
Russ Cox8c195bd2015-02-13 14:40:36 -0500702 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400703 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400704 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500705 walkexpr(&n.Right.Left, init)
706
Russ Cox382b44e2015-02-23 16:07:24 -0500707 n1 := Nod(OADDR, n.Left, nil)
708 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500709 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
710 walkexpr(&n, init)
711 goto ret
712 }
713
714 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500715 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500716 r.Dodata = n.Dodata
717 n = r
718 n = applywritebarrier(n, init)
719 }
720
721 goto ret
722
723 case OAS2:
724 *init = concat(*init, n.Ninit)
725 n.Ninit = nil
726 walkexprlistsafe(n.List, init)
727 walkexprlistsafe(n.Rlist, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500728 ll := ascompatee(OAS, n.List, n.Rlist, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500729 ll = reorder3(ll)
Russ Cox382b44e2015-02-23 16:07:24 -0500730 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500731 lr.N = applywritebarrier(lr.N, init)
732 }
733 n = liststmt(ll)
734 goto ret
735
736 // a,b,... = fn()
737 case OAS2FUNC:
738 *init = concat(*init, n.Ninit)
739
740 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500741 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500742 walkexprlistsafe(n.List, init)
743 walkexpr(&r, init)
744
Russ Cox382b44e2015-02-23 16:07:24 -0500745 ll := ascompatet(int(n.Op), n.List, &r.Type, 0, init)
746 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500747 lr.N = applywritebarrier(lr.N, init)
748 }
749 n = liststmt(concat(list1(r), ll))
750 goto ret
751
752 // x, y = <-c
753 // orderstmt made sure x is addressable.
754 case OAS2RECV:
755 *init = concat(*init, n.Ninit)
756
757 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500758 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500759 walkexprlistsafe(n.List, init)
760 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500761 var n1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500762 if isblank(n.List.N) {
763 n1 = nodnil()
764 } else {
765 n1 = Nod(OADDR, n.List.N, nil)
766 }
767 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500768 fn := chanfn("chanrecv2", 2, r.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500769 r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
770 n = Nod(OAS, n.List.Next.N, r)
771 typecheck(&n, Etop)
772 goto ret
773
774 // a,b = m[i];
775 case OAS2MAPR:
776 *init = concat(*init, n.Ninit)
777
778 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500779 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500780 walkexprlistsafe(n.List, init)
781 walkexpr(&r.Left, init)
782 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500783 t := r.Left.Type
784 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500785 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
786 switch Simsimtype(t.Down) {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700787 case TINT32, TUINT32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500788 p = "mapaccess2_fast32"
789
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700790 case TINT64, TUINT64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500791 p = "mapaccess2_fast64"
792
793 case TSTRING:
794 p = "mapaccess2_faststr"
795 }
796 }
797
Russ Cox382b44e2015-02-23 16:07:24 -0500798 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500799 if p != "" {
800 // fast versions take key by value
801 key = r.Right
802 } else {
803 // standard version takes key by reference
804 // orderexpr made sure key is addressable.
805 key = Nod(OADDR, r.Right, nil)
806
807 p = "mapaccess2"
808 }
809
810 // from:
811 // a,b = m[i]
812 // to:
813 // var,b = mapaccess2*(t, m, i)
814 // a = *var
Russ Cox382b44e2015-02-23 16:07:24 -0500815 a := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500816
Russ Cox382b44e2015-02-23 16:07:24 -0500817 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500818 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
819
820 // mapaccess2* returns a typed bool, but due to spec changes,
821 // the boolean result of i.(T) is now untyped so we make it the
822 // same type as the variable on the lhs.
823 if !isblank(n.List.Next.N) {
824 r.Type.Type.Down.Type = n.List.Next.N.Type
825 }
826 n.Rlist = list1(r)
827 n.Op = OAS2FUNC
828
829 // don't generate a = *var if a is _
830 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500831 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500832 var_.Typecheck = 1
833 n.List.N = var_
834 walkexpr(&n, init)
835 *init = list(*init, n)
836 n = Nod(OAS, a, Nod(OIND, var_, nil))
837 }
838
839 typecheck(&n, Etop)
840 walkexpr(&n, init)
841
842 // mapaccess needs a zero value to be at least this big.
843 if zerosize < t.Type.Width {
844 zerosize = t.Type.Width
845 }
846
847 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
848 goto ret
849
850 case ODELETE:
851 *init = concat(*init, n.Ninit)
852 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500853 map_ := n.List.N
854 key := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500855 walkexpr(&map_, init)
856 walkexpr(&key, init)
857
858 // orderstmt made sure key is addressable.
859 key = Nod(OADDR, key, nil)
860
Russ Cox382b44e2015-02-23 16:07:24 -0500861 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500862 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
863 goto ret
864
Russ Cox8c195bd2015-02-13 14:40:36 -0500865 case OAS2DOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400866 e := n.Rlist.N // i.(T)
867 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
868 // It needs to be removed in all three places.
869 // That would allow inlining x.(struct{*int}) the same as x.(*int).
870 if isdirectiface(e.Type) && !Isfat(e.Type) && flag_race == 0 {
871 // handled directly during gen.
872 walkexprlistsafe(n.List, init)
873 walkexpr(&e.Left, init)
874 goto ret
875 }
876
877 // res, ok = i.(T)
878 // orderstmt made sure a is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500879 *init = concat(*init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500880 n.Ninit = nil
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700881
Russ Cox8c195bd2015-02-13 14:40:36 -0500882 walkexprlistsafe(n.List, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700883 walkexpr(&e.Left, init)
884 t := e.Type // T
885 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500886
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700887 oktype := Types[TBOOL]
Russ Cox382b44e2015-02-23 16:07:24 -0500888 ok := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500889 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700890 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500891 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700892
Russ Cox01af7272015-03-19 23:38:24 +0000893 fromKind := type2IET(from.Type)
894 toKind := type2IET(t)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700895
896 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
897 // This is faster and shorter and allows the corresponding assertX2X2
898 // routines to skip nil checks on their last argument.
899 if isblank(n.List.N) {
900 var fast *Node
901 switch {
902 case fromKind == "E" && toKind == "T":
903 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
904 typ := Nod(OCONVNOP, typename(t), nil)
905 typ.Type = Ptrto(Types[TUINTPTR])
906 fast = Nod(OEQ, tab, typ)
907 case fromKind == "I" && toKind == "E",
908 fromKind == "E" && toKind == "E":
909 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700910 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700911 }
912 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400913 if Debug_typeassert > 0 {
914 Warn("type assertion (ok only) inlined")
915 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700916 n = Nod(OAS, ok, fast)
917 typecheck(&n, Etop)
918 goto ret
919 }
920 }
921
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700922 var resptr *Node // &res
923 if isblank(n.List.N) {
924 resptr = nodnil()
925 } else {
926 resptr = Nod(OADDR, n.List.N, nil)
927 }
928 resptr.Etype = 1 // addr does not escape
929
Russ Cox4224d812015-03-20 00:06:10 -0400930 if Debug_typeassert > 0 {
931 Warn("type assertion not inlined")
932 }
Russ Cox01af7272015-03-19 23:38:24 +0000933 buf := "assert" + fromKind + "2" + toKind + "2"
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700934 fn := syslook(buf, 1)
935 substArgTypes(fn, from.Type, t)
936 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
937 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500938 typecheck(&n, Etop)
939 goto ret
940
Russ Cox4224d812015-03-20 00:06:10 -0400941 case ODOTTYPE, ODOTTYPE2:
942 if !isdirectiface(n.Type) || Isfat(n.Type) {
943 Fatal("walkexpr ODOTTYPE") // should see inside OAS only
944 }
945 walkexpr(&n.Left, init)
946 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -0500947
948 case OCONVIFACE:
949 walkexpr(&n.Left, init)
950
951 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500952 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500953 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500954 l.Type = n.Type
955 l.Typecheck = n.Typecheck
956 n = l
957 goto ret
958 }
959
Russ Cox01af7272015-03-19 23:38:24 +0000960 // Build name of function: convI2E etc.
961 // Not all names are possible
962 // (e.g., we'll never generate convE2E or convE2I).
963 buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
964 fn := syslook(buf, 1)
Russ Cox175929b2015-03-02 14:22:05 -0500965 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -0500966 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500967 ll = list(ll, typename(n.Left.Type))
968 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500969 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500970 ll = list(ll, typename(n.Type))
971 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500972 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Coxc8198342015-03-12 18:45:30 -0400973 sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500974 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500975 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500976 l.Sym = sym
977 l.Type = Ptrto(Types[TUINT8])
978 l.Addable = 1
979 l.Class = PEXTERN
980 l.Xoffset = 0
981 sym.Def = l
982 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
983 }
984
Russ Cox382b44e2015-02-23 16:07:24 -0500985 l := Nod(OADDR, sym.Def, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500986 l.Addable = 1
987 ll = list(ll, l)
988
Russ Coxdc7b54b2015-02-17 22:13:49 -0500989 if isdirectiface(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500990 /* For pointer types, we can make a special form of optimization
991 *
992 * These statements are put onto the expression init list:
993 * Itab *tab = atomicloadtype(&cache);
994 * if(tab == nil)
995 * tab = typ2Itab(type, itype, &cache);
996 *
997 * The CONVIFACE expression is replaced with this:
998 * OEFACE{tab, ptr};
999 */
Russ Cox382b44e2015-02-23 16:07:24 -05001000 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001001
Russ Cox382b44e2015-02-23 16:07:24 -05001002 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001003 typecheck(&n1, Etop)
1004 *init = list(*init, n1)
1005
Russ Cox382b44e2015-02-23 16:07:24 -05001006 fn := syslook("typ2Itab", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001007 n1 = Nod(OCALL, fn, nil)
1008 n1.List = ll
1009 typecheck(&n1, Erv)
1010 walkexpr(&n1, init)
1011
Russ Cox382b44e2015-02-23 16:07:24 -05001012 n2 := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001013 n2.Ntest = Nod(OEQ, l, nodnil())
1014 n2.Nbody = list1(Nod(OAS, l, n1))
1015 n2.Likely = -1
1016 typecheck(&n2, Etop)
1017 *init = list(*init, n2)
1018
1019 l = Nod(OEFACE, l, n.Left)
1020 l.Typecheck = n.Typecheck
1021 l.Type = n.Type
1022 n = l
1023 goto ret
1024 }
1025 }
1026
Russ Coxdc7b54b2015-02-17 22:13:49 -05001027 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001028 ll = list(ll, n.Left)
1029 } else {
1030 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001031 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001032 // the conversions it could see. comparison of an interface
1033 // with a non-interface, especially in a switch on interface value
1034 // with non-interface cases, is not visible to orderstmt, so we
1035 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001036 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001037 ll = list(ll, Nod(OADDR, n.Left, nil))
1038 } else {
1039 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1040 }
David Chase22701332015-03-27 11:21:14 -04001041 dowidth(n.Left.Type)
1042 r := nodnil()
1043 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1044 // Allocate stack buffer for value stored in interface.
1045 r = temp(n.Left.Type)
1046 r = Nod(OAS, r, nil) // zero temp
1047 typecheck(&r, Etop)
1048 *init = list(*init, r)
1049 r = Nod(OADDR, r.Left, nil)
1050 typecheck(&r, Erv)
1051 }
1052 ll = list(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001053 }
1054
David Chase22701332015-03-27 11:21:14 -04001055 if !Isinter(n.Left.Type) {
1056 substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
1057 } else {
1058 substArgTypes(fn, n.Left.Type, n.Type)
1059 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001060 dowidth(fn.Type)
1061 n = Nod(OCALL, fn, nil)
1062 n.List = ll
1063 typecheck(&n, Erv)
1064 walkexpr(&n, init)
1065 goto ret
1066
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001067 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001068 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001069 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001070 if n.Type.Etype == TINT64 {
1071 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1072 goto ret
1073 }
1074
1075 if n.Type.Etype == TUINT64 {
1076 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1077 goto ret
1078 }
1079 }
1080
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001081 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001082 if n.Left.Type.Etype == TINT64 {
1083 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
1084 goto ret
1085 }
1086
1087 if n.Left.Type.Etype == TUINT64 {
1088 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
1089 goto ret
1090 }
1091 }
1092 }
1093
1094 walkexpr(&n.Left, init)
1095 goto ret
1096
1097 case OANDNOT:
1098 walkexpr(&n.Left, init)
1099 n.Op = OAND
1100 n.Right = Nod(OCOM, n.Right, nil)
1101 typecheck(&n.Right, Erv)
1102 walkexpr(&n.Right, init)
1103 goto ret
1104
1105 case OMUL:
1106 walkexpr(&n.Left, init)
1107 walkexpr(&n.Right, init)
1108 walkmul(&n, init)
1109 goto ret
1110
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001111 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001112 walkexpr(&n.Left, init)
1113 walkexpr(&n.Right, init)
1114
1115 /*
1116 * rewrite complex div into function call.
1117 */
Russ Cox382b44e2015-02-23 16:07:24 -05001118 et := int(n.Left.Type.Etype)
Russ Cox8c195bd2015-02-13 14:40:36 -05001119
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001120 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001121 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001122 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1123 n = conv(n, t)
1124 goto ret
1125 }
1126
1127 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001128 if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001129 goto ret
1130 }
1131
1132 // Try rewriting as shifts or magic multiplies.
1133 walkdiv(&n, init)
1134
1135 /*
1136 * rewrite 64-bit div and mod into function calls
1137 * on 32-bit architectures.
1138 */
1139 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001140 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001141 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
1142 goto ret
1143 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001144 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001145 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001146 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001147 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001148 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001149 }
1150 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001151 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001152 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001153 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001154 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001155 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001156
1157 default:
1158 break
1159 }
1160
1161 goto ret
1162
1163 case OINDEX:
1164 walkexpr(&n.Left, init)
1165
1166 // save the original node for bounds checking elision.
1167 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001168 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001169
1170 walkexpr(&n.Right, init)
1171
1172 // if range of type cannot exceed static array bound,
1173 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001174 if n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001175 goto ret
1176 }
Russ Cox382b44e2015-02-23 16:07:24 -05001177 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001178 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001179 t = t.Type
1180 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001181 if Isfixedarray(t) {
1182 n.Bounded = bounded(r, t.Bound)
1183 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001184 Warn("index bounds check elided")
1185 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001186 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001187 Yyerror("index out of bounds")
1188 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001189 } else if Isconst(n.Left, CTSTR) {
Russ Coxbed1f902015-03-02 16:03:26 -05001190 n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval)))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001191 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001192 Warn("index bounds check elided")
1193 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001194 if Smallintconst(n.Right) {
1195 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001196 Yyerror("index out of bounds")
1197 } else {
1198 // replace "abc"[1] with 'b'.
1199 // delayed until now because "abc"[1] is not
1200 // an ideal constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001201 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05001202
Russ Coxbed1f902015-03-02 16:03:26 -05001203 Nodconst(n, n.Type, int64(n.Left.Val.U.Sval[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001204 n.Typecheck = 1
1205 }
1206 }
1207 }
1208
Russ Coxdc7b54b2015-02-17 22:13:49 -05001209 if Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001210 if Mpcmpfixfix(n.Right.Val.U.Xval, &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 {
1211 Yyerror("index out of bounds")
1212 }
1213 }
1214 goto ret
1215
1216 case OINDEXMAP:
1217 if n.Etype == 1 {
1218 goto ret
1219 }
1220 walkexpr(&n.Left, init)
1221 walkexpr(&n.Right, init)
1222
Russ Cox382b44e2015-02-23 16:07:24 -05001223 t := n.Left.Type
1224 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001225 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
1226 switch Simsimtype(t.Down) {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001227 case TINT32, TUINT32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001228 p = "mapaccess1_fast32"
1229
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001230 case TINT64, TUINT64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001231 p = "mapaccess1_fast64"
1232
1233 case TSTRING:
1234 p = "mapaccess1_faststr"
1235 }
1236 }
1237
Russ Cox382b44e2015-02-23 16:07:24 -05001238 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001239 if p != "" {
1240 // fast versions take key by value
1241 key = n.Right
1242 } else {
1243 // standard version takes key by reference.
1244 // orderexpr made sure key is addressable.
1245 key = Nod(OADDR, n.Right, nil)
1246
1247 p = "mapaccess1"
1248 }
1249
1250 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1251 n = Nod(OIND, n, nil)
1252 n.Type = t.Type
1253 n.Typecheck = 1
1254
1255 // mapaccess needs a zero value to be at least this big.
1256 if zerosize < t.Type.Width {
1257 zerosize = t.Type.Width
1258 }
1259 goto ret
1260
1261 case ORECV:
1262 Fatal("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001263
1264 case OSLICE:
1265 if n.Right != nil && n.Right.Left == nil && n.Right.Right == nil { // noop
1266 walkexpr(&n.Left, init)
1267 n = n.Left
1268 goto ret
1269 }
1270 fallthrough
1271
1272 // fallthrough
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001273 case OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001274 if n.Right == nil { // already processed
1275 goto ret
1276 }
1277
1278 walkexpr(&n.Left, init)
1279
1280 // cgen_slice can't handle string literals as source
1281 // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
1282 if (n.Op == OSLICESTR && n.Left.Op == OLITERAL) || (n.Left.Op == OINDEX) {
1283 n.Left = copyexpr(n.Left, n.Left.Type, init)
1284 } else {
1285 n.Left = safeexpr(n.Left, init)
1286 }
1287 walkexpr(&n.Right.Left, init)
1288 n.Right.Left = safeexpr(n.Right.Left, init)
1289 walkexpr(&n.Right.Right, init)
1290 n.Right.Right = safeexpr(n.Right.Right, init)
David Chaseffe7fbf2015-03-27 12:34:45 -04001291 n = sliceany(n, init) // chops n.Right, sets n.List
Russ Cox8c195bd2015-02-13 14:40:36 -05001292 goto ret
1293
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001294 case OSLICE3, OSLICE3ARR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001295 if n.Right == nil { // already processed
1296 goto ret
1297 }
1298
1299 walkexpr(&n.Left, init)
1300
1301 // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
1302 // TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
1303 if n.Left.Op == OINDEX {
1304 n.Left = copyexpr(n.Left, n.Left.Type, init)
1305 } else {
1306 n.Left = safeexpr(n.Left, init)
1307 }
1308 walkexpr(&n.Right.Left, init)
1309 n.Right.Left = safeexpr(n.Right.Left, init)
1310 walkexpr(&n.Right.Right.Left, init)
1311 n.Right.Right.Left = safeexpr(n.Right.Right.Left, init)
1312 walkexpr(&n.Right.Right.Right, init)
1313 n.Right.Right.Right = safeexpr(n.Right.Right.Right, init)
David Chaseffe7fbf2015-03-27 12:34:45 -04001314 n = sliceany(n, init) // chops n.Right, sets n.List
Russ Cox8c195bd2015-02-13 14:40:36 -05001315 goto ret
1316
1317 case OADDR:
1318 walkexpr(&n.Left, init)
1319 goto ret
1320
1321 case ONEW:
1322 if n.Esc == EscNone && n.Type.Type.Width < 1<<16 {
Russ Cox382b44e2015-02-23 16:07:24 -05001323 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001324 r = Nod(OAS, r, nil) // zero temp
1325 typecheck(&r, Etop)
1326 *init = list(*init, r)
1327 r = Nod(OADDR, r.Left, nil)
1328 typecheck(&r, Erv)
1329 n = r
1330 } else {
1331 n = callnew(n.Type.Type)
1332 }
1333
1334 goto ret
1335
1336 // If one argument to the comparison is an empty string,
1337 // comparing the lengths instead will yield the same result
1338 // without the function call.
1339 case OCMPSTR:
Russ Coxbed1f902015-03-02 16:03:26 -05001340 if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval) == 0) {
Russ Cox382b44e2015-02-23 16:07:24 -05001341 r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001342 typecheck(&r, Erv)
1343 walkexpr(&r, init)
1344 r.Type = n.Type
1345 n = r
1346 goto ret
1347 }
1348
1349 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Russ Coxdc7b54b2015-02-17 22:13:49 -05001350 if (n.Etype == OEQ || n.Etype == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && count(n.Left.List) == 2 && Isconst(n.Left.List.Next.N, CTSTR) && cmpslit(n.Right, n.Left.List.Next.N) == 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05001351 r := Nod(int(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001352 typecheck(&r, Erv)
1353 walkexpr(&r, init)
1354 r.Type = n.Type
1355 n = r
1356 goto ret
1357 }
1358
Russ Cox382b44e2015-02-23 16:07:24 -05001359 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001360 if n.Etype == OEQ || n.Etype == ONE {
1361 // prepare for rewrite below
1362 n.Left = cheapexpr(n.Left, init)
1363
1364 n.Right = cheapexpr(n.Right, init)
1365
1366 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1367
1368 // quick check of len before full compare for == or !=
1369 // eqstring assumes that the lengths are equal
1370 if n.Etype == OEQ {
1371 // len(left) == len(right) && eqstring(left, right)
1372 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1373 } else {
1374 // len(left) != len(right) || !eqstring(left, right)
1375 r = Nod(ONOT, r, nil)
1376
1377 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1378 }
1379
1380 typecheck(&r, Erv)
1381 walkexpr(&r, nil)
1382 } else {
1383 // sys_cmpstring(s1, s2) :: 0
1384 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1385
1386 r = Nod(int(n.Etype), r, Nodintconst(0))
1387 }
1388
1389 typecheck(&r, Erv)
1390 if n.Type.Etype != TBOOL {
1391 Fatal("cmp %v", Tconv(n.Type, 0))
1392 }
1393 r.Type = n.Type
1394 n = r
1395 goto ret
1396
1397 case OADDSTR:
1398 n = addstr(n, init)
1399 goto ret
1400
1401 case OAPPEND:
Dave Cheneyd3287562015-03-09 16:24:07 +11001402 if n.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001403 n = appendslice(n, init) // also works for append(slice, string).
1404 } else {
1405 n = walkappend(n, init)
1406 }
1407 goto ret
1408
1409 case OCOPY:
1410 n = copyany(n, init, flag_race)
1411 goto ret
1412
1413 // cannot use chanfn - closechan takes any, not chan any
1414 case OCLOSE:
Russ Cox382b44e2015-02-23 16:07:24 -05001415 fn := syslook("closechan", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001416
Russ Cox13f9c8b2015-03-08 13:33:49 -04001417 substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001418 n = mkcall1(fn, nil, init, n.Left)
1419 goto ret
1420
1421 case OMAKECHAN:
1422 n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
1423 goto ret
1424
1425 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001426 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001427
Russ Cox382b44e2015-02-23 16:07:24 -05001428 fn := syslook("makemap", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001429
Russ Cox382b44e2015-02-23 16:07:24 -05001430 a := nodnil() // hmap buffer
1431 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001432 if n.Esc == EscNone {
1433 // Allocate hmap buffer on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001434 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001435
1436 a = Nod(OAS, var_, nil) // zero temp
1437 typecheck(&a, Etop)
1438 *init = list(*init, a)
1439 a = Nod(OADDR, var_, nil)
1440
1441 // Allocate one bucket on stack.
1442 // Maximum key/value size is 128 bytes, larger objects
1443 // are stored with an indirection. So max bucket size is 2048+eps.
1444 var_ = temp(mapbucket(t))
1445
1446 r = Nod(OAS, var_, nil) // zero temp
1447 typecheck(&r, Etop)
1448 *init = list(*init, r)
1449 r = Nod(OADDR, var_, nil)
1450 }
1451
Russ Cox13f9c8b2015-03-08 13:33:49 -04001452 substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001453 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
1454 goto ret
1455
1456 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001457 l := n.Left
1458 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001459 if r == nil {
1460 r = safeexpr(l, init)
1461 l = r
1462 }
Russ Cox382b44e2015-02-23 16:07:24 -05001463 t := n.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -05001464 if n.Esc == EscNone && Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.Xval) < (1<<16)/t.Type.Width) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001465 // var arr [r]T
1466 // n = arr[:l]
1467 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001468 var_ := temp(t)
1469 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001470 typecheck(&a, Etop)
1471 *init = list(*init, a)
Russ Cox382b44e2015-02-23 16:07:24 -05001472 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001473 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001474 typecheck(&r, Erv)
1475 walkexpr(&r, init)
1476 n = r
1477 } else {
1478 // makeslice(t *Type, nel int64, max int64) (ary []any)
Russ Cox382b44e2015-02-23 16:07:24 -05001479 fn := syslook("makeslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001480
Russ Cox13f9c8b2015-03-08 13:33:49 -04001481 substArgTypes(fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001482 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1483 }
1484
1485 goto ret
1486
1487 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001488 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001489 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001490 t := aindex(Nodintconst(4), Types[TUINT8])
1491 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001492 a = Nod(OADDR, var_, nil)
1493 }
1494
1495 // intstring(*[4]byte, rune)
1496 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1497
1498 goto ret
1499
1500 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001501 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001502 if n.Esc == EscNone {
1503 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001504 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001505
1506 a = Nod(OADDR, temp(t), nil)
1507 }
1508
1509 // slicebytetostring(*[32]byte, []byte) string;
1510 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1511
1512 goto ret
1513
1514 // slicebytetostringtmp([]byte) string;
1515 case OARRAYBYTESTRTMP:
1516 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1517
1518 goto ret
1519
1520 // slicerunetostring(*[32]byte, []rune) string;
1521 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001522 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001523
1524 if n.Esc == EscNone {
1525 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001526 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001527
1528 a = Nod(OADDR, temp(t), nil)
1529 }
1530
1531 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
1532 goto ret
1533
1534 // stringtoslicebyte(*32[byte], string) []byte;
1535 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001536 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001537
1538 if n.Esc == EscNone {
1539 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001540 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001541
1542 a = Nod(OADDR, temp(t), nil)
1543 }
1544
1545 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
1546 goto ret
1547
1548 // stringtoslicebytetmp(string) []byte;
1549 case OSTRARRAYBYTETMP:
1550 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1551
1552 goto ret
1553
1554 // stringtoslicerune(*[32]rune, string) []rune
1555 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001556 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001557
1558 if n.Esc == EscNone {
1559 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001560 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001561
1562 a = Nod(OADDR, temp(t), nil)
1563 }
1564
1565 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
1566 goto ret
1567
1568 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1569 case OCMPIFACE:
1570 if !Eqtype(n.Left.Type, n.Right.Type) {
1571 Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), Tconv(n.Left.Type, 0), Tconv(n.Right.Type, 0))
1572 }
Russ Cox382b44e2015-02-23 16:07:24 -05001573 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001574 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001575 fn = syslook("efaceeq", 1)
1576 } else {
1577 fn = syslook("ifaceeq", 1)
1578 }
1579
1580 n.Right = cheapexpr(n.Right, init)
1581 n.Left = cheapexpr(n.Left, init)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001582 substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001583 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05001584 if n.Etype == ONE {
1585 r = Nod(ONOT, r, nil)
1586 }
1587
1588 // check itable/type before full compare.
1589 if n.Etype == OEQ {
1590 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1591 } else {
1592 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1593 }
1594 typecheck(&r, Erv)
1595 walkexpr(&r, init)
1596 r.Type = n.Type
1597 n = r
1598 goto ret
1599
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001600 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001601 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001602 anylit(0, n, var_, init)
1603 n = var_
1604 goto ret
1605
1606 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001607 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001608 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1609 walkexpr(&n1, init)
1610 n1 = Nod(OADDR, n1, nil)
1611 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
1612 goto ret
1613
1614 case OCLOSURE:
1615 n = walkclosure(n, init)
1616 goto ret
1617
1618 case OCALLPART:
1619 n = walkpartialcall(n, init)
1620 goto ret
1621 }
1622
1623 Fatal("missing switch %v", Oconv(int(n.Op), 0))
1624
1625 // Expressions that are constant at run time but not
1626 // considered const by the language spec are not turned into
1627 // constants until walk. For example, if n is y%1 == 0, the
1628 // walk of y%1 may have replaced it by 0.
1629 // Check whether n with its updated args is itself now a constant.
1630ret:
Russ Cox382b44e2015-02-23 16:07:24 -05001631 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001632
1633 evconst(n)
1634 n.Type = t
1635 if n.Op == OLITERAL {
1636 typecheck(&n, Erv)
1637 }
1638
1639 ullmancalc(n)
1640
1641 if Debug['w'] != 0 && n != nil {
1642 Dump("walk", n)
1643 }
1644
1645 lineno = lno
1646 *np = n
1647}
1648
1649func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001650 // convas will turn map assigns into function calls,
1651 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001652 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001653
1654 if l.Op == OINDEXMAP {
1655 return n
1656 }
1657
1658 return convas(n, init)
1659}
1660
1661func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001662 /*
1663 * check assign expression list to
1664 * a expression list. called in
1665 * expr-list = expr-list
1666 */
1667
1668 // ensure order of evaluation for function calls
Russ Coxc8198342015-03-12 18:45:30 -04001669 for ll := nl; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001670 ll.N = safeexpr(ll.N, init)
1671 }
Russ Coxc8198342015-03-12 18:45:30 -04001672 for lr := nr; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001673 lr.N = safeexpr(lr.N, init)
1674 }
1675
Russ Cox175929b2015-03-02 14:22:05 -05001676 var nn *NodeList
Russ Coxc8198342015-03-12 18:45:30 -04001677 ll := nl
1678 lr := nr
Russ Coxd7f6d462015-03-09 00:31:13 -04001679 for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001680 // Do not generate 'x = x' during return. See issue 4014.
1681 if op == ORETURN && ll.N == lr.N {
1682 continue
1683 }
1684 nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
1685 }
1686
1687 // cannot happen: caller checked that lists had same length
1688 if ll != nil || lr != nil {
1689 Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nl, obj.FmtSign), Oconv(int(op), 0), Hconv(nr, obj.FmtSign), count(nl), count(nr), Curfn.Nname.Sym.Name)
1690 }
1691 return nn
1692}
1693
1694/*
1695 * l is an lv and rt is the type of an rv
1696 * return 1 if this implies a function call
1697 * evaluating the lv or a function call
1698 * in the conversion of the types
1699 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001700func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001701 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001702 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001703 }
Russ Cox175929b2015-03-02 14:22:05 -05001704 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001705 if needwritebarrier(l, &r) {
1706 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001707 }
1708 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001709 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001710 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001711 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001712}
1713
1714func ascompatet(op int, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
1715 var l *Node
1716 var tmp *Node
1717 var a *Node
1718 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001719 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001720
1721 /*
1722 * check assign type list to
1723 * a expression list. called in
1724 * expr-list = func()
1725 */
Russ Cox382b44e2015-02-23 16:07:24 -05001726 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001727
Russ Cox175929b2015-03-02 14:22:05 -05001728 var nn *NodeList
1729 var mm *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001730 ucount := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001731 for ll = nl; ll != nil; ll = ll.Next {
1732 if r == nil {
1733 break
1734 }
1735 l = ll.N
1736 if isblank(l) {
1737 r = structnext(&saver)
1738 continue
1739 }
1740
1741 // any lv that causes a fn call must be
1742 // deferred until all the return arguments
1743 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001744 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001745 tmp = temp(r.Type)
1746 typecheck(&tmp, Erv)
1747 a = Nod(OAS, l, tmp)
1748 a = convas(a, init)
1749 mm = list(mm, a)
1750 l = tmp
1751 }
1752
1753 a = Nod(OAS, l, nodarg(r, fp))
1754 a = convas(a, init)
1755 ullmancalc(a)
1756 if a.Ullman >= UINF {
1757 Dump("ascompatet ucount", a)
1758 ucount++
1759 }
1760
1761 nn = list(nn, a)
1762 r = structnext(&saver)
1763 }
1764
1765 if ll != nil || r != nil {
1766 Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
1767 }
1768
1769 if ucount != 0 {
1770 Fatal("ascompatet: too many function calls evaluating parameters")
1771 }
1772 return concat(nn, mm)
1773}
1774
1775/*
1776* package all the arguments that match a ... T parameter into a []T.
1777 */
1778func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
Dave Cheneye4981812015-03-10 09:58:01 +11001779 esc := uint8(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001780 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001781 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001782 }
1783
Russ Cox382b44e2015-02-23 16:07:24 -05001784 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001785 tslice.Type = l.Type.Type
1786 tslice.Bound = -1
1787
Russ Cox382b44e2015-02-23 16:07:24 -05001788 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 if count(lr0) == 0 {
1790 n = nodnil()
1791 n.Type = tslice
1792 } else {
1793 n = Nod(OCOMPLIT, nil, typenod(tslice))
1794 if ddd != nil {
1795 n.Alloc = ddd.Alloc // temporary to use
1796 }
1797 n.List = lr0
Dave Cheneye4981812015-03-10 09:58:01 +11001798 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001799 typecheck(&n, Erv)
1800 if n.Type == nil {
1801 Fatal("mkdotargslice: typecheck failed")
1802 }
1803 walkexpr(&n, init)
1804 }
1805
Russ Cox382b44e2015-02-23 16:07:24 -05001806 a := Nod(OAS, nodarg(l, fp), n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001807 nn = list(nn, convas(a, init))
1808 return nn
1809}
1810
1811/*
1812 * helpers for shape errors
1813 */
1814func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001815 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001816
Russ Cox382b44e2015-02-23 16:07:24 -05001817 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001818 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001819 first := 1
1820 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001821 if first != 0 {
1822 first = 0
1823 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001824 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001825 }
Russ Coxc8198342015-03-12 18:45:30 -04001826 fmt_ += Tconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001827 }
1828
1829 if first != 0 {
1830 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1831 }
1832 return fmt_
1833}
1834
1835func dumpnodetypes(l *NodeList, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001836 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001837
Russ Cox382b44e2015-02-23 16:07:24 -05001838 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001839 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001840 first := 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001841 for ; l != nil; l = l.Next {
1842 r = l.N
1843 if first != 0 {
1844 first = 0
1845 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001846 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001847 }
Russ Coxc8198342015-03-12 18:45:30 -04001848 fmt_ += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001849 }
1850
1851 if first != 0 {
1852 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1853 }
1854 return fmt_
1855}
1856
1857/*
1858 * check assign expression list to
1859 * a type list. called in
1860 * return expr-list
1861 * func(expr-list)
1862 */
Dave Cheneyd3287562015-03-09 16:24:07 +11001863func ascompatte(op int, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001864 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001865
Russ Cox382b44e2015-02-23 16:07:24 -05001866 lr0 := lr
1867 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001868 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001869 if lr != nil {
1870 r = lr.N
1871 }
Russ Cox175929b2015-03-02 14:22:05 -05001872 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001873
1874 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001875 var a *Node
1876 var l2 string
1877 var ll *Type
1878 var l1 string
Russ Cox8c195bd2015-02-13 14:40:36 -05001879 if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg != 0 {
1880 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001881 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001882 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001883 r = Nod(OCONVNOP, r, nil)
1884 r.Type = a.Type
1885 nn = list1(convas(Nod(OAS, a, r), init))
1886 goto ret
1887 }
1888
1889 // conversions involved.
1890 // copy into temporaries.
Russ Cox175929b2015-03-02 14:22:05 -05001891 var alist *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001892
Russ Cox382b44e2015-02-23 16:07:24 -05001893 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001894 a = temp(l.Type)
1895 alist = list(alist, a)
1896 }
1897
1898 a = Nod(OAS2, nil, nil)
1899 a.List = alist
1900 a.Rlist = lr
1901 typecheck(&a, Etop)
1902 walkstmt(&a)
1903 *init = list(*init, a)
1904 lr = alist
1905 r = lr.N
1906 l = Structfirst(&savel, nl)
1907 }
1908
1909loop:
Dave Cheneyd3287562015-03-09 16:24:07 +11001910 if l != nil && l.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001911 // the ddd parameter must be last
1912 ll = structnext(&savel)
1913
1914 if ll != nil {
1915 Yyerror("... must be last argument")
1916 }
1917
1918 // special case --
1919 // only if we are assigning a single ddd
1920 // argument to a ddd parameter then it is
1921 // passed thru unencapsulated
Dave Cheneyd3287562015-03-09 16:24:07 +11001922 if r != nil && lr.Next == nil && isddd && Eqtype(l.Type, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001923 a = Nod(OAS, nodarg(l, fp), r)
1924 a = convas(a, init)
1925 nn = list(nn, a)
1926 goto ret
1927 }
1928
1929 // normal case -- make a slice of all
1930 // remaining arguments and pass it to
1931 // the ddd parameter.
1932 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1933
1934 goto ret
1935 }
1936
1937 if l == nil || r == nil {
1938 if l != nil || r != nil {
1939 l1 = dumptypes(nl, "expected")
1940 l2 = dumpnodetypes(lr0, "given")
1941 if l != nil {
1942 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1943 } else {
1944 Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1945 }
1946 }
1947
1948 goto ret
1949 }
1950
1951 a = Nod(OAS, nodarg(l, fp), r)
1952 a = convas(a, init)
1953 nn = list(nn, a)
1954
1955 l = structnext(&savel)
1956 r = nil
1957 lr = lr.Next
1958 if lr != nil {
1959 r = lr.N
1960 }
1961 goto loop
1962
1963ret:
1964 for lr = nn; lr != nil; lr = lr.Next {
1965 lr.N.Typecheck = 1
1966 }
1967 return nn
1968}
1969
1970// generate code for print
1971func walkprint(nn *Node, init **NodeList) *Node {
1972 var r *Node
1973 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001974 var on *Node
1975 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001976 var et int
Russ Cox8c195bd2015-02-13 14:40:36 -05001977
Russ Cox382b44e2015-02-23 16:07:24 -05001978 op := int(nn.Op)
1979 all := nn.List
Russ Cox175929b2015-03-02 14:22:05 -05001980 var calls *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001981 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001982
1983 // Hoist all the argument evaluation up before the lock.
1984 walkexprlistcheap(all, init)
1985
1986 calls = list(calls, mkcall("printlock", nil, init))
1987
Russ Cox382b44e2015-02-23 16:07:24 -05001988 for l := all; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001989 if notfirst {
Russ Cox8c195bd2015-02-13 14:40:36 -05001990 calls = list(calls, mkcall("printsp", nil, init))
1991 }
1992
Russ Coxdc7b54b2015-02-17 22:13:49 -05001993 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001994
1995 n = l.N
1996 if n.Op == OLITERAL {
1997 switch n.Val.Ctype {
1998 case CTRUNE:
1999 defaultlit(&n, runetype)
2000
2001 case CTINT:
2002 defaultlit(&n, Types[TINT64])
2003
2004 case CTFLT:
2005 defaultlit(&n, Types[TFLOAT64])
2006 }
2007 }
2008
2009 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
2010 defaultlit(&n, Types[TINT64])
2011 }
2012 defaultlit(&n, nil)
2013 l.N = n
2014 if n.Type == nil || n.Type.Etype == TFORW {
2015 continue
2016 }
2017
2018 t = n.Type
2019 et = int(n.Type.Etype)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002020 if Isinter(n.Type) {
2021 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002022 on = syslook("printeface", 1)
2023 } else {
2024 on = syslook("printiface", 1)
2025 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002026 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002027 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Russ Cox8c195bd2015-02-13 14:40:36 -05002028 on = syslook("printpointer", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002029 substArgTypes(on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05002030 } else if Isslice(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002031 on = syslook("printslice", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002032 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002033 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002034 if et == TUINT64 {
2035 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
2036 on = syslook("printhex", 0)
2037 } else {
2038 on = syslook("printuint", 0)
2039 }
2040 } else {
2041 on = syslook("printint", 0)
2042 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002043 } else if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002044 on = syslook("printfloat", 0)
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002045 } else if Iscomplex[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002046 on = syslook("printcomplex", 0)
2047 } else if et == TBOOL {
2048 on = syslook("printbool", 0)
2049 } else if et == TSTRING {
2050 on = syslook("printstring", 0)
2051 } else {
2052 badtype(OPRINT, n.Type, nil)
2053 continue
2054 }
2055
2056 t = *getinarg(on.Type)
2057 if t != nil {
2058 t = t.Type
2059 }
2060 if t != nil {
2061 t = t.Type
2062 }
2063
2064 if !Eqtype(t, n.Type) {
2065 n = Nod(OCONV, n, nil)
2066 n.Type = t
2067 }
2068
2069 r = Nod(OCALL, on, nil)
2070 r.List = list1(n)
2071 calls = list(calls, r)
2072 }
2073
2074 if op == OPRINTN {
2075 calls = list(calls, mkcall("printnl", nil, nil))
2076 }
2077
2078 calls = list(calls, mkcall("printunlock", nil, init))
2079
2080 typechecklist(calls, Etop)
2081 walkexprlist(calls, init)
2082
2083 r = Nod(OEMPTY, nil, nil)
2084 typecheck(&r, Etop)
2085 walkexpr(&r, init)
2086 r.Ninit = calls
2087 return r
2088}
2089
2090func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002091 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -05002092 fn := syslook("newobject", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002093 substArgTypes(fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002094 return mkcall1(fn, Ptrto(t), nil, typename(t))
2095}
2096
Russ Coxdc7b54b2015-02-17 22:13:49 -05002097func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002098 n = outervalue(n)
2099
2100 // If n is *autotmp and autotmp = &foo, replace n with foo.
2101 // We introduce such temps when initializing struct literals.
2102 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox382b44e2015-02-23 16:07:24 -05002103 defn := n.Left.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002104 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2105 n = defn.Right.Left
2106 }
2107 }
2108
2109 switch n.Op {
2110 // OINDREG only ends up in walk if it's indirect of SP.
2111 case OINDREG:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002112 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002113
2114 case ONAME:
2115 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002116 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002117 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002118 }
2119 }
2120
Russ Coxdc7b54b2015-02-17 22:13:49 -05002121 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002122}
2123
Russ Coxdc7b54b2015-02-17 22:13:49 -05002124func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002125 n = outervalue(n)
2126
2127 switch n.Op {
2128 case ONAME:
2129 switch n.Class {
2130 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002131 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002132 }
2133 }
2134
Russ Coxdc7b54b2015-02-17 22:13:49 -05002135 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002136}
2137
2138// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002139func needwritebarrier(l *Node, r *Node) bool {
2140 if use_writebarrier == 0 {
2141 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002142 }
2143
2144 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002145 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002146 }
2147
2148 // No write barrier for write of non-pointers.
2149 dowidth(l.Type)
2150
2151 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002152 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002153 }
2154
2155 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002156 if isstack(l) {
2157 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002158 }
2159
2160 // No write barrier for implicit or explicit zeroing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002161 if r == nil || iszero(r) {
2162 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002163 }
2164
2165 // No write barrier for initialization to constant.
2166 if r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002167 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002168 }
2169
2170 // No write barrier for storing static (read-only) data.
2171 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002172 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002173 }
2174
2175 // No write barrier for storing address of stack values,
2176 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002177 if r.Op == OADDR && isstack(r.Left) {
2178 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002179 }
2180
2181 // No write barrier for storing address of global, which
2182 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002183 if r.Op == OADDR && isglobal(r.Left) {
2184 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002185 }
2186
2187 // No write barrier for reslice: x = x[0:y] or x = append(x, ...).
2188 // Both are compiled to modify x directly.
2189 // In the case of append, a write barrier may still be needed
2190 // if the underlying array grows, but the append code can
2191 // generate the write barrier directly in that case.
2192 // (It does not yet, but the cost of the write barrier will be
2193 // small compared to the cost of the allocation.)
Dave Cheneyb006d382015-03-06 18:42:58 +11002194 if r.Reslice {
Russ Cox8c195bd2015-02-13 14:40:36 -05002195 switch r.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002196 case OSLICE, OSLICE3, OSLICESTR, OAPPEND:
Russ Cox8c195bd2015-02-13 14:40:36 -05002197 break
2198
2199 default:
2200 Dump("bad reslice-l", l)
2201 Dump("bad reslice-r", r)
2202 }
2203
Russ Coxdc7b54b2015-02-17 22:13:49 -05002204 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002205 }
2206
2207 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002208 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002209}
2210
2211// TODO(rsc): Perhaps componentgen should run before this.
2212
Russ Cox01531372015-03-02 21:25:33 -05002213var applywritebarrier_bv Bvec
Russ Cox8c195bd2015-02-13 14:40:36 -05002214
2215func applywritebarrier(n *Node, init **NodeList) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002216 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002217 if Curfn != nil && Curfn.Func.Nowritebarrier {
Russ Cox8c195bd2015-02-13 14:40:36 -05002218 Yyerror("write barrier prohibited")
2219 }
Russ Cox382b44e2015-02-23 16:07:24 -05002220 t := n.Left.Type
2221 l := Nod(OADDR, n.Left, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002222 l.Etype = 1 // addr does not escape
2223 if t.Width == int64(Widthptr) {
2224 n = mkcall1(writebarrierfn("writebarrierptr", t, n.Right.Type), nil, init, l, n.Right)
2225 } else if t.Etype == TSTRING {
2226 n = mkcall1(writebarrierfn("writebarrierstring", t, n.Right.Type), nil, init, l, n.Right)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002227 } else if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002228 n = mkcall1(writebarrierfn("writebarrierslice", t, n.Right.Type), nil, init, l, n.Right)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002229 } else if Isinter(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002230 n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right)
2231 } else if t.Width <= int64(4*Widthptr) {
Russ Cox382b44e2015-02-23 16:07:24 -05002232 x := int64(0)
Russ Cox01531372015-03-02 21:25:33 -05002233 if applywritebarrier_bv.b == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 applywritebarrier_bv = bvalloc(obj.BitsPerPointer * 4)
2235 }
2236 bvresetall(applywritebarrier_bv)
2237 twobitwalktype1(t, &x, applywritebarrier_bv)
2238 const (
2239 PtrBit = 1
2240 )
2241 // The bvgets are looking for BitsPointer in successive slots.
2242 if obj.BitsPointer != 1<<PtrBit {
2243 Fatal("wrong PtrBit")
2244 }
Russ Cox382b44e2015-02-23 16:07:24 -05002245 var name string
Russ Cox8c195bd2015-02-13 14:40:36 -05002246 switch t.Width / int64(Widthptr) {
2247 default:
2248 Fatal("found writebarrierfat for %d-byte object of type %v", int(t.Width), Tconv(t, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002249
2250 case 2:
2251 name = fmt.Sprintf("writebarrierfat%d%d", bvget(applywritebarrier_bv, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit))
2252
2253 case 3:
2254 name = fmt.Sprintf("writebarrierfat%d%d%d", bvget(applywritebarrier_bv, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 2*obj.BitsPerPointer+PtrBit))
2255
2256 case 4:
2257 name = fmt.Sprintf("writebarrierfat%d%d%d%d", bvget(applywritebarrier_bv, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 2*obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 3*obj.BitsPerPointer+PtrBit))
2258 }
2259
2260 n = mkcall1(writebarrierfn(name, t, n.Right.Type), nil, init, l, nodnil(), n.Right)
2261 } else {
Russ Cox382b44e2015-02-23 16:07:24 -05002262 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002263 for r.Op == OCONVNOP {
2264 r = r.Left
2265 }
2266 r = Nod(OADDR, r, nil)
2267 r.Etype = 1 // addr does not escape
2268
2269 //warnl(n->lineno, "typedmemmove %T %N", t, r);
2270 n = mkcall1(writebarrierfn("typedmemmove", t, r.Left.Type), nil, init, typename(t), l, r)
2271 }
2272 }
2273
2274 return n
2275}
2276
2277func convas(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002278 if n.Op != OAS {
2279 Fatal("convas: not OAS %v", Oconv(int(n.Op), 0))
2280 }
2281
2282 n.Typecheck = 1
2283
Russ Cox382b44e2015-02-23 16:07:24 -05002284 var lt *Type
2285 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002286 if n.Left == nil || n.Right == nil {
2287 goto out
2288 }
2289
2290 lt = n.Left.Type
2291 rt = n.Right.Type
2292 if lt == nil || rt == nil {
2293 goto out
2294 }
2295
2296 if isblank(n.Left) {
2297 defaultlit(&n.Right, nil)
2298 goto out
2299 }
2300
2301 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002302 map_ := n.Left.Left
2303 key := n.Left.Right
2304 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002305 walkexpr(&map_, init)
2306 walkexpr(&key, init)
2307 walkexpr(&val, init)
2308
2309 // orderexpr made sure key and val are addressable.
2310 key = Nod(OADDR, key, nil)
2311
2312 val = Nod(OADDR, val, nil)
2313 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2314 goto out
2315 }
2316
2317 if !Eqtype(lt, rt) {
2318 n.Right = assignconv(n.Right, lt, "assignment")
2319 walkexpr(&n.Right, init)
2320 }
2321
2322out:
2323 ullmancalc(n)
2324 return n
2325}
2326
2327/*
2328 * from ascompat[te]
2329 * evaluating actual function arguments.
2330 * f(a,b)
2331 * if there is exactly one function expr,
2332 * then it is done first. otherwise must
2333 * make temp variables
2334 */
2335func reorder1(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002336 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002337
Russ Cox382b44e2015-02-23 16:07:24 -05002338 c := 0 // function calls
2339 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002340
Russ Cox382b44e2015-02-23 16:07:24 -05002341 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002342 n = l.N
2343 t++
2344 ullmancalc(n)
2345 if n.Ullman >= UINF {
2346 c++
2347 }
2348 }
2349
2350 if c == 0 || t == 1 {
2351 return all
2352 }
2353
Russ Cox175929b2015-03-02 14:22:05 -05002354 var g *NodeList // fncalls assigned to tempnames
2355 var f *Node // last fncall assigned to stack
2356 var r *NodeList // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002357 d := 0
2358 var a *Node
2359 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002360 n = l.N
2361 if n.Ullman < UINF {
2362 r = list(r, n)
2363 continue
2364 }
2365
2366 d++
2367 if d == c {
2368 f = n
2369 continue
2370 }
2371
2372 // make assignment of fncall to tempname
2373 a = temp(n.Right.Type)
2374
2375 a = Nod(OAS, a, n.Right)
2376 g = list(g, a)
2377
2378 // put normal arg assignment on list
2379 // with fncall replaced by tempname
2380 n.Right = a.Left
2381
2382 r = list(r, n)
2383 }
2384
2385 if f != nil {
2386 g = list(g, f)
2387 }
2388 return concat(g, r)
2389}
2390
2391/*
2392 * from ascompat[ee]
2393 * a,b = c,d
2394 * simultaneous assignment. there cannot
2395 * be later use of an earlier lvalue.
2396 *
2397 * function calls have been removed.
2398 */
2399func reorder3(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002400 var l *Node
2401
2402 // If a needed expression may be affected by an
2403 // earlier assignment, make an early copy of that
2404 // expression and use the copy instead.
Russ Cox175929b2015-03-02 14:22:05 -05002405 var early *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002406
Russ Cox175929b2015-03-02 14:22:05 -05002407 var mapinit *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002408 for list := all; list != nil; list = list.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002409 l = list.N.Left
2410
2411 // Save subexpressions needed on left side.
2412 // Drill through non-dereferences.
2413 for {
2414 if l.Op == ODOT || l.Op == OPAREN {
2415 l = l.Left
2416 continue
2417 }
2418
Russ Coxdc7b54b2015-02-17 22:13:49 -05002419 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002420 reorder3save(&l.Right, all, list, &early)
2421 l = l.Left
2422 continue
2423 }
2424
2425 break
2426 }
2427
2428 switch l.Op {
2429 default:
2430 Fatal("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002431
2432 case ONAME:
2433 break
2434
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002435 case OINDEX, OINDEXMAP:
Russ Cox8c195bd2015-02-13 14:40:36 -05002436 reorder3save(&l.Left, all, list, &early)
2437 reorder3save(&l.Right, all, list, &early)
2438 if l.Op == OINDEXMAP {
2439 list.N = convas(list.N, &mapinit)
2440 }
2441
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002442 case OIND, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05002443 reorder3save(&l.Left, all, list, &early)
2444 }
2445
2446 // Save expression on right side.
2447 reorder3save(&list.N.Right, all, list, &early)
2448 }
2449
2450 early = concat(mapinit, early)
2451 return concat(early, all)
2452}
2453
2454/*
2455 * if the evaluation of *np would be affected by the
2456 * assignments in all up to but not including stop,
2457 * copy into a temporary during *early and
2458 * replace *np with that temp.
2459 */
2460func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05002461 n := *np
Russ Coxdc7b54b2015-02-17 22:13:49 -05002462 if !aliased(n, all, stop) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002463 return
2464 }
2465
Russ Cox382b44e2015-02-23 16:07:24 -05002466 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002467 q = Nod(OAS, q, n)
2468 typecheck(&q, Etop)
2469 *early = list(*early, q)
2470 *np = q.Left
2471}
2472
2473/*
2474 * what's the outer value that a write to n affects?
2475 * outer value means containing struct or array.
2476 */
2477func outervalue(n *Node) *Node {
2478 for {
2479 if n.Op == OXDOT {
2480 Fatal("OXDOT in walk")
2481 }
2482 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2483 n = n.Left
2484 continue
2485 }
2486
Russ Coxdc7b54b2015-02-17 22:13:49 -05002487 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002488 n = n.Left
2489 continue
2490 }
2491
2492 break
2493 }
2494
2495 return n
2496}
2497
2498/*
2499 * Is it possible that the computation of n might be
2500 * affected by writes in as up to but not including stop?
2501 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002502func aliased(n *Node, all *NodeList, stop *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002503 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002504 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002505 }
2506
2507 // Look for obvious aliasing: a variable being assigned
2508 // during the all list and appearing in n.
2509 // Also record whether there are any writes to main memory.
2510 // Also record whether there are any writes to variables
2511 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002512 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002513
Russ Cox382b44e2015-02-23 16:07:24 -05002514 varwrite := 0
2515 var a *Node
2516 for l := all; l != stop; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002517 a = outervalue(l.N.Left)
2518 if a.Op != ONAME {
2519 memwrite = 1
2520 continue
2521 }
2522
2523 switch n.Class {
2524 default:
2525 varwrite = 1
2526 continue
2527
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002528 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002529 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002530 varwrite = 1
2531 continue
2532 }
2533
Russ Coxdc7b54b2015-02-17 22:13:49 -05002534 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002535 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002536 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002537 }
2538 }
2539 }
2540
2541 // The variables being written do not appear in n.
2542 // However, n might refer to computed addresses
2543 // that are being written.
2544
2545 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002546 if memwrite == 0 && varwrite == 0 {
2547 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002548 }
2549
2550 // If n does not refer to computed addresses
2551 // (that is, if n only refers to variables whose addresses
2552 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002553 if varexpr(n) {
2554 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002555 }
2556
2557 // Otherwise, both the writes and n refer to computed memory addresses.
2558 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002559 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002560}
2561
2562/*
2563 * does the evaluation of n only refer to variables
2564 * whose addresses have not been taken?
2565 * (and no other memory)
2566 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002567func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002568 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002569 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002570 }
2571
2572 switch n.Op {
2573 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002574 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002575
2576 case ONAME:
2577 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002578 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002579 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002580 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002581 }
2582 }
2583
Russ Coxdc7b54b2015-02-17 22:13:49 -05002584 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002585
2586 case OADD,
2587 OSUB,
2588 OOR,
2589 OXOR,
2590 OMUL,
2591 ODIV,
2592 OMOD,
2593 OLSH,
2594 ORSH,
2595 OAND,
2596 OANDNOT,
2597 OPLUS,
2598 OMINUS,
2599 OCOM,
2600 OPAREN,
2601 OANDAND,
2602 OOROR,
2603 ODOT, // but not ODOTPTR
2604 OCONV,
2605 OCONVNOP,
2606 OCONVIFACE,
2607 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002608 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002609 }
2610
2611 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002612 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002613}
2614
2615/*
2616 * is the name l mentioned in r?
2617 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002618func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002619 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002620 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002621 }
2622 switch r.Op {
2623 // match each right given left
2624 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002625 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002626
2627 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002628 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002629 }
2630
Russ Coxdc7b54b2015-02-17 22:13:49 -05002631 if vmatch2(l, r.Left) {
2632 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002633 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002634 if vmatch2(l, r.Right) {
2635 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002636 }
Russ Cox382b44e2015-02-23 16:07:24 -05002637 for ll := r.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002638 if vmatch2(l, ll.N) {
2639 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002640 }
2641 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002642 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002643}
2644
2645/*
2646 * is any name mentioned in l also mentioned in r?
Keith Randallcd5b1442015-03-11 12:58:47 -07002647 * called by sinit.go
Russ Cox8c195bd2015-02-13 14:40:36 -05002648 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002649func vmatch1(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002650 /*
2651 * isolate all left sides
2652 */
2653 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002654 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002655 }
2656 switch l.Op {
2657 case ONAME:
2658 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002659 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002660 break
2661
2662 // assignment to non-stack variable
2663 // must be delayed if right has function calls.
2664 default:
2665 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002666 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002667 }
2668 }
2669
2670 return vmatch2(l, r)
2671
2672 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002673 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002674 }
2675
Russ Coxdc7b54b2015-02-17 22:13:49 -05002676 if vmatch1(l.Left, r) {
2677 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002678 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002679 if vmatch1(l.Right, r) {
2680 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002681 }
Russ Cox382b44e2015-02-23 16:07:24 -05002682 for ll := l.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002683 if vmatch1(ll.N, r) {
2684 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002685 }
2686 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002687 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002688}
2689
2690/*
2691 * walk through argin parameters.
2692 * generate and return code to allocate
2693 * copies of escaped parameters to the heap.
2694 */
2695func paramstoheap(argin **Type, out int) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002696 var savet Iter
2697 var v *Node
2698 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002699
Russ Cox175929b2015-03-02 14:22:05 -05002700 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002701 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002702 v = t.Nname
2703 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2704 v = nil
2705 }
2706
2707 // For precise stacks, the garbage collector assumes results
2708 // are always live, so zero them always.
2709 if out != 0 {
2710 // Defer might stop a panic and show the
2711 // return values as they exist at the time of panic.
2712 // Make sure to zero them on entry to the function.
2713 nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
2714 }
2715
Russ Coxdc7b54b2015-02-17 22:13:49 -05002716 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002717 continue
2718 }
2719
2720 // generate allocation & copying code
2721 if compiling_runtime != 0 {
2722 Yyerror("%v escapes to heap, not allowed in runtime.", Nconv(v, 0))
2723 }
2724 if v.Alloc == nil {
2725 v.Alloc = callnew(v.Type)
2726 }
2727 nn = list(nn, Nod(OAS, v.Heapaddr, v.Alloc))
2728 if v.Class&^PHEAP != PPARAMOUT {
2729 as = Nod(OAS, v, v.Stackparam)
2730 v.Stackparam.Typecheck = 1
2731 typecheck(&as, Etop)
2732 as = applywritebarrier(as, &nn)
2733 nn = list(nn, as)
2734 }
2735 }
2736
2737 return nn
2738}
2739
2740/*
2741 * walk through argout parameters copying back to stack
2742 */
2743func returnsfromheap(argin **Type) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002744 var savet Iter
2745 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002746
Russ Cox175929b2015-03-02 14:22:05 -05002747 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002748 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002749 v = t.Nname
2750 if v == nil || v.Class != PHEAP|PPARAMOUT {
2751 continue
2752 }
2753 nn = list(nn, Nod(OAS, v.Stackparam, v))
2754 }
2755
2756 return nn
2757}
2758
2759/*
2760 * take care of migrating any function in/out args
2761 * between the stack and the heap. adds code to
2762 * curfn's before and after lists.
2763 */
2764func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002765 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002766 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002767 nn := paramstoheap(getthis(Curfn.Type), 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05002768 nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
2769 nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002770 Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
2771 lineno = Curfn.Func.Endlineno
2772 Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05002773 lineno = lno
2774}
2775
2776func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002777 if fn.Type == nil || fn.Type.Etype != TFUNC {
2778 Fatal("mkcall %v %v", Nconv(fn, 0), Tconv(fn.Type, 0))
2779 }
2780
Russ Cox175929b2015-03-02 14:22:05 -05002781 var args *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002782 n := fn.Type.Intuple
2783 for i := 0; i < n; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05002784 args = list(args, va[i])
2785 }
2786
Russ Cox382b44e2015-02-23 16:07:24 -05002787 r := Nod(OCALL, fn, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002788 r.List = args
2789 if fn.Type.Outtuple > 0 {
2790 typecheck(&r, Erv|Efnstruct)
2791 } else {
2792 typecheck(&r, Etop)
2793 }
2794 walkexpr(&r, init)
2795 r.Type = t
2796 return r
2797}
2798
2799func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
2800 return vmkcall(syslook(name, 0), t, init, args)
2801}
2802
2803func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
2804 return vmkcall(fn, t, init, args)
2805}
2806
2807func conv(n *Node, t *Type) *Node {
2808 if Eqtype(n.Type, t) {
2809 return n
2810 }
2811 n = Nod(OCONV, n, nil)
2812 n.Type = t
2813 typecheck(&n, Erv)
2814 return n
2815}
2816
2817func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002818 if t.Etype != TCHAN {
2819 Fatal("chanfn %v", Tconv(t, 0))
2820 }
Russ Cox382b44e2015-02-23 16:07:24 -05002821 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002822 switch n {
2823 default:
2824 Fatal("chanfn %d", n)
2825 case 1:
2826 substArgTypes(fn, t.Type)
2827 case 2:
2828 substArgTypes(fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002829 }
2830 return fn
2831}
2832
2833func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002834 if t.Etype != TMAP {
2835 Fatal("mapfn %v", Tconv(t, 0))
2836 }
Russ Cox382b44e2015-02-23 16:07:24 -05002837 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002838 substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002839 return fn
2840}
2841
2842func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002843 if t.Etype != TMAP {
2844 Fatal("mapfn %v", Tconv(t, 0))
2845 }
Russ Cox382b44e2015-02-23 16:07:24 -05002846 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002847 substArgTypes(fn, t.Down, t.Type, t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05002848 return fn
2849}
2850
2851func writebarrierfn(name string, l *Type, r *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002852 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002853 substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002854 return fn
2855}
2856
2857func addstr(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002858 // orderexpr rewrote OADDSTR to have a list of strings.
Russ Cox382b44e2015-02-23 16:07:24 -05002859 c := count(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002860
2861 if c < 2 {
2862 Yyerror("addstr count %d too small", c)
2863 }
2864
Russ Cox382b44e2015-02-23 16:07:24 -05002865 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002866 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002867 sz := int64(0)
2868 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002869 if n.Op == OLITERAL {
Russ Coxbed1f902015-03-02 16:03:26 -05002870 sz += int64(len(n.Val.U.Sval))
Russ Cox8c195bd2015-02-13 14:40:36 -05002871 }
2872 }
2873
2874 // Don't allocate the buffer if the result won't fit.
2875 if sz < tmpstringbufsize {
2876 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002877 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002878
2879 buf = Nod(OADDR, temp(t), nil)
2880 }
2881 }
2882
2883 // build list of string arguments
Russ Cox382b44e2015-02-23 16:07:24 -05002884 args := list1(buf)
Russ Cox8c195bd2015-02-13 14:40:36 -05002885
Russ Cox382b44e2015-02-23 16:07:24 -05002886 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002887 args = list(args, conv(l.N, Types[TSTRING]))
2888 }
2889
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002890 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002891 if c <= 5 {
2892 // small numbers of strings use direct runtime helpers.
2893 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002894 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002895 } else {
2896 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002897 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002898
Russ Cox382b44e2015-02-23 16:07:24 -05002899 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002900 t.Type = Types[TSTRING]
2901 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002902 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05002903 slice.Alloc = n.Alloc
2904 slice.List = args.Next // skip buf arg
2905 args = list1(buf)
2906 args = list(args, slice)
2907 slice.Esc = EscNone
2908 }
2909
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002910 cat := syslook(fn, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05002911 r := Nod(OCALL, cat, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002912 r.List = args
2913 typecheck(&r, Erv)
2914 walkexpr(&r, init)
2915 r.Type = n.Type
2916
2917 return r
2918}
2919
2920// expand append(l1, l2...) to
2921// init {
2922// s := l1
2923// if n := len(l1) + len(l2) - cap(s); n > 0 {
2924// s = growslice(s, n)
2925// }
2926// s = s[:len(l1)+len(l2)]
2927// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2928// }
2929// s
2930//
2931// l2 is allowed to be a string.
2932func appendslice(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002933 walkexprlistsafe(n.List, init)
2934
2935 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2936 // and n are name or literal, but those may index the slice we're
2937 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05002938 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002939 l.N = cheapexpr(l.N, init)
2940 }
2941
Russ Cox382b44e2015-02-23 16:07:24 -05002942 l1 := n.List.N
2943 l2 := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -05002944
Russ Cox382b44e2015-02-23 16:07:24 -05002945 s := temp(l1.Type) // var s []T
Russ Cox175929b2015-03-02 14:22:05 -05002946 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002947 l = list(l, Nod(OAS, s, l1)) // s = l1
2948
Russ Cox382b44e2015-02-23 16:07:24 -05002949 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002950
Russ Cox382b44e2015-02-23 16:07:24 -05002951 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002952
2953 // n := len(s) + len(l2) - cap(s)
2954 nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
2955
2956 nif.Ntest = Nod(OGT, nt, Nodintconst(0))
2957
Matthew Dempsky81d40722015-02-27 15:13:05 +09002958 // instantiate growslice(Type*, []any, int) []any
Russ Coxcdb7d7d2015-03-05 13:57:36 -05002959 fn := syslook("growslice", 1) // growslice(<type>, old []T, n int64) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002960 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002961
2962 // s = growslice(T, s, n)
Matthew Dempsky81d40722015-02-27 15:13:05 +09002963 nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002964
2965 l = list(l, nif)
2966
2967 if haspointers(l1.Type.Type) {
2968 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002969 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002970
2971 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002972 nptr2 := l2
2973 fn := syslook("typedslicecopy", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002974 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002975 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
Russ Cox8c195bd2015-02-13 14:40:36 -05002976 l = list(l, nt)
2977 } else if flag_race != 0 {
2978 // rely on runtime to instrument copy.
2979 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002980 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002981
2982 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002983 nptr2 := l2
2984 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002985 if l2.Type.Etype == TSTRING {
2986 fn = syslook("slicestringcopy", 1)
2987 } else {
2988 fn = syslook("slicecopy", 1)
2989 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002990 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002991 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05002992 l = list(l, nt)
2993 } else {
2994 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002995 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002996
Russ Coxdc7b54b2015-02-17 22:13:49 -05002997 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002998 nptr1 = Nod(OADDR, nptr1, nil)
2999
Russ Cox382b44e2015-02-23 16:07:24 -05003000 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003001
Russ Cox382b44e2015-02-23 16:07:24 -05003002 fn := syslook("memmove", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003003 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003004
Russ Cox382b44e2015-02-23 16:07:24 -05003005 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
Russ Cox8c195bd2015-02-13 14:40:36 -05003006
3007 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Russ Cox382b44e2015-02-23 16:07:24 -05003008 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
Russ Cox8c195bd2015-02-13 14:40:36 -05003009 l = list(l, nt)
3010 }
3011
3012 // s = s[:len(l1)+len(l2)]
3013 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
3014
3015 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
3016 nt.Etype = 1
3017 l = list(l, Nod(OAS, s, nt))
3018
3019 typechecklist(l, Etop)
3020 walkstmtlist(l)
3021 *init = concat(*init, l)
3022 return s
3023}
3024
3025// expand append(src, a [, b]* ) to
3026//
3027// init {
3028// s := src
3029// const argc = len(args) - 1
3030// if cap(s) - len(s) < argc {
3031// s = growslice(s, argc)
3032// }
3033// n := len(s)
3034// s = s[:n+argc]
3035// s[n] = a
3036// s[n+1] = b
3037// ...
3038// }
3039// s
3040func walkappend(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003041 walkexprlistsafe(n.List, init)
3042
3043 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
3044 // and n are name or literal, but those may index the slice we're
3045 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05003046 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003047 l.N = cheapexpr(l.N, init)
3048 }
3049
Russ Cox382b44e2015-02-23 16:07:24 -05003050 nsrc := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -05003051
3052 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003053 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003054 nsrc.Type = nsrc.Type.Type.Type
3055 }
Russ Cox382b44e2015-02-23 16:07:24 -05003056 argc := count(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003057 if argc < 1 {
3058 return nsrc
3059 }
3060
Russ Cox175929b2015-03-02 14:22:05 -05003061 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003062
Russ Cox382b44e2015-02-23 16:07:24 -05003063 ns := temp(nsrc.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003064 l = list(l, Nod(OAS, ns, nsrc)) // s = src
3065
Russ Cox382b44e2015-02-23 16:07:24 -05003066 na := Nodintconst(int64(argc)) // const argc
3067 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox8c195bd2015-02-13 14:40:36 -05003068 nx.Ntest = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
3069
Matthew Dempsky81d40722015-02-27 15:13:05 +09003070 fn := syslook("growslice", 1) // growslice(<type>, old []T, n int) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003071 substArgTypes(fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003072
Matthew Dempsky81d40722015-02-27 15:13:05 +09003073 nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, na)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003074
3075 l = list(l, nx)
3076
Russ Cox382b44e2015-02-23 16:07:24 -05003077 nn := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003078 l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
3079
3080 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
3081 nx.Etype = 1
3082 l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
3083
Russ Cox382b44e2015-02-23 16:07:24 -05003084 for a := n.List.Next; a != nil; a = a.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003085 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003086 nx.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05003087 l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg
3088 if a.Next != nil {
3089 l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
3090 }
3091 }
3092
3093 typechecklist(l, Etop)
3094 walkstmtlist(l)
3095 *init = concat(*init, l)
3096 return ns
3097}
3098
3099// Lower copy(a, b) to a memmove call or a runtime call.
3100//
3101// init {
3102// n := len(a)
3103// if n > len(b) { n = len(b) }
3104// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3105// }
3106// n;
3107//
3108// Also works if b is a string.
3109//
3110func copyany(n *Node, init **NodeList, runtimecall int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003111 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05003112 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003113 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
3114 }
3115
3116 if runtimecall != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05003117 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003118 if n.Right.Type.Etype == TSTRING {
3119 fn = syslook("slicestringcopy", 1)
3120 } else {
3121 fn = syslook("slicecopy", 1)
3122 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04003123 substArgTypes(fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003124 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3125 }
3126
3127 walkexpr(&n.Left, init)
3128 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003129 nl := temp(n.Left.Type)
3130 nr := temp(n.Right.Type)
Russ Cox175929b2015-03-02 14:22:05 -05003131 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003132 l = list(l, Nod(OAS, nl, n.Left))
3133 l = list(l, Nod(OAS, nr, n.Right))
3134
Russ Cox382b44e2015-02-23 16:07:24 -05003135 nfrm := Nod(OSPTR, nr, nil)
3136 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003137
Russ Cox382b44e2015-02-23 16:07:24 -05003138 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003139
3140 // n = len(to)
3141 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
3142
3143 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003144 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003145
3146 nif.Ntest = Nod(OGT, nlen, Nod(OLEN, nr, nil))
3147 nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
3148 l = list(l, nif)
3149
3150 // Call memmove.
Russ Cox382b44e2015-02-23 16:07:24 -05003151 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003152
Russ Cox13f9c8b2015-03-08 13:33:49 -04003153 substArgTypes(fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003154 nwid := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -05003155 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
3156 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
3157 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
3158
3159 typechecklist(l, Etop)
3160 walkstmtlist(l)
3161 *init = concat(*init, l)
3162 return nlen
3163}
3164
3165// Generate frontend part for OSLICE[3][ARR|STR]
3166//
3167func sliceany(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003168 var hb *Node
3169 var cb *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003170
3171 // print("before sliceany: %+N\n", n);
3172
Russ Cox382b44e2015-02-23 16:07:24 -05003173 src := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003174
Russ Cox382b44e2015-02-23 16:07:24 -05003175 lb := n.Right.Left
3176 slice3 := n.Op == OSLICE3 || n.Op == OSLICE3ARR
Russ Coxdc7b54b2015-02-17 22:13:49 -05003177 if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003178 hb = n.Right.Right.Left
3179 cb = n.Right.Right.Right
3180 } else {
3181 hb = n.Right.Right
3182 cb = nil
3183 }
3184
Russ Cox382b44e2015-02-23 16:07:24 -05003185 bounded := int(n.Etype)
Russ Cox8c195bd2015-02-13 14:40:36 -05003186
Russ Cox382b44e2015-02-23 16:07:24 -05003187 var bound *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003188 if n.Op == OSLICESTR {
3189 bound = Nod(OLEN, src, nil)
3190 } else {
3191 bound = Nod(OCAP, src, nil)
3192 }
3193
3194 typecheck(&bound, Erv)
3195 walkexpr(&bound, init) // if src is an array, bound will be a const now.
3196
3197 // static checks if possible
Russ Cox382b44e2015-02-23 16:07:24 -05003198 bv := int64(1 << 50)
Russ Cox8c195bd2015-02-13 14:40:36 -05003199
Russ Coxdc7b54b2015-02-17 22:13:49 -05003200 if Isconst(bound, CTINT) {
3201 if !Smallintconst(bound) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003202 Yyerror("array len too large")
3203 } else {
3204 bv = Mpgetfix(bound.Val.U.Xval)
3205 }
3206 }
3207
Russ Coxdc7b54b2015-02-17 22:13:49 -05003208 if Isconst(cb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003209 cbv := Mpgetfix(cb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003210 if cbv < 0 || cbv > bv {
3211 Yyerror("slice index out of bounds")
3212 }
3213 }
3214
Russ Coxdc7b54b2015-02-17 22:13:49 -05003215 if Isconst(hb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003216 hbv := Mpgetfix(hb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003217 if hbv < 0 || hbv > bv {
3218 Yyerror("slice index out of bounds")
3219 }
3220 }
3221
Russ Coxdc7b54b2015-02-17 22:13:49 -05003222 if Isconst(lb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003223 lbv := Mpgetfix(lb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003224 if lbv < 0 || lbv > bv {
3225 Yyerror("slice index out of bounds")
3226 lbv = -1
3227 }
3228
3229 if lbv == 0 {
3230 lb = nil
3231 }
3232 }
3233
3234 // Checking src[lb:hb:cb] or src[lb:hb].
3235 // if chk0 || chk1 || chk2 { panicslice() }
Russ Cox8c195bd2015-02-13 14:40:36 -05003236
3237 // All comparisons are unsigned to avoid testing < 0.
Russ Cox382b44e2015-02-23 16:07:24 -05003238 bt := Types[Simtype[TUINT]]
Russ Cox8c195bd2015-02-13 14:40:36 -05003239
3240 if cb != nil && cb.Type.Width > 4 {
3241 bt = Types[TUINT64]
3242 }
3243 if hb != nil && hb.Type.Width > 4 {
3244 bt = Types[TUINT64]
3245 }
3246 if lb != nil && lb.Type.Width > 4 {
3247 bt = Types[TUINT64]
3248 }
3249
3250 bound = cheapexpr(conv(bound, bt), init)
3251
Russ Cox44928112015-03-02 20:34:22 -05003252 var chk0 *Node // cap(src) < cb
Russ Cox8c195bd2015-02-13 14:40:36 -05003253 if cb != nil {
3254 cb = cheapexpr(conv(cb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003255 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003256 chk0 = Nod(OLT, bound, cb)
3257 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003258 } else if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003259 // When we figure out what this means, implement it.
3260 Fatal("slice3 with cb == N") // rejected by parser
3261 }
3262
Russ Cox44928112015-03-02 20:34:22 -05003263 var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
Russ Cox8c195bd2015-02-13 14:40:36 -05003264 if hb != nil {
3265 hb = cheapexpr(conv(hb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003266 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003267 if cb != nil {
3268 chk1 = Nod(OLT, cb, hb)
3269 } else {
3270 chk1 = Nod(OLT, bound, hb)
3271 }
3272 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003273 } else if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003274 // When we figure out what this means, implement it.
3275 Fatal("slice3 with hb == N") // rejected by parser
3276 } else if n.Op == OSLICEARR {
3277 hb = bound
3278 } else {
3279 hb = Nod(OLEN, src, nil)
3280 typecheck(&hb, Erv)
3281 walkexpr(&hb, init)
3282 hb = cheapexpr(conv(hb, bt), init)
3283 }
3284
Russ Cox44928112015-03-02 20:34:22 -05003285 var chk2 *Node // hb < lb
Russ Cox8c195bd2015-02-13 14:40:36 -05003286 if lb != nil {
3287 lb = cheapexpr(conv(lb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003288 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003289 chk2 = Nod(OLT, hb, lb)
3290 }
3291 }
3292
3293 if chk0 != nil || chk1 != nil || chk2 != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003294 chk := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003295 chk.Nbody = list1(mkcall("panicslice", nil, init))
3296 chk.Likely = -1
3297 if chk0 != nil {
3298 chk.Ntest = chk0
3299 }
3300 if chk1 != nil {
3301 if chk.Ntest == nil {
3302 chk.Ntest = chk1
3303 } else {
3304 chk.Ntest = Nod(OOROR, chk.Ntest, chk1)
3305 }
3306 }
3307
3308 if chk2 != nil {
3309 if chk.Ntest == nil {
3310 chk.Ntest = chk2
3311 } else {
3312 chk.Ntest = Nod(OOROR, chk.Ntest, chk2)
3313 }
3314 }
3315
3316 typecheck(&chk, Etop)
3317 walkstmt(&chk)
3318 *init = concat(*init, chk.Ninit)
3319 chk.Ninit = nil
3320 *init = list(*init, chk)
3321 }
3322
3323 // prepare new cap, len and offs for backend cgen_slice
3324 // cap = bound [ - lo ]
3325 n.Right = nil
3326
3327 n.List = nil
Russ Coxdc7b54b2015-02-17 22:13:49 -05003328 if !slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003329 cb = bound
3330 }
3331 if lb == nil {
3332 bound = conv(cb, Types[Simtype[TUINT]])
3333 } else {
3334 bound = Nod(OSUB, conv(cb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
3335 }
3336 typecheck(&bound, Erv)
3337 walkexpr(&bound, init)
3338 n.List = list(n.List, bound)
3339
3340 // len = hi [ - lo]
3341 if lb == nil {
3342 hb = conv(hb, Types[Simtype[TUINT]])
3343 } else {
3344 hb = Nod(OSUB, conv(hb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
3345 }
3346 typecheck(&hb, Erv)
3347 walkexpr(&hb, init)
3348 n.List = list(n.List, hb)
3349
3350 // offs = [width *] lo, but omit if zero
3351 if lb != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003352 var w int64
Russ Cox8c195bd2015-02-13 14:40:36 -05003353 if n.Op == OSLICESTR {
3354 w = 1
3355 } else {
3356 w = n.Type.Type.Width
3357 }
3358 lb = conv(lb, Types[TUINTPTR])
3359 if w > 1 {
3360 lb = Nod(OMUL, Nodintconst(w), lb)
3361 }
3362 typecheck(&lb, Erv)
3363 walkexpr(&lb, init)
3364 n.List = list(n.List, lb)
3365 }
3366
3367 // print("after sliceany: %+N\n", n);
3368
3369 return n
3370}
3371
3372func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003373 // Should only arrive here with large memory or
3374 // a struct/array containing a non-memory field/element.
3375 // Small memory is handled inline, and single non-memory
3376 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003377 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003378
3379 if a != AMEM && a != -1 {
3380 Fatal("eqfor %v", Tconv(t, 0))
3381 }
3382
3383 if a == AMEM {
Russ Cox382b44e2015-02-23 16:07:24 -05003384 n := syslook("memequal", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003385 substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003386 *needsize = 1
3387 return n
3388 }
3389
Russ Cox382b44e2015-02-23 16:07:24 -05003390 sym := typesymprefix(".eq", t)
3391 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003392 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003393 ntype := Nod(OTFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003394 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3395 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3396 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3397 typecheck(&ntype, Etype)
3398 n.Type = ntype.Type
3399 *needsize = 0
3400 return n
3401}
3402
3403func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003404 n := 0
3405 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003406 n++
3407 }
3408 return n
3409}
3410
3411func walkcompare(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003412 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003413
3414 // Given interface value l and concrete value r, rewrite
3415 // l == r
3416 // to
3417 // x, ok := l.(type(r)); ok && x == r
3418 // Handle != similarly.
3419 // This avoids the allocation that would be required
3420 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003421 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003422
Russ Cox175929b2015-03-02 14:22:05 -05003423 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003424 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003425 l = n.Left
3426 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003427 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003428 l = n.Right
3429 r = n.Left
3430 }
3431
3432 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003433 x := temp(r.Type)
3434 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003435
3436 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003437 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003438
3439 a.Type = r.Type
3440
3441 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003442 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003443
3444 expr.List = list1(x)
3445 expr.List = list(expr.List, ok)
3446 expr.Rlist = list1(a)
3447 typecheck(&expr, Etop)
3448 walkexpr(&expr, init)
3449
3450 if n.Op == OEQ {
3451 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3452 } else {
3453 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3454 }
3455 *init = list(*init, expr)
Russ Cox44928112015-03-02 20:34:22 -05003456 finishcompare(np, n, r, init)
3457 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003458 }
3459
3460 // Must be comparison of array or struct.
3461 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003462 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003463
3464 switch t.Etype {
3465 default:
3466 return
3467
3468 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003469 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003470 return
3471 }
3472
3473 case TSTRUCT:
3474 break
3475 }
3476
Russ Cox44928112015-03-02 20:34:22 -05003477 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003478 for cmpl != nil && cmpl.Op == OCONVNOP {
3479 cmpl = cmpl.Left
3480 }
Russ Cox44928112015-03-02 20:34:22 -05003481 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003482 for cmpr != nil && cmpr.Op == OCONVNOP {
3483 cmpr = cmpr.Left
3484 }
3485
Russ Coxdc7b54b2015-02-17 22:13:49 -05003486 if !islvalue(cmpl) || !islvalue(cmpr) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003487 Fatal("arguments of comparison must be lvalues - %v %v", Nconv(cmpl, 0), Nconv(cmpr, 0))
3488 }
3489
3490 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003491 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003492 a.Right.Etype = 1 // addr does not escape
3493 typecheck(&a, Etop)
3494 *init = list(*init, a)
3495
3496 r = temp(Ptrto(t))
3497 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3498 a.Right.Etype = 1 // addr does not escape
3499 typecheck(&a, Etop)
3500 *init = list(*init, a)
3501
Russ Cox44928112015-03-02 20:34:22 -05003502 andor := OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003503 if n.Op == ONE {
3504 andor = OOROR
3505 }
3506
Russ Cox44928112015-03-02 20:34:22 -05003507 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003508 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003509 // Four or fewer elements of a basic type.
3510 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003511 var li *Node
3512 var ri *Node
3513 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003514 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3515 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
3516 a = Nod(int(n.Op), li, ri)
3517 if expr == nil {
3518 expr = a
3519 } else {
3520 expr = Nod(andor, expr, a)
3521 }
3522 }
3523
3524 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003525 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003526 }
Russ Cox44928112015-03-02 20:34:22 -05003527 finishcompare(np, n, expr, init)
3528 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003529 }
3530
3531 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3532 // Struct of four or fewer fields.
3533 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003534 var li *Node
3535 var ri *Node
3536 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003537 if isblanksym(t1.Sym) {
3538 continue
3539 }
3540 li = Nod(OXDOT, l, newname(t1.Sym))
3541 ri = Nod(OXDOT, r, newname(t1.Sym))
3542 a = Nod(int(n.Op), li, ri)
3543 if expr == nil {
3544 expr = a
3545 } else {
3546 expr = Nod(andor, expr, a)
3547 }
3548 }
3549
3550 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003551 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003552 }
Russ Cox44928112015-03-02 20:34:22 -05003553 finishcompare(np, n, expr, init)
3554 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003555 }
3556
3557 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003558 var needsize int
3559 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003560
3561 call.List = list(call.List, l)
3562 call.List = list(call.List, r)
3563 if needsize != 0 {
3564 call.List = list(call.List, Nodintconst(t.Width))
3565 }
3566 r = call
3567 if n.Op != OEQ {
3568 r = Nod(ONOT, r, nil)
3569 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003570
Russ Cox44928112015-03-02 20:34:22 -05003571 finishcompare(np, n, r, init)
3572 return
3573}
3574
3575func finishcompare(np **Node, n, r *Node, init **NodeList) {
3576 // Using np here to avoid passing &r to typecheck.
3577 *np = r
3578 typecheck(np, Erv)
3579 walkexpr(np, init)
3580 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003581 if r.Type != n.Type {
3582 r = Nod(OCONVNOP, r, nil)
3583 r.Type = n.Type
3584 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003585 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003586 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003587}
3588
Russ Coxdc7b54b2015-02-17 22:13:49 -05003589func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003590 var ar *Node
3591 var br *Node
3592 for a != nil && b != nil && a.Op == b.Op {
3593 switch a.Op {
3594 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003595 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003596
3597 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003598 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003599
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003600 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003601 ar = a.Right
3602 br = b.Right
3603 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003604 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003605 }
3606
3607 case OINDEX:
3608 ar = a.Right
3609 br = b.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003610 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.Xval, br.Val.U.Xval) != 0 {
3611 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003612 }
3613 }
3614
3615 a = a.Left
3616 b = b.Left
3617 }
3618
Russ Coxdc7b54b2015-02-17 22:13:49 -05003619 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003620}
3621
3622func walkrotate(np **Node) {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +01003623 if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003624 return
3625 }
3626
Russ Cox382b44e2015-02-23 16:07:24 -05003627 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003628
3629 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003630 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003631
Russ Cox382b44e2015-02-23 16:07:24 -05003632 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003633 if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || Issigned[n.Type.Etype] || l.Op == r.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05003634 return
3635 }
3636
3637 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003638 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003639 return
3640 }
3641
3642 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003643 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003644
Russ Coxdc7b54b2015-02-17 22:13:49 -05003645 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05003646 sl := int(Mpgetfix(l.Right.Val.U.Xval))
Russ Cox8c195bd2015-02-13 14:40:36 -05003647 if sl >= 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05003648 sr := int(Mpgetfix(r.Right.Val.U.Xval))
Russ Cox8c195bd2015-02-13 14:40:36 -05003649 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003650 // Rewrite left shift half to left rotate.
3651 if l.Op == OLSH {
3652 n = l
3653 } else {
3654 n = r
3655 }
3656 n.Op = OLROT
3657
3658 // Remove rotate 0 and rotate w.
3659 s := int(Mpgetfix(n.Right.Val.U.Xval))
3660
3661 if s == 0 || s == w {
3662 n = n.Left
3663 }
3664
3665 *np = n
3666 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003667 }
3668 }
3669 return
3670 }
3671
3672 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3673 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003674}
3675
3676/*
3677 * walkmul rewrites integer multiplication by powers of two as shifts.
3678 */
3679func walkmul(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003680 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003681 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003682 return
3683 }
3684
Russ Cox382b44e2015-02-23 16:07:24 -05003685 var nr *Node
3686 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003687 if n.Right.Op == OLITERAL {
3688 nl = n.Left
3689 nr = n.Right
3690 } else if n.Left.Op == OLITERAL {
3691 nl = n.Right
3692 nr = n.Left
3693 } else {
3694 return
3695 }
3696
Russ Cox382b44e2015-02-23 16:07:24 -05003697 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003698
3699 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003700 var pow int
3701 var w int
Russ Cox8c195bd2015-02-13 14:40:36 -05003702 if Mpgetfix(nr.Val.U.Xval) == 0 {
3703 cheapexpr(nl, init)
3704 Nodconst(n, n.Type, 0)
3705 goto ret
3706 }
3707
3708 // nr is a constant.
3709 pow = powtwo(nr)
3710
3711 if pow < 0 {
3712 return
3713 }
3714 if pow >= 1000 {
3715 // negative power of 2, like -16
3716 neg = 1
3717
3718 pow -= 1000
3719 }
3720
3721 w = int(nl.Type.Width * 8)
3722 if pow+1 >= w { // too big, shouldn't happen
3723 return
3724 }
3725
3726 nl = cheapexpr(nl, init)
3727
3728 if pow == 0 {
3729 // x*1 is x
3730 n = nl
3731
3732 goto ret
3733 }
3734
3735 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3736
3737ret:
3738 if neg != 0 {
3739 n = Nod(OMINUS, n, nil)
3740 }
3741
3742 typecheck(&n, Erv)
3743 walkexpr(&n, init)
3744 *np = n
3745}
3746
3747/*
3748 * walkdiv rewrites division by a constant as less expensive
3749 * operations.
3750 */
3751func walkdiv(np **Node, init **NodeList) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003752 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003753
3754 // TODO(minux)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +01003755 if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003756 return
3757 }
3758
Russ Cox382b44e2015-02-23 16:07:24 -05003759 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003760 if n.Right.Op != OLITERAL {
3761 return
3762 }
3763
3764 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003765 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003766
Russ Cox382b44e2015-02-23 16:07:24 -05003767 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003768
3769 // special cases of mod/div
3770 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003771 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003772
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003773 s := 0 // 1 if nr is negative.
3774 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003775 if pow >= 1000 {
3776 // negative power of 2
3777 s = 1
3778
3779 pow -= 1000
3780 }
3781
3782 if pow+1 >= w {
3783 // divisor too large.
3784 return
3785 }
3786
3787 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003788 // try to do division by multiply by (2^w)/d
3789 // see hacker's delight chapter 10
3790 // TODO: support 64-bit magic multiply here.
3791 var m Magic
3792 m.W = w
3793
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003794 if Issigned[nl.Type.Etype] {
Russ Cox79f727a2015-03-02 12:35:15 -05003795 m.Sd = Mpgetfix(nr.Val.U.Xval)
3796 Smagic(&m)
3797 } else {
3798 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
3799 Umagic(&m)
3800 }
3801
3802 if m.Bad != 0 {
3803 return
3804 }
3805
3806 // We have a quick division method so use it
3807 // for modulo too.
3808 if n.Op == OMOD {
3809 // rewrite as A%B = A - (A/B*B).
3810 n1 := Nod(ODIV, nl, nr)
3811
3812 n2 := Nod(OMUL, n1, nr)
3813 n = Nod(OSUB, nl, n2)
3814 goto ret
3815 }
3816
3817 switch Simtype[nl.Type.Etype] {
3818 default:
3819 return
3820
3821 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003822 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003823 nc := Nod(OXXX, nil, nil)
3824
3825 Nodconst(nc, nl.Type, int64(m.Um))
3826 n1 := Nod(OMUL, nl, nc)
3827 typecheck(&n1, Erv)
3828 n1.Op = OHMUL
3829 if m.Ua != 0 {
3830 // Select a Go type with (at least) twice the width.
3831 var twide *Type
3832 switch Simtype[nl.Type.Etype] {
3833 default:
3834 return
3835
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003836 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003837 twide = Types[TUINT32]
3838
3839 case TUINT32:
3840 twide = Types[TUINT64]
3841
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003842 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003843 twide = Types[TINT32]
3844
3845 case TINT32:
3846 twide = Types[TINT64]
3847 }
3848
3849 // add numerator (might overflow).
3850 // n2 = (n1 + nl)
3851 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3852
3853 // shift by m.s
3854 nc := Nod(OXXX, nil, nil)
3855
3856 Nodconst(nc, Types[TUINT], int64(m.S))
3857 n = conv(Nod(ORSH, n2, nc), nl.Type)
3858 } else {
3859 // n = n1 >> m.s
3860 nc := Nod(OXXX, nil, nil)
3861
3862 Nodconst(nc, Types[TUINT], int64(m.S))
3863 n = Nod(ORSH, n1, nc)
3864 }
3865
3866 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003867 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003868 nc := Nod(OXXX, nil, nil)
3869
3870 Nodconst(nc, nl.Type, m.Sm)
3871 n1 := Nod(OMUL, nl, nc)
3872 typecheck(&n1, Erv)
3873 n1.Op = OHMUL
3874 if m.Sm < 0 {
3875 // add the numerator.
3876 n1 = Nod(OADD, n1, nl)
3877 }
3878
3879 // shift by m.s
3880 nc = Nod(OXXX, nil, nil)
3881
3882 Nodconst(nc, Types[TUINT], int64(m.S))
3883 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3884
3885 // add 1 iff n1 is negative.
3886 nc = Nod(OXXX, nil, nil)
3887
3888 Nodconst(nc, Types[TUINT], int64(w)-1)
3889 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3890 n = Nod(OSUB, n2, n3)
3891
3892 // apply sign.
3893 if m.Sd < 0 {
3894 n = Nod(OMINUS, n, nil)
3895 }
3896 }
3897
3898 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003899 }
3900
3901 switch pow {
3902 case 0:
3903 if n.Op == OMOD {
3904 // nl % 1 is zero.
3905 Nodconst(n, n.Type, 0)
3906 } else if s != 0 {
3907 // divide by -1
3908 n.Op = OMINUS
3909
3910 n.Right = nil
3911 } else {
3912 // divide by 1
3913 n = nl
3914 }
3915
3916 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003917 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003918 if n.Op == OMOD {
3919 // signed modulo 2^pow is like ANDing
3920 // with the last pow bits, but if nl < 0,
3921 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003922 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003923
3924 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003925 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003926 if pow == 1 {
3927 typecheck(&n1, Erv)
3928 n1 = cheapexpr(n1, init)
3929
3930 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003931 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003932
Russ Cox382b44e2015-02-23 16:07:24 -05003933 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003934 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003935 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003936 n = Nod(OADD, n3, n1)
3937 } else {
3938 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003939 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003940
3941 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003942 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003943 typecheck(&n2, Erv)
3944 n2 = cheapexpr(n2, init)
3945
Russ Cox382b44e2015-02-23 16:07:24 -05003946 n3 := Nod(OADD, nl, n2)
3947 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003948 n = Nod(OSUB, n4, n2)
3949 }
3950
3951 break
3952 } else {
3953 // arithmetic right shift does not give the correct rounding.
3954 // if nl >= 0, nl >> n == nl / nr
3955 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003956 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003957
3958 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003959 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003960 if pow == 1 {
3961 // nl+1 is nl-(-1)
3962 n.Left = Nod(OSUB, nl, n1)
3963 } else {
3964 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003965 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003966
3967 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003968 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003969 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3970 }
3971
3972 // n = (nl + 2^pow-1) >> pow
3973 n.Op = ORSH
3974
3975 nc = Nod(OXXX, nil, nil)
3976 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3977 n.Right = nc
3978 n.Typecheck = 0
3979 }
3980
3981 if s != 0 {
3982 n = Nod(OMINUS, n, nil)
3983 }
3984 break
3985 }
3986
Russ Cox382b44e2015-02-23 16:07:24 -05003987 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003988 if n.Op == OMOD {
3989 // n = nl & (nr-1)
3990 n.Op = OAND
3991
3992 Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.Xval)-1)
3993 } else {
3994 // n = nl >> pow
3995 n.Op = ORSH
3996
3997 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3998 }
3999
4000 n.Typecheck = 0
4001 n.Right = nc
4002 }
4003
4004 goto ret
4005
Russ Cox8c195bd2015-02-13 14:40:36 -05004006ret:
4007 typecheck(&n, Erv)
4008 walkexpr(&n, init)
4009 *np = n
4010}
4011
4012// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05004013func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004014 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004015 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004016 }
4017
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004018 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05004019 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05004020
Russ Coxdc7b54b2015-02-17 22:13:49 -05004021 if Smallintconst(n) {
Russ Cox382b44e2015-02-23 16:07:24 -05004022 v := Mpgetfix(n.Val.U.Xval)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004023 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05004024 }
4025
4026 switch n.Op {
4027 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05004028 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004029 if Smallintconst(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05004030 v = Mpgetfix(n.Left.Val.U.Xval)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004031 } else if Smallintconst(n.Right) {
Russ Cox8c195bd2015-02-13 14:40:36 -05004032 v = Mpgetfix(n.Right.Val.U.Xval)
4033 }
4034
4035 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004036 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004037 }
4038
4039 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004040 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004041 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004042 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004043 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004044 }
4045 }
4046
4047 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004048 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004049 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004050 for bits > 0 && v >= 2 {
4051 bits--
4052 v >>= 1
4053 }
4054 }
4055
4056 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004057 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004058 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004059 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004060 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004061 }
4062 bits -= int32(v)
4063 }
4064 }
4065
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004066 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004067 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004068 }
4069
Russ Coxdc7b54b2015-02-17 22:13:49 -05004070 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004071}
4072
4073func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004074 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004075 return
4076 }
4077
4078 switch n.Op {
4079 default:
4080 Fatal("usefield %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05004081
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004082 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05004083 break
4084 }
4085
Russ Cox382b44e2015-02-23 16:07:24 -05004086 field := n.Paramfld
Russ Cox8c195bd2015-02-13 14:40:36 -05004087 if field == nil {
4088 Fatal("usefield %v %v without paramfld", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
4089 }
Russ Coxbed1f902015-03-02 16:03:26 -05004090 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05004091 return
4092 }
4093
4094 // dedup on list
4095 if field.Lastfn == Curfn {
4096 return
4097 }
4098 field.Lastfn = Curfn
4099 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004100 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05004101 field.Outer = field.Outer.Type
4102 }
4103 if field.Outer.Sym == nil {
4104 Yyerror("tracked field must be in named struct type")
4105 }
4106 if !exportname(field.Sym.Name) {
4107 Yyerror("tracked field must be exported (upper case)")
4108 }
4109
Russ Cox382b44e2015-02-23 16:07:24 -05004110 l := typ(0)
Russ Cox8c195bd2015-02-13 14:40:36 -05004111 l.Type = field
4112 l.Down = Curfn.Paramfld
4113 Curfn.Paramfld = l
4114}
4115
Russ Coxdc7b54b2015-02-17 22:13:49 -05004116func candiscardlist(l *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004117 for ; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004118 if !candiscard(l.N) {
4119 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004120 }
4121 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004122 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004123}
4124
Russ Coxdc7b54b2015-02-17 22:13:49 -05004125func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004126 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004127 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004128 }
4129
4130 switch n.Op {
4131 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004132 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004133
4134 // Discardable as long as the subpieces are.
4135 case ONAME,
4136 ONONAME,
4137 OTYPE,
4138 OPACK,
4139 OLITERAL,
4140 OADD,
4141 OSUB,
4142 OOR,
4143 OXOR,
4144 OADDSTR,
4145 OADDR,
4146 OANDAND,
4147 OARRAYBYTESTR,
4148 OARRAYRUNESTR,
4149 OSTRARRAYBYTE,
4150 OSTRARRAYRUNE,
4151 OCAP,
4152 OCMPIFACE,
4153 OCMPSTR,
4154 OCOMPLIT,
4155 OMAPLIT,
4156 OSTRUCTLIT,
4157 OARRAYLIT,
4158 OPTRLIT,
4159 OCONV,
4160 OCONVIFACE,
4161 OCONVNOP,
4162 ODOT,
4163 OEQ,
4164 ONE,
4165 OLT,
4166 OLE,
4167 OGT,
4168 OGE,
4169 OKEY,
4170 OLEN,
4171 OMUL,
4172 OLSH,
4173 ORSH,
4174 OAND,
4175 OANDNOT,
4176 ONEW,
4177 ONOT,
4178 OCOM,
4179 OPLUS,
4180 OMINUS,
4181 OOROR,
4182 OPAREN,
4183 ORUNESTR,
4184 OREAL,
4185 OIMAG,
4186 OCOMPLEX:
4187 break
4188
4189 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004190 case ODIV, OMOD:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004191 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004192 break
4193 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004194 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.Fval, 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004195 break
4196 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004197 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004198
4199 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004200 case OMAKECHAN, OMAKEMAP:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004201 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004202 break
4203 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004204 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004205
4206 // Difficult to tell what sizes are okay.
4207 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004208 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004209 }
4210
Russ Coxdc7b54b2015-02-17 22:13:49 -05004211 if !candiscard(n.Left) || !candiscard(n.Right) || !candiscard(n.Ntest) || !candiscard(n.Nincr) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.Nelse) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
4212 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004213 }
4214
Russ Coxdc7b54b2015-02-17 22:13:49 -05004215 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004216}
4217
4218// rewrite
4219// print(x, y, z)
4220// into
4221// func(a1, a2, a3) {
4222// print(a1, a2, a3)
4223// }(x, y, z)
4224// and same for println.
4225
4226var walkprintfunc_prgen int
4227
4228func walkprintfunc(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05004229 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05004230
4231 if n.Ninit != nil {
4232 walkstmtlist(n.Ninit)
4233 *init = concat(*init, n.Ninit)
4234 n.Ninit = nil
4235 }
4236
Russ Cox382b44e2015-02-23 16:07:24 -05004237 t := Nod(OTFUNC, nil, nil)
4238 num := 0
Russ Cox175929b2015-03-02 14:22:05 -05004239 var printargs *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05004240 var a *Node
4241 var buf string
4242 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05004243 buf = fmt.Sprintf("a%d", num)
4244 num++
4245 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
4246 t.List = list(t.List, a)
4247 printargs = list(printargs, a.Left)
4248 }
4249
Russ Cox382b44e2015-02-23 16:07:24 -05004250 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004251 walkprintfunc_prgen++
4252 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
4253 fn.Nname = newname(Lookup(buf))
4254 fn.Nname.Defn = fn
4255 fn.Nname.Ntype = t
4256 declare(fn.Nname, PFUNC)
4257
Russ Cox382b44e2015-02-23 16:07:24 -05004258 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004259 Curfn = nil
4260 funchdr(fn)
4261
4262 a = Nod(int(n.Op), nil, nil)
4263 a.List = printargs
4264 typecheck(&a, Etop)
4265 walkstmt(&a)
4266
4267 fn.Nbody = list1(a)
4268
4269 funcbody(fn)
4270
4271 typecheck(&fn, Etop)
4272 typechecklist(fn.Nbody, Etop)
4273 xtop = list(xtop, fn)
4274 Curfn = oldfn
4275
4276 a = Nod(OCALL, nil, nil)
4277 a.Left = fn.Nname
4278 a.List = n.List
4279 typecheck(&a, Etop)
4280 walkexpr(&a, init)
4281 *np = a
4282}