blob: 22f1ea7eb59d1c7eb574d0e10a1aaecb12702c13 [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.
Russ Cox382b44e2015-02-23 16:07:24 -050032 for l := fn.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.
Russ Cox382b44e2015-02-23 16:07:24 -050039 for l := fn.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050040 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Defn != nil && l.N.Defn.Op == OTYPESW && l.N.Used != 0 {
41 l.N.Defn.Left.Used++
42 }
43 }
44
Russ Cox382b44e2015-02-23 16:07:24 -050045 for l := fn.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050046 if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used != 0 {
47 continue
48 }
49 if l.N.Defn != nil && l.N.Defn.Op == OTYPESW {
50 if l.N.Defn.Left.Used != 0 {
51 continue
52 }
53 lineno = l.N.Defn.Left.Lineno
54 Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
55 l.N.Defn.Left.Used = 1 // suppress repeats
56 } 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()
73 if Debug['W'] != 0 && Curfn.Enter != nil {
Russ Cox382b44e2015-02-23 16:07:24 -050074 s := fmt.Sprintf("enter %v", Sconv(Curfn.Nname.Sym, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050075 dumplist(s, Curfn.Enter)
76 }
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 Cox8c195bd2015-02-13 14:40:36 -050086 for ; a != nil && b != nil; (func() { a = a.Next; b = b.Next })() {
87 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
94func paramoutheap(fn *Node) int {
Russ Cox382b44e2015-02-23 16:07:24 -050095 for l := fn.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050096 switch l.N.Class {
97 case PPARAMOUT,
98 PPARAMOUT | PHEAP:
99 return int(l.N.Addrtaken)
100
101 // stop early - parameters are over
102 case PAUTO,
103 PAUTO | PHEAP:
104 return 0
105 }
106 }
107
108 return 0
109}
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 {
235 case OPRINT,
236 OPRINTN:
237 walkprintfunc(&n.Left, &n.Ninit)
238
239 case OCOPY:
240 n.Left = copyany(n.Left, &n.Ninit, 1)
241
242 default:
243 walkexpr(&n.Left, &n.Ninit)
244 }
245
246 // make room for size & fn arguments.
247 adjustargs(n, 2*Widthptr)
248
249 case OFOR:
250 if n.Ntest != nil {
251 walkstmtlist(n.Ntest.Ninit)
Russ Cox382b44e2015-02-23 16:07:24 -0500252 init := n.Ntest.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500253 n.Ntest.Ninit = nil
254 walkexpr(&n.Ntest, &init)
255 addinit(&n.Ntest, init)
256 }
257
258 walkstmt(&n.Nincr)
259 walkstmtlist(n.Nbody)
260
261 case OIF:
262 walkexpr(&n.Ntest, &n.Ninit)
263 walkstmtlist(n.Nbody)
264 walkstmtlist(n.Nelse)
265
266 case OPROC:
267 switch n.Left.Op {
268 case OPRINT,
269 OPRINTN:
270 walkprintfunc(&n.Left, &n.Ninit)
271
272 case OCOPY:
273 n.Left = copyany(n.Left, &n.Ninit, 1)
274
275 default:
276 walkexpr(&n.Left, &n.Ninit)
277 }
278
279 // make room for size & fn arguments.
280 adjustargs(n, 2*Widthptr)
281
282 case ORETURN:
283 walkexprlist(n.List, &n.Ninit)
284 if n.List == nil {
285 break
286 }
287 if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) != 0 {
288 // assign to the function out parameters,
289 // so that reorder3 can fix up conflicts
Russ Cox175929b2015-03-02 14:22:05 -0500290 var rl *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500291
Russ Cox382b44e2015-02-23 16:07:24 -0500292 var cl int
293 for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500294 cl = int(ll.N.Class) &^ PHEAP
295 if cl == PAUTO {
296 break
297 }
298 if cl == PPARAMOUT {
299 rl = list(rl, ll.N)
300 }
301 }
302
Russ Coxdc7b54b2015-02-17 22:13:49 -0500303 if samelist(rl, n.List) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500304 // special return in disguise
305 n.List = nil
306
307 break
308 }
309
310 if count(n.List) == 1 && count(rl) > 1 {
311 // OAS2FUNC in disguise
Russ Cox382b44e2015-02-23 16:07:24 -0500312 f := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500313
314 if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
315 Fatal("expected return of call, have %v", Nconv(f, 0))
316 }
317 n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
318 break
319 }
320
321 // move function calls out, to make reorder3's job easier.
322 walkexprlistsafe(n.List, &n.Ninit)
323
Russ Cox382b44e2015-02-23 16:07:24 -0500324 ll := ascompatee(int(n.Op), rl, n.List, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500325 n.List = reorder3(ll)
326 break
327 }
328
Russ Cox382b44e2015-02-23 16:07:24 -0500329 ll := ascompatte(int(n.Op), nil, 0, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500330 n.List = ll
331
332 case ORETJMP:
333 break
334
335 case OSELECT:
336 walkselect(n)
337
338 case OSWITCH:
339 walkswitch(n)
340
341 case ORANGE:
342 walkrange(n)
343
344 case OXFALL:
345 Yyerror("fallthrough statement out of place")
346 n.Op = OFALL
347 }
348
349 if n.Op == ONAME {
350 Fatal("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
351 }
352
353 *np = n
354}
355
356/*
357 * walk the whole tree of the body of an
358 * expression or simple statement.
359 * the types expressions are calculated.
360 * compile-time constants are evaluated.
361 * complex side effects like statements are appended to init
362 */
363func walkexprlist(l *NodeList, init **NodeList) {
364 for ; l != nil; l = l.Next {
365 walkexpr(&l.N, init)
366 }
367}
368
369func walkexprlistsafe(l *NodeList, init **NodeList) {
370 for ; l != nil; l = l.Next {
371 l.N = safeexpr(l.N, init)
372 walkexpr(&l.N, init)
373 }
374}
375
376func walkexprlistcheap(l *NodeList, init **NodeList) {
377 for ; l != nil; l = l.Next {
378 l.N = cheapexpr(l.N, init)
379 walkexpr(&l.N, init)
380 }
381}
382
383func walkexpr(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -0500384 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500385
386 if n == nil {
387 return
388 }
389
390 if init == &n.Ninit {
391 // not okay to use n->ninit when walking n,
392 // because we might replace n with some other node
393 // and would lose the init list.
394 Fatal("walkexpr init == &n->ninit")
395 }
396
397 if n.Ninit != nil {
398 walkstmtlist(n.Ninit)
399 *init = concat(*init, n.Ninit)
400 n.Ninit = nil
401 }
402
403 // annoying case - not typechecked
404 if n.Op == OKEY {
405 walkexpr(&n.Left, init)
406 walkexpr(&n.Right, init)
407 return
408 }
409
Russ Cox382b44e2015-02-23 16:07:24 -0500410 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500411
412 if Debug['w'] > 1 {
413 Dump("walk-before", n)
414 }
415
416 if n.Typecheck != 1 {
417 Fatal("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
418 }
419
420 switch n.Op {
421 default:
422 Dump("walk", n)
423 Fatal("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
424
425 case OTYPE,
426 ONONAME,
427 OINDREG,
428 OEMPTY,
429 OPARAM:
430 goto ret
431
432 case ONOT,
433 OMINUS,
434 OPLUS,
435 OCOM,
436 OREAL,
437 OIMAG,
438 ODOTMETH,
439 ODOTINTER:
440 walkexpr(&n.Left, init)
441 goto ret
442
443 case OIND:
444 walkexpr(&n.Left, init)
445 goto ret
446
447 case ODOT:
448 usefield(n)
449 walkexpr(&n.Left, init)
450 goto ret
451
452 case ODOTPTR:
453 usefield(n)
454 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
455 // No actual copy will be generated, so emit an explicit nil check.
456 n.Left = cheapexpr(n.Left, init)
457
458 checknil(n.Left, init)
459 }
460
461 walkexpr(&n.Left, init)
462 goto ret
463
464 case OEFACE:
465 walkexpr(&n.Left, init)
466 walkexpr(&n.Right, init)
467 goto ret
468
469 case OSPTR,
470 OITAB:
471 walkexpr(&n.Left, init)
472 goto ret
473
474 case OLEN,
475 OCAP:
476 walkexpr(&n.Left, init)
477
478 // replace len(*[10]int) with 10.
479 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500480 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500481
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000482 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500483 t = t.Type
484 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500485 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500486 safeexpr(n.Left, init)
487 Nodconst(n, n.Type, t.Bound)
488 n.Typecheck = 1
489 }
490
491 goto ret
492
493 case OLSH,
494 ORSH:
495 walkexpr(&n.Left, init)
496 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500497 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500498 n.Bounded = bounded(n.Right, 8*t.Width)
499 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500500 Warn("shift bounds check elided")
501 }
502 goto ret
503
504 // Use results from call expression as arguments for complex.
505 case OAND,
506 OSUB,
507 OHMUL,
508 OLT,
509 OLE,
510 OGE,
511 OGT,
512 OADD,
513 OCOMPLEX,
514 OLROT:
515 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
516 n.Left = n.List.N
517 n.Right = n.List.Next.N
518 }
519
520 walkexpr(&n.Left, init)
521 walkexpr(&n.Right, init)
522 goto ret
523
524 case OOR,
525 OXOR:
526 walkexpr(&n.Left, init)
527 walkexpr(&n.Right, init)
528 walkrotate(&n)
529 goto ret
530
531 case OEQ,
532 ONE:
533 walkexpr(&n.Left, init)
534 walkexpr(&n.Right, init)
535
536 // Disable safemode while compiling this code: the code we
537 // generate internally can refer to unsafe.Pointer.
538 // In this case it can happen if we need to generate an ==
539 // for a struct containing a reflect.Value, which itself has
540 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500541 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500542
543 safemode = 0
544 walkcompare(&n, init)
545 safemode = old_safemode
546 goto ret
547
548 case OANDAND,
549 OOROR:
550 walkexpr(&n.Left, init)
551
552 // cannot put side effects from n->right on init,
553 // because they cannot run before n->left is checked.
554 // save elsewhere and store on the eventual n->right.
Russ Cox175929b2015-03-02 14:22:05 -0500555 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500556
557 walkexpr(&n.Right, &ll)
558 addinit(&n.Right, ll)
559 goto ret
560
561 case OPRINT,
562 OPRINTN:
563 walkexprlist(n.List, init)
564 n = walkprint(n, init)
565 goto ret
566
567 case OPANIC:
568 n = mkcall("gopanic", nil, init, n.Left)
569 goto ret
570
571 case ORECOVER:
572 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
573 goto ret
574
575 case OLITERAL:
576 n.Addable = 1
577 goto ret
578
579 case OCLOSUREVAR,
580 OCFUNC:
581 n.Addable = 1
582 goto ret
583
584 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500585 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Russ Cox8c195bd2015-02-13 14:40:36 -0500586 n.Addable = 1
587 }
588 goto ret
589
590 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500591 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500592 if n.List != nil && n.List.N.Op == OAS {
593 goto ret
594 }
595 walkexpr(&n.Left, init)
596 walkexprlist(n.List, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500597 ll := ascompatte(int(n.Op), n, int(n.Isddd), getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500598 n.List = reorder1(ll)
599 goto ret
600
601 case OCALLFUNC:
602 if n.Left.Op == OCLOSURE {
603 // Transform direct call of a closure to call of a normal function.
604 // transformclosure already did all preparation work.
605
606 // Append captured variables to argument list.
607 n.List = concat(n.List, n.Left.Enter)
608
609 n.Left.Enter = nil
610
611 // Replace OCLOSURE with ONAME/PFUNC.
612 n.Left = n.Left.Closure.Nname
613
614 // Update type of OCALLFUNC node.
615 // Output arguments had not changed, but their offsets could.
616 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500617 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500618 if t.Etype == TFIELD {
619 t = t.Type
620 }
621 n.Type = t
622 } else {
623 n.Type = getoutargx(n.Left.Type)
624 }
625 }
626
Russ Cox382b44e2015-02-23 16:07:24 -0500627 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500628 if n.List != nil && n.List.N.Op == OAS {
629 goto ret
630 }
631
632 walkexpr(&n.Left, init)
633 walkexprlist(n.List, init)
634
Russ Cox382b44e2015-02-23 16:07:24 -0500635 ll := ascompatte(int(n.Op), n, int(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)
Russ Cox382b44e2015-02-23 16:07:24 -0500646 ll := ascompatte(int(n.Op), n, 0, getthis(t), list1(n.Left.Left), 0, init)
647 lr := ascompatte(int(n.Op), n, int(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
673 // x = i.(T); n->left is x, n->right->left is i.
674 // orderstmt made sure x is addressable.
675 case ODOTTYPE:
676 walkexpr(&n.Right.Left, init)
677
Russ Cox382b44e2015-02-23 16:07:24 -0500678 n1 := Nod(OADDR, n.Left, nil)
679 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500680
Russ Cox382b44e2015-02-23 16:07:24 -0500681 from := "I"
Russ Cox8c195bd2015-02-13 14:40:36 -0500682
Russ Cox382b44e2015-02-23 16:07:24 -0500683 to := "T"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500684 if isnilinter(r.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500685 from = "E"
686 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500687 if isnilinter(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500688 to = "E"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500689 } else if Isinter(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500690 to = "I"
691 }
692
Russ Cox382b44e2015-02-23 16:07:24 -0500693 buf := fmt.Sprintf("assert%s2%s", from, to)
Russ Cox8c195bd2015-02-13 14:40:36 -0500694
Russ Cox382b44e2015-02-23 16:07:24 -0500695 fn := syslook(buf, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500696 argtype(fn, r.Left.Type)
697 argtype(fn, r.Type)
698
699 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
700 walkexpr(&n, init)
701 goto ret
702
703 // x = <-c; n->left is x, n->right->left is c.
704 // orderstmt made sure x is addressable.
705 case ORECV:
706 walkexpr(&n.Right.Left, init)
707
Russ Cox382b44e2015-02-23 16:07:24 -0500708 n1 := Nod(OADDR, n.Left, nil)
709 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500710 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
711 walkexpr(&n, init)
712 goto ret
713 }
714
715 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500716 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500717 r.Dodata = n.Dodata
718 n = r
719 n = applywritebarrier(n, init)
720 }
721
722 goto ret
723
724 case OAS2:
725 *init = concat(*init, n.Ninit)
726 n.Ninit = nil
727 walkexprlistsafe(n.List, init)
728 walkexprlistsafe(n.Rlist, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500729 ll := ascompatee(OAS, n.List, n.Rlist, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500730 ll = reorder3(ll)
Russ Cox382b44e2015-02-23 16:07:24 -0500731 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500732 lr.N = applywritebarrier(lr.N, init)
733 }
734 n = liststmt(ll)
735 goto ret
736
737 // a,b,... = fn()
738 case OAS2FUNC:
739 *init = concat(*init, n.Ninit)
740
741 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500742 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500743 walkexprlistsafe(n.List, init)
744 walkexpr(&r, init)
745
Russ Cox382b44e2015-02-23 16:07:24 -0500746 ll := ascompatet(int(n.Op), n.List, &r.Type, 0, init)
747 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500748 lr.N = applywritebarrier(lr.N, init)
749 }
750 n = liststmt(concat(list1(r), ll))
751 goto ret
752
753 // x, y = <-c
754 // orderstmt made sure x is addressable.
755 case OAS2RECV:
756 *init = concat(*init, n.Ninit)
757
758 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500759 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500760 walkexprlistsafe(n.List, init)
761 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500762 var n1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500763 if isblank(n.List.N) {
764 n1 = nodnil()
765 } else {
766 n1 = Nod(OADDR, n.List.N, nil)
767 }
768 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500769 fn := chanfn("chanrecv2", 2, r.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500770 r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
771 n = Nod(OAS, n.List.Next.N, r)
772 typecheck(&n, Etop)
773 goto ret
774
775 // a,b = m[i];
776 case OAS2MAPR:
777 *init = concat(*init, n.Ninit)
778
779 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500780 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500781 walkexprlistsafe(n.List, init)
782 walkexpr(&r.Left, init)
783 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500784 t := r.Left.Type
785 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500786 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
787 switch Simsimtype(t.Down) {
788 case TINT32,
789 TUINT32:
790 p = "mapaccess2_fast32"
791
792 case TINT64,
793 TUINT64:
794 p = "mapaccess2_fast64"
795
796 case TSTRING:
797 p = "mapaccess2_faststr"
798 }
799 }
800
Russ Cox382b44e2015-02-23 16:07:24 -0500801 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500802 if p != "" {
803 // fast versions take key by value
804 key = r.Right
805 } else {
806 // standard version takes key by reference
807 // orderexpr made sure key is addressable.
808 key = Nod(OADDR, r.Right, nil)
809
810 p = "mapaccess2"
811 }
812
813 // from:
814 // a,b = m[i]
815 // to:
816 // var,b = mapaccess2*(t, m, i)
817 // a = *var
Russ Cox382b44e2015-02-23 16:07:24 -0500818 a := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500819
Russ Cox382b44e2015-02-23 16:07:24 -0500820 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500821 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
822
823 // mapaccess2* returns a typed bool, but due to spec changes,
824 // the boolean result of i.(T) is now untyped so we make it the
825 // same type as the variable on the lhs.
826 if !isblank(n.List.Next.N) {
827 r.Type.Type.Down.Type = n.List.Next.N.Type
828 }
829 n.Rlist = list1(r)
830 n.Op = OAS2FUNC
831
832 // don't generate a = *var if a is _
833 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500834 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500835 var_.Typecheck = 1
836 n.List.N = var_
837 walkexpr(&n, init)
838 *init = list(*init, n)
839 n = Nod(OAS, a, Nod(OIND, var_, nil))
840 }
841
842 typecheck(&n, Etop)
843 walkexpr(&n, init)
844
845 // mapaccess needs a zero value to be at least this big.
846 if zerosize < t.Type.Width {
847 zerosize = t.Type.Width
848 }
849
850 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
851 goto ret
852
853 case ODELETE:
854 *init = concat(*init, n.Ninit)
855 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500856 map_ := n.List.N
857 key := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500858 walkexpr(&map_, init)
859 walkexpr(&key, init)
860
861 // orderstmt made sure key is addressable.
862 key = Nod(OADDR, key, nil)
863
Russ Cox382b44e2015-02-23 16:07:24 -0500864 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500865 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
866 goto ret
867
868 // a,b = i.(T)
869 // orderstmt made sure a is addressable.
870 case OAS2DOTTYPE:
871 *init = concat(*init, n.Ninit)
872
873 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500874 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500875 walkexprlistsafe(n.List, init)
876 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500877 var n1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500878 if isblank(n.List.N) {
879 n1 = nodnil()
880 } else {
881 n1 = Nod(OADDR, n.List.N, nil)
882 }
883 n1.Etype = 1 // addr does not escape
884
Russ Cox382b44e2015-02-23 16:07:24 -0500885 from := "I"
Russ Cox8c195bd2015-02-13 14:40:36 -0500886
Russ Cox382b44e2015-02-23 16:07:24 -0500887 to := "T"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500888 if isnilinter(r.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500889 from = "E"
890 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500891 if isnilinter(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500892 to = "E"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500893 } else if Isinter(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500894 to = "I"
895 }
Russ Cox382b44e2015-02-23 16:07:24 -0500896 buf := fmt.Sprintf("assert%s2%s2", from, to)
Russ Cox8c195bd2015-02-13 14:40:36 -0500897
Russ Cox382b44e2015-02-23 16:07:24 -0500898 fn := syslook(buf, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500899 argtype(fn, r.Left.Type)
900 argtype(fn, r.Type)
901
Russ Cox382b44e2015-02-23 16:07:24 -0500902 t := Types[TBOOL]
903 ok := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500904 if !isblank(ok) {
905 t = ok.Type
906 }
907 r = mkcall1(fn, t, init, typename(r.Type), r.Left, n1)
908 n = Nod(OAS, ok, r)
909 typecheck(&n, Etop)
910 goto ret
911
912 case ODOTTYPE,
913 ODOTTYPE2:
914 Fatal("walkexpr ODOTTYPE") // should see inside OAS or OAS2 only
Russ Cox8c195bd2015-02-13 14:40:36 -0500915
916 case OCONVIFACE:
917 walkexpr(&n.Left, init)
918
919 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500920 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500921 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500922 l.Type = n.Type
923 l.Typecheck = n.Typecheck
924 n = l
925 goto ret
926 }
927
928 // Build name of function: convI2E etc.
929 // Not all names are possible
930 // (e.g., we'll never generate convE2E or convE2I).
Russ Cox382b44e2015-02-23 16:07:24 -0500931 from := "T"
Russ Cox8c195bd2015-02-13 14:40:36 -0500932
Russ Cox382b44e2015-02-23 16:07:24 -0500933 to := "I"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500934 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500935 from = "E"
Russ Coxdc7b54b2015-02-17 22:13:49 -0500936 } else if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500937 from = "I"
938 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500939 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500940 to = "E"
941 }
Russ Cox382b44e2015-02-23 16:07:24 -0500942 buf := fmt.Sprintf("conv%s2%s", from, to)
Russ Cox8c195bd2015-02-13 14:40:36 -0500943
Russ Cox382b44e2015-02-23 16:07:24 -0500944 fn := syslook(buf, 1)
Russ Cox175929b2015-03-02 14:22:05 -0500945 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -0500946 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500947 ll = list(ll, typename(n.Left.Type))
948 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500949 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500950 ll = list(ll, typename(n.Type))
951 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500952 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500953 sym := Pkglookup(fmt.Sprintf("%v.%v", Tconv(n.Left.Type, obj.FmtLeft), Tconv(n.Type, obj.FmtLeft)), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500954 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500955 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500956 l.Sym = sym
957 l.Type = Ptrto(Types[TUINT8])
958 l.Addable = 1
959 l.Class = PEXTERN
960 l.Xoffset = 0
961 sym.Def = l
962 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
963 }
964
Russ Cox382b44e2015-02-23 16:07:24 -0500965 l := Nod(OADDR, sym.Def, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500966 l.Addable = 1
967 ll = list(ll, l)
968
Russ Coxdc7b54b2015-02-17 22:13:49 -0500969 if isdirectiface(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500970 /* For pointer types, we can make a special form of optimization
971 *
972 * These statements are put onto the expression init list:
973 * Itab *tab = atomicloadtype(&cache);
974 * if(tab == nil)
975 * tab = typ2Itab(type, itype, &cache);
976 *
977 * The CONVIFACE expression is replaced with this:
978 * OEFACE{tab, ptr};
979 */
Russ Cox382b44e2015-02-23 16:07:24 -0500980 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500981
Russ Cox382b44e2015-02-23 16:07:24 -0500982 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -0500983 typecheck(&n1, Etop)
984 *init = list(*init, n1)
985
Russ Cox382b44e2015-02-23 16:07:24 -0500986 fn := syslook("typ2Itab", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500987 n1 = Nod(OCALL, fn, nil)
988 n1.List = ll
989 typecheck(&n1, Erv)
990 walkexpr(&n1, init)
991
Russ Cox382b44e2015-02-23 16:07:24 -0500992 n2 := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500993 n2.Ntest = Nod(OEQ, l, nodnil())
994 n2.Nbody = list1(Nod(OAS, l, n1))
995 n2.Likely = -1
996 typecheck(&n2, Etop)
997 *init = list(*init, n2)
998
999 l = Nod(OEFACE, l, n.Left)
1000 l.Typecheck = n.Typecheck
1001 l.Type = n.Type
1002 n = l
1003 goto ret
1004 }
1005 }
1006
Russ Coxdc7b54b2015-02-17 22:13:49 -05001007 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001008 ll = list(ll, n.Left)
1009 } else {
1010 // regular types are passed by reference to avoid C vararg calls
1011 // orderexpr arranged for n->left to be a temporary for all
1012 // the conversions it could see. comparison of an interface
1013 // with a non-interface, especially in a switch on interface value
1014 // with non-interface cases, is not visible to orderstmt, so we
1015 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001016 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001017 ll = list(ll, Nod(OADDR, n.Left, nil))
1018 } else {
1019 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1020 }
1021 }
1022
1023 argtype(fn, n.Left.Type)
1024 argtype(fn, n.Type)
1025 dowidth(fn.Type)
1026 n = Nod(OCALL, fn, nil)
1027 n.List = ll
1028 typecheck(&n, Erv)
1029 walkexpr(&n, init)
1030 goto ret
1031
1032 case OCONV,
1033 OCONVNOP:
1034 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001035 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001036 if n.Type.Etype == TINT64 {
1037 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1038 goto ret
1039 }
1040
1041 if n.Type.Etype == TUINT64 {
1042 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1043 goto ret
1044 }
1045 }
1046
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001047 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001048 if n.Left.Type.Etype == TINT64 {
1049 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
1050 goto ret
1051 }
1052
1053 if n.Left.Type.Etype == TUINT64 {
1054 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
1055 goto ret
1056 }
1057 }
1058 }
1059
1060 walkexpr(&n.Left, init)
1061 goto ret
1062
1063 case OANDNOT:
1064 walkexpr(&n.Left, init)
1065 n.Op = OAND
1066 n.Right = Nod(OCOM, n.Right, nil)
1067 typecheck(&n.Right, Erv)
1068 walkexpr(&n.Right, init)
1069 goto ret
1070
1071 case OMUL:
1072 walkexpr(&n.Left, init)
1073 walkexpr(&n.Right, init)
1074 walkmul(&n, init)
1075 goto ret
1076
1077 case ODIV,
1078 OMOD:
1079 walkexpr(&n.Left, init)
1080 walkexpr(&n.Right, init)
1081
1082 /*
1083 * rewrite complex div into function call.
1084 */
Russ Cox382b44e2015-02-23 16:07:24 -05001085 et := int(n.Left.Type.Etype)
Russ Cox8c195bd2015-02-13 14:40:36 -05001086
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001087 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001088 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001089 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1090 n = conv(n, t)
1091 goto ret
1092 }
1093
1094 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001095 if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001096 goto ret
1097 }
1098
1099 // Try rewriting as shifts or magic multiplies.
1100 walkdiv(&n, init)
1101
1102 /*
1103 * rewrite 64-bit div and mod into function calls
1104 * on 32-bit architectures.
1105 */
1106 switch n.Op {
1107 case OMOD,
1108 ODIV:
1109 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
1110 goto ret
1111 }
1112 if et == TINT64 {
1113 namebuf = "int64"
1114 } else {
1115 namebuf = "uint64"
1116 }
1117 if n.Op == ODIV {
1118 namebuf += "div"
1119 } else {
1120 namebuf += "mod"
1121 }
1122 n = mkcall(namebuf, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
1123
1124 default:
1125 break
1126 }
1127
1128 goto ret
1129
1130 case OINDEX:
1131 walkexpr(&n.Left, init)
1132
1133 // save the original node for bounds checking elision.
1134 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001135 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001136
1137 walkexpr(&n.Right, init)
1138
1139 // if range of type cannot exceed static array bound,
1140 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001141 if n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001142 goto ret
1143 }
Russ Cox382b44e2015-02-23 16:07:24 -05001144 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001145 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001146 t = t.Type
1147 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001148 if Isfixedarray(t) {
1149 n.Bounded = bounded(r, t.Bound)
1150 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001151 Warn("index bounds check elided")
1152 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001153 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001154 Yyerror("index out of bounds")
1155 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001156 } else if Isconst(n.Left, CTSTR) {
1157 n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval.S)))
1158 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001159 Warn("index bounds check elided")
1160 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001161 if Smallintconst(n.Right) {
1162 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001163 Yyerror("index out of bounds")
1164 } else {
1165 // replace "abc"[1] with 'b'.
1166 // delayed until now because "abc"[1] is not
1167 // an ideal constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001168 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05001169
1170 Nodconst(n, n.Type, int64(n.Left.Val.U.Sval.S[v]))
1171 n.Typecheck = 1
1172 }
1173 }
1174 }
1175
Russ Coxdc7b54b2015-02-17 22:13:49 -05001176 if Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001177 if Mpcmpfixfix(n.Right.Val.U.Xval, &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 {
1178 Yyerror("index out of bounds")
1179 }
1180 }
1181 goto ret
1182
1183 case OINDEXMAP:
1184 if n.Etype == 1 {
1185 goto ret
1186 }
1187 walkexpr(&n.Left, init)
1188 walkexpr(&n.Right, init)
1189
Russ Cox382b44e2015-02-23 16:07:24 -05001190 t := n.Left.Type
1191 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001192 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
1193 switch Simsimtype(t.Down) {
1194 case TINT32,
1195 TUINT32:
1196 p = "mapaccess1_fast32"
1197
1198 case TINT64,
1199 TUINT64:
1200 p = "mapaccess1_fast64"
1201
1202 case TSTRING:
1203 p = "mapaccess1_faststr"
1204 }
1205 }
1206
Russ Cox382b44e2015-02-23 16:07:24 -05001207 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001208 if p != "" {
1209 // fast versions take key by value
1210 key = n.Right
1211 } else {
1212 // standard version takes key by reference.
1213 // orderexpr made sure key is addressable.
1214 key = Nod(OADDR, n.Right, nil)
1215
1216 p = "mapaccess1"
1217 }
1218
1219 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1220 n = Nod(OIND, n, nil)
1221 n.Type = t.Type
1222 n.Typecheck = 1
1223
1224 // mapaccess needs a zero value to be at least this big.
1225 if zerosize < t.Type.Width {
1226 zerosize = t.Type.Width
1227 }
1228 goto ret
1229
1230 case ORECV:
1231 Fatal("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001232
1233 case OSLICE:
1234 if n.Right != nil && n.Right.Left == nil && n.Right.Right == nil { // noop
1235 walkexpr(&n.Left, init)
1236 n = n.Left
1237 goto ret
1238 }
1239 fallthrough
1240
1241 // fallthrough
1242 case OSLICEARR,
1243 OSLICESTR:
1244 if n.Right == nil { // already processed
1245 goto ret
1246 }
1247
1248 walkexpr(&n.Left, init)
1249
1250 // cgen_slice can't handle string literals as source
1251 // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
1252 if (n.Op == OSLICESTR && n.Left.Op == OLITERAL) || (n.Left.Op == OINDEX) {
1253 n.Left = copyexpr(n.Left, n.Left.Type, init)
1254 } else {
1255 n.Left = safeexpr(n.Left, init)
1256 }
1257 walkexpr(&n.Right.Left, init)
1258 n.Right.Left = safeexpr(n.Right.Left, init)
1259 walkexpr(&n.Right.Right, init)
1260 n.Right.Right = safeexpr(n.Right.Right, init)
1261 n = sliceany(n, init) // chops n->right, sets n->list
1262 goto ret
1263
1264 case OSLICE3,
1265 OSLICE3ARR:
1266 if n.Right == nil { // already processed
1267 goto ret
1268 }
1269
1270 walkexpr(&n.Left, init)
1271
1272 // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi]
1273 // TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
1274 if n.Left.Op == OINDEX {
1275 n.Left = copyexpr(n.Left, n.Left.Type, init)
1276 } else {
1277 n.Left = safeexpr(n.Left, init)
1278 }
1279 walkexpr(&n.Right.Left, init)
1280 n.Right.Left = safeexpr(n.Right.Left, init)
1281 walkexpr(&n.Right.Right.Left, init)
1282 n.Right.Right.Left = safeexpr(n.Right.Right.Left, init)
1283 walkexpr(&n.Right.Right.Right, init)
1284 n.Right.Right.Right = safeexpr(n.Right.Right.Right, init)
1285 n = sliceany(n, init) // chops n->right, sets n->list
1286 goto ret
1287
1288 case OADDR:
1289 walkexpr(&n.Left, init)
1290 goto ret
1291
1292 case ONEW:
1293 if n.Esc == EscNone && n.Type.Type.Width < 1<<16 {
Russ Cox382b44e2015-02-23 16:07:24 -05001294 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001295 r = Nod(OAS, r, nil) // zero temp
1296 typecheck(&r, Etop)
1297 *init = list(*init, r)
1298 r = Nod(OADDR, r.Left, nil)
1299 typecheck(&r, Erv)
1300 n = r
1301 } else {
1302 n = callnew(n.Type.Type)
1303 }
1304
1305 goto ret
1306
1307 // If one argument to the comparison is an empty string,
1308 // comparing the lengths instead will yield the same result
1309 // without the function call.
1310 case OCMPSTR:
Russ Coxdc7b54b2015-02-17 22:13:49 -05001311 if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval.S) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval.S) == 0) {
Russ Cox382b44e2015-02-23 16:07:24 -05001312 r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001313 typecheck(&r, Erv)
1314 walkexpr(&r, init)
1315 r.Type = n.Type
1316 n = r
1317 goto ret
1318 }
1319
1320 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Russ Coxdc7b54b2015-02-17 22:13:49 -05001321 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 -05001322 r := Nod(int(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001323 typecheck(&r, Erv)
1324 walkexpr(&r, init)
1325 r.Type = n.Type
1326 n = r
1327 goto ret
1328 }
1329
Russ Cox382b44e2015-02-23 16:07:24 -05001330 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001331 if n.Etype == OEQ || n.Etype == ONE {
1332 // prepare for rewrite below
1333 n.Left = cheapexpr(n.Left, init)
1334
1335 n.Right = cheapexpr(n.Right, init)
1336
1337 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1338
1339 // quick check of len before full compare for == or !=
1340 // eqstring assumes that the lengths are equal
1341 if n.Etype == OEQ {
1342 // len(left) == len(right) && eqstring(left, right)
1343 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1344 } else {
1345 // len(left) != len(right) || !eqstring(left, right)
1346 r = Nod(ONOT, r, nil)
1347
1348 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1349 }
1350
1351 typecheck(&r, Erv)
1352 walkexpr(&r, nil)
1353 } else {
1354 // sys_cmpstring(s1, s2) :: 0
1355 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1356
1357 r = Nod(int(n.Etype), r, Nodintconst(0))
1358 }
1359
1360 typecheck(&r, Erv)
1361 if n.Type.Etype != TBOOL {
1362 Fatal("cmp %v", Tconv(n.Type, 0))
1363 }
1364 r.Type = n.Type
1365 n = r
1366 goto ret
1367
1368 case OADDSTR:
1369 n = addstr(n, init)
1370 goto ret
1371
1372 case OAPPEND:
1373 if n.Isddd != 0 {
1374 n = appendslice(n, init) // also works for append(slice, string).
1375 } else {
1376 n = walkappend(n, init)
1377 }
1378 goto ret
1379
1380 case OCOPY:
1381 n = copyany(n, init, flag_race)
1382 goto ret
1383
1384 // cannot use chanfn - closechan takes any, not chan any
1385 case OCLOSE:
Russ Cox382b44e2015-02-23 16:07:24 -05001386 fn := syslook("closechan", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001387
1388 argtype(fn, n.Left.Type)
1389 n = mkcall1(fn, nil, init, n.Left)
1390 goto ret
1391
1392 case OMAKECHAN:
1393 n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
1394 goto ret
1395
1396 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001397 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001398
Russ Cox382b44e2015-02-23 16:07:24 -05001399 fn := syslook("makemap", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001400
Russ Cox382b44e2015-02-23 16:07:24 -05001401 a := nodnil() // hmap buffer
1402 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001403 if n.Esc == EscNone {
1404 // Allocate hmap buffer on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001405 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001406
1407 a = Nod(OAS, var_, nil) // zero temp
1408 typecheck(&a, Etop)
1409 *init = list(*init, a)
1410 a = Nod(OADDR, var_, nil)
1411
1412 // Allocate one bucket on stack.
1413 // Maximum key/value size is 128 bytes, larger objects
1414 // are stored with an indirection. So max bucket size is 2048+eps.
1415 var_ = temp(mapbucket(t))
1416
1417 r = Nod(OAS, var_, nil) // zero temp
1418 typecheck(&r, Etop)
1419 *init = list(*init, r)
1420 r = Nod(OADDR, var_, nil)
1421 }
1422
1423 argtype(fn, hmap(t)) // hmap buffer
1424 argtype(fn, mapbucket(t)) // bucket buffer
1425 argtype(fn, t.Down) // key type
1426 argtype(fn, t.Type) // value type
1427 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
1428 goto ret
1429
1430 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001431 l := n.Left
1432 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001433 if r == nil {
1434 r = safeexpr(l, init)
1435 l = r
1436 }
Russ Cox382b44e2015-02-23 16:07:24 -05001437 t := n.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -05001438 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 -05001439 // var arr [r]T
1440 // n = arr[:l]
1441 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001442 var_ := temp(t)
1443 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001444 typecheck(&a, Etop)
1445 *init = list(*init, a)
Russ Cox382b44e2015-02-23 16:07:24 -05001446 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
1447 r = conv(r, n.Type) // in case n->type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001448 typecheck(&r, Erv)
1449 walkexpr(&r, init)
1450 n = r
1451 } else {
1452 // makeslice(t *Type, nel int64, max int64) (ary []any)
Russ Cox382b44e2015-02-23 16:07:24 -05001453 fn := syslook("makeslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001454
1455 argtype(fn, t.Type) // any-1
1456 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1457 }
1458
1459 goto ret
1460
1461 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001462 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001463 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001464 t := aindex(Nodintconst(4), Types[TUINT8])
1465 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001466 a = Nod(OADDR, var_, nil)
1467 }
1468
1469 // intstring(*[4]byte, rune)
1470 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1471
1472 goto ret
1473
1474 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001475 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001476 if n.Esc == EscNone {
1477 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001478 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001479
1480 a = Nod(OADDR, temp(t), nil)
1481 }
1482
1483 // slicebytetostring(*[32]byte, []byte) string;
1484 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1485
1486 goto ret
1487
1488 // slicebytetostringtmp([]byte) string;
1489 case OARRAYBYTESTRTMP:
1490 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1491
1492 goto ret
1493
1494 // slicerunetostring(*[32]byte, []rune) string;
1495 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001496 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001497
1498 if n.Esc == EscNone {
1499 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001500 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001501
1502 a = Nod(OADDR, temp(t), nil)
1503 }
1504
1505 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
1506 goto ret
1507
1508 // stringtoslicebyte(*32[byte], string) []byte;
1509 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001510 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001511
1512 if n.Esc == EscNone {
1513 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001514 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001515
1516 a = Nod(OADDR, temp(t), nil)
1517 }
1518
1519 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
1520 goto ret
1521
1522 // stringtoslicebytetmp(string) []byte;
1523 case OSTRARRAYBYTETMP:
1524 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1525
1526 goto ret
1527
1528 // stringtoslicerune(*[32]rune, string) []rune
1529 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001530 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001531
1532 if n.Esc == EscNone {
1533 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001534 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001535
1536 a = Nod(OADDR, temp(t), nil)
1537 }
1538
1539 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
1540 goto ret
1541
1542 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1543 case OCMPIFACE:
1544 if !Eqtype(n.Left.Type, n.Right.Type) {
1545 Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), Tconv(n.Left.Type, 0), Tconv(n.Right.Type, 0))
1546 }
Russ Cox382b44e2015-02-23 16:07:24 -05001547 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001548 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001549 fn = syslook("efaceeq", 1)
1550 } else {
1551 fn = syslook("ifaceeq", 1)
1552 }
1553
1554 n.Right = cheapexpr(n.Right, init)
1555 n.Left = cheapexpr(n.Left, init)
1556 argtype(fn, n.Right.Type)
1557 argtype(fn, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001558 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05001559 if n.Etype == ONE {
1560 r = Nod(ONOT, r, nil)
1561 }
1562
1563 // check itable/type before full compare.
1564 if n.Etype == OEQ {
1565 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1566 } else {
1567 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1568 }
1569 typecheck(&r, Erv)
1570 walkexpr(&r, init)
1571 r.Type = n.Type
1572 n = r
1573 goto ret
1574
1575 case OARRAYLIT,
1576 OMAPLIT,
1577 OSTRUCTLIT,
1578 OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001579 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001580 anylit(0, n, var_, init)
1581 n = var_
1582 goto ret
1583
1584 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001585 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001586 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1587 walkexpr(&n1, init)
1588 n1 = Nod(OADDR, n1, nil)
1589 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
1590 goto ret
1591
1592 case OCLOSURE:
1593 n = walkclosure(n, init)
1594 goto ret
1595
1596 case OCALLPART:
1597 n = walkpartialcall(n, init)
1598 goto ret
1599 }
1600
1601 Fatal("missing switch %v", Oconv(int(n.Op), 0))
1602
1603 // Expressions that are constant at run time but not
1604 // considered const by the language spec are not turned into
1605 // constants until walk. For example, if n is y%1 == 0, the
1606 // walk of y%1 may have replaced it by 0.
1607 // Check whether n with its updated args is itself now a constant.
1608ret:
Russ Cox382b44e2015-02-23 16:07:24 -05001609 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001610
1611 evconst(n)
1612 n.Type = t
1613 if n.Op == OLITERAL {
1614 typecheck(&n, Erv)
1615 }
1616
1617 ullmancalc(n)
1618
1619 if Debug['w'] != 0 && n != nil {
1620 Dump("walk", n)
1621 }
1622
1623 lineno = lno
1624 *np = n
1625}
1626
1627func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001628 // convas will turn map assigns into function calls,
1629 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001630 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001631
1632 if l.Op == OINDEXMAP {
1633 return n
1634 }
1635
1636 return convas(n, init)
1637}
1638
1639func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
1640 var ll *NodeList
1641 var lr *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001642
1643 /*
1644 * check assign expression list to
1645 * a expression list. called in
1646 * expr-list = expr-list
1647 */
1648
1649 // ensure order of evaluation for function calls
1650 for ll = nl; ll != nil; ll = ll.Next {
1651 ll.N = safeexpr(ll.N, init)
1652 }
1653 for lr = nr; lr != nil; lr = lr.Next {
1654 lr.N = safeexpr(lr.N, init)
1655 }
1656
Russ Cox175929b2015-03-02 14:22:05 -05001657 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001658 ll = nl
1659 lr = nr
1660 for ; ll != nil && lr != nil; (func() { ll = ll.Next; lr = lr.Next })() {
1661 // Do not generate 'x = x' during return. See issue 4014.
1662 if op == ORETURN && ll.N == lr.N {
1663 continue
1664 }
1665 nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
1666 }
1667
1668 // cannot happen: caller checked that lists had same length
1669 if ll != nil || lr != nil {
1670 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)
1671 }
1672 return nn
1673}
1674
1675/*
1676 * l is an lv and rt is the type of an rv
1677 * return 1 if this implies a function call
1678 * evaluating the lv or a function call
1679 * in the conversion of the types
1680 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001681func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001682 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001683 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001684 }
Russ Cox175929b2015-03-02 14:22:05 -05001685 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001686 if needwritebarrier(l, &r) {
1687 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001688 }
1689 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001690 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001691 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001692 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001693}
1694
1695func ascompatet(op int, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
1696 var l *Node
1697 var tmp *Node
1698 var a *Node
1699 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001700 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001701
1702 /*
1703 * check assign type list to
1704 * a expression list. called in
1705 * expr-list = func()
1706 */
Russ Cox382b44e2015-02-23 16:07:24 -05001707 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001708
Russ Cox175929b2015-03-02 14:22:05 -05001709 var nn *NodeList
1710 var mm *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001711 ucount := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001712 for ll = nl; ll != nil; ll = ll.Next {
1713 if r == nil {
1714 break
1715 }
1716 l = ll.N
1717 if isblank(l) {
1718 r = structnext(&saver)
1719 continue
1720 }
1721
1722 // any lv that causes a fn call must be
1723 // deferred until all the return arguments
1724 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001725 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001726 tmp = temp(r.Type)
1727 typecheck(&tmp, Erv)
1728 a = Nod(OAS, l, tmp)
1729 a = convas(a, init)
1730 mm = list(mm, a)
1731 l = tmp
1732 }
1733
1734 a = Nod(OAS, l, nodarg(r, fp))
1735 a = convas(a, init)
1736 ullmancalc(a)
1737 if a.Ullman >= UINF {
1738 Dump("ascompatet ucount", a)
1739 ucount++
1740 }
1741
1742 nn = list(nn, a)
1743 r = structnext(&saver)
1744 }
1745
1746 if ll != nil || r != nil {
1747 Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
1748 }
1749
1750 if ucount != 0 {
1751 Fatal("ascompatet: too many function calls evaluating parameters")
1752 }
1753 return concat(nn, mm)
1754}
1755
1756/*
1757* package all the arguments that match a ... T parameter into a []T.
1758 */
1759func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
Russ Cox382b44e2015-02-23 16:07:24 -05001760 esc := EscUnknown
Russ Cox8c195bd2015-02-13 14:40:36 -05001761 if ddd != nil {
1762 esc = int(ddd.Esc)
1763 }
1764
Russ Cox382b44e2015-02-23 16:07:24 -05001765 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001766 tslice.Type = l.Type.Type
1767 tslice.Bound = -1
1768
Russ Cox382b44e2015-02-23 16:07:24 -05001769 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001770 if count(lr0) == 0 {
1771 n = nodnil()
1772 n.Type = tslice
1773 } else {
1774 n = Nod(OCOMPLIT, nil, typenod(tslice))
1775 if ddd != nil {
1776 n.Alloc = ddd.Alloc // temporary to use
1777 }
1778 n.List = lr0
1779 n.Esc = uint(esc)
1780 typecheck(&n, Erv)
1781 if n.Type == nil {
1782 Fatal("mkdotargslice: typecheck failed")
1783 }
1784 walkexpr(&n, init)
1785 }
1786
Russ Cox382b44e2015-02-23 16:07:24 -05001787 a := Nod(OAS, nodarg(l, fp), n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001788 nn = list(nn, convas(a, init))
1789 return nn
1790}
1791
1792/*
1793 * helpers for shape errors
1794 */
1795func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001796 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001797
Russ Cox382b44e2015-02-23 16:07:24 -05001798 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001799 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001800 first := 1
1801 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001802 if first != 0 {
1803 first = 0
1804 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001805 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 }
1807 fmt_ += fmt.Sprintf("%v", Tconv(l, 0))
1808 }
1809
1810 if first != 0 {
1811 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1812 }
1813 return fmt_
1814}
1815
1816func dumpnodetypes(l *NodeList, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001817 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001818
Russ Cox382b44e2015-02-23 16:07:24 -05001819 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001820 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001821 first := 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001822 for ; l != nil; l = l.Next {
1823 r = l.N
1824 if first != 0 {
1825 first = 0
1826 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001827 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001828 }
1829 fmt_ += fmt.Sprintf("%v", Tconv(r.Type, 0))
1830 }
1831
1832 if first != 0 {
1833 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1834 }
1835 return fmt_
1836}
1837
1838/*
1839 * check assign expression list to
1840 * a type list. called in
1841 * return expr-list
1842 * func(expr-list)
1843 */
1844func ascompatte(op int, call *Node, isddd int, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001845 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001846
Russ Cox382b44e2015-02-23 16:07:24 -05001847 lr0 := lr
1848 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001849 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001850 if lr != nil {
1851 r = lr.N
1852 }
Russ Cox175929b2015-03-02 14:22:05 -05001853 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001854
1855 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001856 var a *Node
1857 var l2 string
1858 var ll *Type
1859 var l1 string
Russ Cox8c195bd2015-02-13 14:40:36 -05001860 if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg != 0 {
1861 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001862 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001863 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001864 r = Nod(OCONVNOP, r, nil)
1865 r.Type = a.Type
1866 nn = list1(convas(Nod(OAS, a, r), init))
1867 goto ret
1868 }
1869
1870 // conversions involved.
1871 // copy into temporaries.
Russ Cox175929b2015-03-02 14:22:05 -05001872 var alist *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001873
Russ Cox382b44e2015-02-23 16:07:24 -05001874 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001875 a = temp(l.Type)
1876 alist = list(alist, a)
1877 }
1878
1879 a = Nod(OAS2, nil, nil)
1880 a.List = alist
1881 a.Rlist = lr
1882 typecheck(&a, Etop)
1883 walkstmt(&a)
1884 *init = list(*init, a)
1885 lr = alist
1886 r = lr.N
1887 l = Structfirst(&savel, nl)
1888 }
1889
1890loop:
1891 if l != nil && l.Isddd != 0 {
1892 // the ddd parameter must be last
1893 ll = structnext(&savel)
1894
1895 if ll != nil {
1896 Yyerror("... must be last argument")
1897 }
1898
1899 // special case --
1900 // only if we are assigning a single ddd
1901 // argument to a ddd parameter then it is
1902 // passed thru unencapsulated
1903 if r != nil && lr.Next == nil && isddd != 0 && Eqtype(l.Type, r.Type) {
1904 a = Nod(OAS, nodarg(l, fp), r)
1905 a = convas(a, init)
1906 nn = list(nn, a)
1907 goto ret
1908 }
1909
1910 // normal case -- make a slice of all
1911 // remaining arguments and pass it to
1912 // the ddd parameter.
1913 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1914
1915 goto ret
1916 }
1917
1918 if l == nil || r == nil {
1919 if l != nil || r != nil {
1920 l1 = dumptypes(nl, "expected")
1921 l2 = dumpnodetypes(lr0, "given")
1922 if l != nil {
1923 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1924 } else {
1925 Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1926 }
1927 }
1928
1929 goto ret
1930 }
1931
1932 a = Nod(OAS, nodarg(l, fp), r)
1933 a = convas(a, init)
1934 nn = list(nn, a)
1935
1936 l = structnext(&savel)
1937 r = nil
1938 lr = lr.Next
1939 if lr != nil {
1940 r = lr.N
1941 }
1942 goto loop
1943
1944ret:
1945 for lr = nn; lr != nil; lr = lr.Next {
1946 lr.N.Typecheck = 1
1947 }
1948 return nn
1949}
1950
1951// generate code for print
1952func walkprint(nn *Node, init **NodeList) *Node {
1953 var r *Node
1954 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001955 var on *Node
1956 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001957 var et int
Russ Cox8c195bd2015-02-13 14:40:36 -05001958
Russ Cox382b44e2015-02-23 16:07:24 -05001959 op := int(nn.Op)
1960 all := nn.List
Russ Cox175929b2015-03-02 14:22:05 -05001961 var calls *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001962 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001963
1964 // Hoist all the argument evaluation up before the lock.
1965 walkexprlistcheap(all, init)
1966
1967 calls = list(calls, mkcall("printlock", nil, init))
1968
Russ Cox382b44e2015-02-23 16:07:24 -05001969 for l := all; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001970 if notfirst {
Russ Cox8c195bd2015-02-13 14:40:36 -05001971 calls = list(calls, mkcall("printsp", nil, init))
1972 }
1973
Russ Coxdc7b54b2015-02-17 22:13:49 -05001974 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001975
1976 n = l.N
1977 if n.Op == OLITERAL {
1978 switch n.Val.Ctype {
1979 case CTRUNE:
1980 defaultlit(&n, runetype)
1981
1982 case CTINT:
1983 defaultlit(&n, Types[TINT64])
1984
1985 case CTFLT:
1986 defaultlit(&n, Types[TFLOAT64])
1987 }
1988 }
1989
1990 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
1991 defaultlit(&n, Types[TINT64])
1992 }
1993 defaultlit(&n, nil)
1994 l.N = n
1995 if n.Type == nil || n.Type.Etype == TFORW {
1996 continue
1997 }
1998
1999 t = n.Type
2000 et = int(n.Type.Etype)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002001 if Isinter(n.Type) {
2002 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002003 on = syslook("printeface", 1)
2004 } else {
2005 on = syslook("printiface", 1)
2006 }
2007 argtype(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002008 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Russ Cox8c195bd2015-02-13 14:40:36 -05002009 on = syslook("printpointer", 1)
2010 argtype(on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05002011 } else if Isslice(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002012 on = syslook("printslice", 1)
2013 argtype(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002014 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002015 if et == TUINT64 {
2016 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
2017 on = syslook("printhex", 0)
2018 } else {
2019 on = syslook("printuint", 0)
2020 }
2021 } else {
2022 on = syslook("printint", 0)
2023 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002024 } else if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002025 on = syslook("printfloat", 0)
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002026 } else if Iscomplex[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002027 on = syslook("printcomplex", 0)
2028 } else if et == TBOOL {
2029 on = syslook("printbool", 0)
2030 } else if et == TSTRING {
2031 on = syslook("printstring", 0)
2032 } else {
2033 badtype(OPRINT, n.Type, nil)
2034 continue
2035 }
2036
2037 t = *getinarg(on.Type)
2038 if t != nil {
2039 t = t.Type
2040 }
2041 if t != nil {
2042 t = t.Type
2043 }
2044
2045 if !Eqtype(t, n.Type) {
2046 n = Nod(OCONV, n, nil)
2047 n.Type = t
2048 }
2049
2050 r = Nod(OCALL, on, nil)
2051 r.List = list1(n)
2052 calls = list(calls, r)
2053 }
2054
2055 if op == OPRINTN {
2056 calls = list(calls, mkcall("printnl", nil, nil))
2057 }
2058
2059 calls = list(calls, mkcall("printunlock", nil, init))
2060
2061 typechecklist(calls, Etop)
2062 walkexprlist(calls, init)
2063
2064 r = Nod(OEMPTY, nil, nil)
2065 typecheck(&r, Etop)
2066 walkexpr(&r, init)
2067 r.Ninit = calls
2068 return r
2069}
2070
2071func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002072 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -05002073 fn := syslook("newobject", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002074 argtype(fn, t)
2075 return mkcall1(fn, Ptrto(t), nil, typename(t))
2076}
2077
Russ Coxdc7b54b2015-02-17 22:13:49 -05002078func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002079 n = outervalue(n)
2080
2081 // If n is *autotmp and autotmp = &foo, replace n with foo.
2082 // We introduce such temps when initializing struct literals.
2083 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox382b44e2015-02-23 16:07:24 -05002084 defn := n.Left.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002085 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2086 n = defn.Right.Left
2087 }
2088 }
2089
2090 switch n.Op {
2091 // OINDREG only ends up in walk if it's indirect of SP.
2092 case OINDREG:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002093 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002094
2095 case ONAME:
2096 switch n.Class {
2097 case PAUTO,
2098 PPARAM,
2099 PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002100 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002101 }
2102 }
2103
Russ Coxdc7b54b2015-02-17 22:13:49 -05002104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002105}
2106
Russ Coxdc7b54b2015-02-17 22:13:49 -05002107func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002108 n = outervalue(n)
2109
2110 switch n.Op {
2111 case ONAME:
2112 switch n.Class {
2113 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002114 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002115 }
2116 }
2117
Russ Coxdc7b54b2015-02-17 22:13:49 -05002118 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002119}
2120
2121// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002122func needwritebarrier(l *Node, r *Node) bool {
2123 if use_writebarrier == 0 {
2124 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002125 }
2126
2127 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002128 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002129 }
2130
2131 // No write barrier for write of non-pointers.
2132 dowidth(l.Type)
2133
2134 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002135 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002136 }
2137
2138 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002139 if isstack(l) {
2140 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002141 }
2142
2143 // No write barrier for implicit or explicit zeroing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002144 if r == nil || iszero(r) {
2145 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002146 }
2147
2148 // No write barrier for initialization to constant.
2149 if r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002150 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002151 }
2152
2153 // No write barrier for storing static (read-only) data.
2154 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002155 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 }
2157
2158 // No write barrier for storing address of stack values,
2159 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002160 if r.Op == OADDR && isstack(r.Left) {
2161 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002162 }
2163
2164 // No write barrier for storing address of global, which
2165 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002166 if r.Op == OADDR && isglobal(r.Left) {
2167 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002168 }
2169
2170 // No write barrier for reslice: x = x[0:y] or x = append(x, ...).
2171 // Both are compiled to modify x directly.
2172 // In the case of append, a write barrier may still be needed
2173 // if the underlying array grows, but the append code can
2174 // generate the write barrier directly in that case.
2175 // (It does not yet, but the cost of the write barrier will be
2176 // small compared to the cost of the allocation.)
2177 if r.Reslice != 0 {
2178 switch r.Op {
2179 case OSLICE,
2180 OSLICE3,
2181 OSLICESTR,
2182 OAPPEND:
2183 break
2184
2185 default:
2186 Dump("bad reslice-l", l)
2187 Dump("bad reslice-r", r)
2188 }
2189
Russ Coxdc7b54b2015-02-17 22:13:49 -05002190 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002191 }
2192
2193 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002194 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002195}
2196
2197// TODO(rsc): Perhaps componentgen should run before this.
2198
2199var applywritebarrier_bv *Bvec
2200
2201func applywritebarrier(n *Node, init **NodeList) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002202 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002203 if Curfn != nil && Curfn.Nowritebarrier {
2204 Yyerror("write barrier prohibited")
2205 }
Russ Cox382b44e2015-02-23 16:07:24 -05002206 t := n.Left.Type
2207 l := Nod(OADDR, n.Left, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002208 l.Etype = 1 // addr does not escape
2209 if t.Width == int64(Widthptr) {
2210 n = mkcall1(writebarrierfn("writebarrierptr", t, n.Right.Type), nil, init, l, n.Right)
2211 } else if t.Etype == TSTRING {
2212 n = mkcall1(writebarrierfn("writebarrierstring", t, n.Right.Type), nil, init, l, n.Right)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002213 } else if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002214 n = mkcall1(writebarrierfn("writebarrierslice", t, n.Right.Type), nil, init, l, n.Right)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002215 } else if Isinter(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002216 n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right)
2217 } else if t.Width <= int64(4*Widthptr) {
Russ Cox382b44e2015-02-23 16:07:24 -05002218 x := int64(0)
Russ Cox8c195bd2015-02-13 14:40:36 -05002219 if applywritebarrier_bv == nil {
2220 applywritebarrier_bv = bvalloc(obj.BitsPerPointer * 4)
2221 }
2222 bvresetall(applywritebarrier_bv)
2223 twobitwalktype1(t, &x, applywritebarrier_bv)
2224 const (
2225 PtrBit = 1
2226 )
2227 // The bvgets are looking for BitsPointer in successive slots.
2228 if obj.BitsPointer != 1<<PtrBit {
2229 Fatal("wrong PtrBit")
2230 }
Russ Cox382b44e2015-02-23 16:07:24 -05002231 var name string
Russ Cox8c195bd2015-02-13 14:40:36 -05002232 switch t.Width / int64(Widthptr) {
2233 default:
2234 Fatal("found writebarrierfat for %d-byte object of type %v", int(t.Width), Tconv(t, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002235
2236 case 2:
2237 name = fmt.Sprintf("writebarrierfat%d%d", bvget(applywritebarrier_bv, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit))
2238
2239 case 3:
2240 name = fmt.Sprintf("writebarrierfat%d%d%d", bvget(applywritebarrier_bv, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 2*obj.BitsPerPointer+PtrBit))
2241
2242 case 4:
2243 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))
2244 }
2245
2246 n = mkcall1(writebarrierfn(name, t, n.Right.Type), nil, init, l, nodnil(), n.Right)
2247 } else {
Russ Cox382b44e2015-02-23 16:07:24 -05002248 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002249 for r.Op == OCONVNOP {
2250 r = r.Left
2251 }
2252 r = Nod(OADDR, r, nil)
2253 r.Etype = 1 // addr does not escape
2254
2255 //warnl(n->lineno, "typedmemmove %T %N", t, r);
2256 n = mkcall1(writebarrierfn("typedmemmove", t, r.Left.Type), nil, init, typename(t), l, r)
2257 }
2258 }
2259
2260 return n
2261}
2262
2263func convas(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002264 if n.Op != OAS {
2265 Fatal("convas: not OAS %v", Oconv(int(n.Op), 0))
2266 }
2267
2268 n.Typecheck = 1
2269
Russ Cox382b44e2015-02-23 16:07:24 -05002270 var lt *Type
2271 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002272 if n.Left == nil || n.Right == nil {
2273 goto out
2274 }
2275
2276 lt = n.Left.Type
2277 rt = n.Right.Type
2278 if lt == nil || rt == nil {
2279 goto out
2280 }
2281
2282 if isblank(n.Left) {
2283 defaultlit(&n.Right, nil)
2284 goto out
2285 }
2286
2287 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002288 map_ := n.Left.Left
2289 key := n.Left.Right
2290 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002291 walkexpr(&map_, init)
2292 walkexpr(&key, init)
2293 walkexpr(&val, init)
2294
2295 // orderexpr made sure key and val are addressable.
2296 key = Nod(OADDR, key, nil)
2297
2298 val = Nod(OADDR, val, nil)
2299 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2300 goto out
2301 }
2302
2303 if !Eqtype(lt, rt) {
2304 n.Right = assignconv(n.Right, lt, "assignment")
2305 walkexpr(&n.Right, init)
2306 }
2307
2308out:
2309 ullmancalc(n)
2310 return n
2311}
2312
2313/*
2314 * from ascompat[te]
2315 * evaluating actual function arguments.
2316 * f(a,b)
2317 * if there is exactly one function expr,
2318 * then it is done first. otherwise must
2319 * make temp variables
2320 */
2321func reorder1(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002322 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002323
Russ Cox382b44e2015-02-23 16:07:24 -05002324 c := 0 // function calls
2325 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002326
Russ Cox382b44e2015-02-23 16:07:24 -05002327 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002328 n = l.N
2329 t++
2330 ullmancalc(n)
2331 if n.Ullman >= UINF {
2332 c++
2333 }
2334 }
2335
2336 if c == 0 || t == 1 {
2337 return all
2338 }
2339
Russ Cox175929b2015-03-02 14:22:05 -05002340 var g *NodeList // fncalls assigned to tempnames
2341 var f *Node // last fncall assigned to stack
2342 var r *NodeList // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002343 d := 0
2344 var a *Node
2345 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002346 n = l.N
2347 if n.Ullman < UINF {
2348 r = list(r, n)
2349 continue
2350 }
2351
2352 d++
2353 if d == c {
2354 f = n
2355 continue
2356 }
2357
2358 // make assignment of fncall to tempname
2359 a = temp(n.Right.Type)
2360
2361 a = Nod(OAS, a, n.Right)
2362 g = list(g, a)
2363
2364 // put normal arg assignment on list
2365 // with fncall replaced by tempname
2366 n.Right = a.Left
2367
2368 r = list(r, n)
2369 }
2370
2371 if f != nil {
2372 g = list(g, f)
2373 }
2374 return concat(g, r)
2375}
2376
2377/*
2378 * from ascompat[ee]
2379 * a,b = c,d
2380 * simultaneous assignment. there cannot
2381 * be later use of an earlier lvalue.
2382 *
2383 * function calls have been removed.
2384 */
2385func reorder3(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002386 var l *Node
2387
2388 // If a needed expression may be affected by an
2389 // earlier assignment, make an early copy of that
2390 // expression and use the copy instead.
Russ Cox175929b2015-03-02 14:22:05 -05002391 var early *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002392
Russ Cox175929b2015-03-02 14:22:05 -05002393 var mapinit *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002394 for list := all; list != nil; list = list.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002395 l = list.N.Left
2396
2397 // Save subexpressions needed on left side.
2398 // Drill through non-dereferences.
2399 for {
2400 if l.Op == ODOT || l.Op == OPAREN {
2401 l = l.Left
2402 continue
2403 }
2404
Russ Coxdc7b54b2015-02-17 22:13:49 -05002405 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002406 reorder3save(&l.Right, all, list, &early)
2407 l = l.Left
2408 continue
2409 }
2410
2411 break
2412 }
2413
2414 switch l.Op {
2415 default:
2416 Fatal("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002417
2418 case ONAME:
2419 break
2420
2421 case OINDEX,
2422 OINDEXMAP:
2423 reorder3save(&l.Left, all, list, &early)
2424 reorder3save(&l.Right, all, list, &early)
2425 if l.Op == OINDEXMAP {
2426 list.N = convas(list.N, &mapinit)
2427 }
2428
2429 case OIND,
2430 ODOTPTR:
2431 reorder3save(&l.Left, all, list, &early)
2432 }
2433
2434 // Save expression on right side.
2435 reorder3save(&list.N.Right, all, list, &early)
2436 }
2437
2438 early = concat(mapinit, early)
2439 return concat(early, all)
2440}
2441
2442/*
2443 * if the evaluation of *np would be affected by the
2444 * assignments in all up to but not including stop,
2445 * copy into a temporary during *early and
2446 * replace *np with that temp.
2447 */
2448func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05002449 n := *np
Russ Coxdc7b54b2015-02-17 22:13:49 -05002450 if !aliased(n, all, stop) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002451 return
2452 }
2453
Russ Cox382b44e2015-02-23 16:07:24 -05002454 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002455 q = Nod(OAS, q, n)
2456 typecheck(&q, Etop)
2457 *early = list(*early, q)
2458 *np = q.Left
2459}
2460
2461/*
2462 * what's the outer value that a write to n affects?
2463 * outer value means containing struct or array.
2464 */
2465func outervalue(n *Node) *Node {
2466 for {
2467 if n.Op == OXDOT {
2468 Fatal("OXDOT in walk")
2469 }
2470 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2471 n = n.Left
2472 continue
2473 }
2474
Russ Coxdc7b54b2015-02-17 22:13:49 -05002475 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002476 n = n.Left
2477 continue
2478 }
2479
2480 break
2481 }
2482
2483 return n
2484}
2485
2486/*
2487 * Is it possible that the computation of n might be
2488 * affected by writes in as up to but not including stop?
2489 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002490func aliased(n *Node, all *NodeList, stop *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002491 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002492 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002493 }
2494
2495 // Look for obvious aliasing: a variable being assigned
2496 // during the all list and appearing in n.
2497 // Also record whether there are any writes to main memory.
2498 // Also record whether there are any writes to variables
2499 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002500 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002501
Russ Cox382b44e2015-02-23 16:07:24 -05002502 varwrite := 0
2503 var a *Node
2504 for l := all; l != stop; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002505 a = outervalue(l.N.Left)
2506 if a.Op != ONAME {
2507 memwrite = 1
2508 continue
2509 }
2510
2511 switch n.Class {
2512 default:
2513 varwrite = 1
2514 continue
2515
2516 case PAUTO,
2517 PPARAM,
2518 PPARAMOUT:
2519 if n.Addrtaken != 0 {
2520 varwrite = 1
2521 continue
2522 }
2523
Russ Coxdc7b54b2015-02-17 22:13:49 -05002524 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002525 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002526 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002527 }
2528 }
2529 }
2530
2531 // The variables being written do not appear in n.
2532 // However, n might refer to computed addresses
2533 // that are being written.
2534
2535 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002536 if memwrite == 0 && varwrite == 0 {
2537 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002538 }
2539
2540 // If n does not refer to computed addresses
2541 // (that is, if n only refers to variables whose addresses
2542 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002543 if varexpr(n) {
2544 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002545 }
2546
2547 // Otherwise, both the writes and n refer to computed memory addresses.
2548 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002549 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002550}
2551
2552/*
2553 * does the evaluation of n only refer to variables
2554 * whose addresses have not been taken?
2555 * (and no other memory)
2556 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002557func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002558 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002559 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002560 }
2561
2562 switch n.Op {
2563 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002564 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002565
2566 case ONAME:
2567 switch n.Class {
2568 case PAUTO,
2569 PPARAM,
2570 PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002571 if n.Addrtaken == 0 {
2572 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002573 }
2574 }
2575
Russ Coxdc7b54b2015-02-17 22:13:49 -05002576 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002577
2578 case OADD,
2579 OSUB,
2580 OOR,
2581 OXOR,
2582 OMUL,
2583 ODIV,
2584 OMOD,
2585 OLSH,
2586 ORSH,
2587 OAND,
2588 OANDNOT,
2589 OPLUS,
2590 OMINUS,
2591 OCOM,
2592 OPAREN,
2593 OANDAND,
2594 OOROR,
2595 ODOT, // but not ODOTPTR
2596 OCONV,
2597 OCONVNOP,
2598 OCONVIFACE,
2599 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002600 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002601 }
2602
2603 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002604 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002605}
2606
2607/*
2608 * is the name l mentioned in r?
2609 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002610func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002611 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002612 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002613 }
2614 switch r.Op {
2615 // match each right given left
2616 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002617 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002618
2619 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002620 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002621 }
2622
Russ Coxdc7b54b2015-02-17 22:13:49 -05002623 if vmatch2(l, r.Left) {
2624 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002625 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002626 if vmatch2(l, r.Right) {
2627 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002628 }
Russ Cox382b44e2015-02-23 16:07:24 -05002629 for ll := r.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002630 if vmatch2(l, ll.N) {
2631 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002632 }
2633 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002634 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002635}
2636
2637/*
2638 * is any name mentioned in l also mentioned in r?
2639 * called by sinit.c
2640 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002641func vmatch1(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002642 /*
2643 * isolate all left sides
2644 */
2645 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002646 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002647 }
2648 switch l.Op {
2649 case ONAME:
2650 switch l.Class {
2651 case PPARAM,
2652 PPARAMREF,
2653 PAUTO:
2654 break
2655
2656 // assignment to non-stack variable
2657 // must be delayed if right has function calls.
2658 default:
2659 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002660 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002661 }
2662 }
2663
2664 return vmatch2(l, r)
2665
2666 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002667 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002668 }
2669
Russ Coxdc7b54b2015-02-17 22:13:49 -05002670 if vmatch1(l.Left, r) {
2671 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002672 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002673 if vmatch1(l.Right, r) {
2674 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002675 }
Russ Cox382b44e2015-02-23 16:07:24 -05002676 for ll := l.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002677 if vmatch1(ll.N, r) {
2678 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002679 }
2680 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002681 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002682}
2683
2684/*
2685 * walk through argin parameters.
2686 * generate and return code to allocate
2687 * copies of escaped parameters to the heap.
2688 */
2689func paramstoheap(argin **Type, out int) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002690 var savet Iter
2691 var v *Node
2692 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002693
Russ Cox175929b2015-03-02 14:22:05 -05002694 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002695 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002696 v = t.Nname
2697 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2698 v = nil
2699 }
2700
2701 // For precise stacks, the garbage collector assumes results
2702 // are always live, so zero them always.
2703 if out != 0 {
2704 // Defer might stop a panic and show the
2705 // return values as they exist at the time of panic.
2706 // Make sure to zero them on entry to the function.
2707 nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
2708 }
2709
Russ Coxdc7b54b2015-02-17 22:13:49 -05002710 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002711 continue
2712 }
2713
2714 // generate allocation & copying code
2715 if compiling_runtime != 0 {
2716 Yyerror("%v escapes to heap, not allowed in runtime.", Nconv(v, 0))
2717 }
2718 if v.Alloc == nil {
2719 v.Alloc = callnew(v.Type)
2720 }
2721 nn = list(nn, Nod(OAS, v.Heapaddr, v.Alloc))
2722 if v.Class&^PHEAP != PPARAMOUT {
2723 as = Nod(OAS, v, v.Stackparam)
2724 v.Stackparam.Typecheck = 1
2725 typecheck(&as, Etop)
2726 as = applywritebarrier(as, &nn)
2727 nn = list(nn, as)
2728 }
2729 }
2730
2731 return nn
2732}
2733
2734/*
2735 * walk through argout parameters copying back to stack
2736 */
2737func returnsfromheap(argin **Type) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002738 var savet Iter
2739 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002740
Russ Cox175929b2015-03-02 14:22:05 -05002741 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002742 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002743 v = t.Nname
2744 if v == nil || v.Class != PHEAP|PPARAMOUT {
2745 continue
2746 }
2747 nn = list(nn, Nod(OAS, v.Stackparam, v))
2748 }
2749
2750 return nn
2751}
2752
2753/*
2754 * take care of migrating any function in/out args
2755 * between the stack and the heap. adds code to
2756 * curfn's before and after lists.
2757 */
2758func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002759 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002760 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002761 nn := paramstoheap(getthis(Curfn.Type), 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05002762 nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
2763 nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
2764 Curfn.Enter = concat(Curfn.Enter, nn)
2765 lineno = Curfn.Endlineno
2766 Curfn.Exit = returnsfromheap(Getoutarg(Curfn.Type))
2767 lineno = lno
2768}
2769
2770func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002771 if fn.Type == nil || fn.Type.Etype != TFUNC {
2772 Fatal("mkcall %v %v", Nconv(fn, 0), Tconv(fn.Type, 0))
2773 }
2774
Russ Cox175929b2015-03-02 14:22:05 -05002775 var args *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002776 n := fn.Type.Intuple
2777 for i := 0; i < n; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05002778 args = list(args, va[i])
2779 }
2780
Russ Cox382b44e2015-02-23 16:07:24 -05002781 r := Nod(OCALL, fn, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002782 r.List = args
2783 if fn.Type.Outtuple > 0 {
2784 typecheck(&r, Erv|Efnstruct)
2785 } else {
2786 typecheck(&r, Etop)
2787 }
2788 walkexpr(&r, init)
2789 r.Type = t
2790 return r
2791}
2792
2793func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
2794 return vmkcall(syslook(name, 0), t, init, args)
2795}
2796
2797func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
2798 return vmkcall(fn, t, init, args)
2799}
2800
2801func conv(n *Node, t *Type) *Node {
2802 if Eqtype(n.Type, t) {
2803 return n
2804 }
2805 n = Nod(OCONV, n, nil)
2806 n.Type = t
2807 typecheck(&n, Erv)
2808 return n
2809}
2810
2811func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002812 if t.Etype != TCHAN {
2813 Fatal("chanfn %v", Tconv(t, 0))
2814 }
Russ Cox382b44e2015-02-23 16:07:24 -05002815 fn := syslook(name, 1)
2816 for i := 0; i < n; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05002817 argtype(fn, t.Type)
2818 }
2819 return fn
2820}
2821
2822func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002823 if t.Etype != TMAP {
2824 Fatal("mapfn %v", Tconv(t, 0))
2825 }
Russ Cox382b44e2015-02-23 16:07:24 -05002826 fn := syslook(name, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002827 argtype(fn, t.Down)
2828 argtype(fn, t.Type)
2829 argtype(fn, t.Down)
2830 argtype(fn, t.Type)
2831 return fn
2832}
2833
2834func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002835 if t.Etype != TMAP {
2836 Fatal("mapfn %v", Tconv(t, 0))
2837 }
Russ Cox382b44e2015-02-23 16:07:24 -05002838 fn := syslook(name, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002839 argtype(fn, t.Down)
2840 argtype(fn, t.Type)
2841 argtype(fn, t.Down)
2842 return fn
2843}
2844
2845func writebarrierfn(name string, l *Type, r *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002846 fn := syslook(name, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002847 argtype(fn, l)
2848 argtype(fn, r)
2849 return fn
2850}
2851
2852func addstr(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002853 // orderexpr rewrote OADDSTR to have a list of strings.
Russ Cox382b44e2015-02-23 16:07:24 -05002854 c := count(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002855
2856 if c < 2 {
2857 Yyerror("addstr count %d too small", c)
2858 }
2859
Russ Cox382b44e2015-02-23 16:07:24 -05002860 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002861 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002862 sz := int64(0)
2863 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002864 if n.Op == OLITERAL {
2865 sz += int64(len(n.Val.U.Sval.S))
2866 }
2867 }
2868
2869 // Don't allocate the buffer if the result won't fit.
2870 if sz < tmpstringbufsize {
2871 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002872 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002873
2874 buf = Nod(OADDR, temp(t), nil)
2875 }
2876 }
2877
2878 // build list of string arguments
Russ Cox382b44e2015-02-23 16:07:24 -05002879 args := list1(buf)
Russ Cox8c195bd2015-02-13 14:40:36 -05002880
Russ Cox382b44e2015-02-23 16:07:24 -05002881 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002882 args = list(args, conv(l.N, Types[TSTRING]))
2883 }
2884
2885 if c <= 5 {
2886 // small numbers of strings use direct runtime helpers.
2887 // note: orderexpr knows this cutoff too.
2888 namebuf = fmt.Sprintf("concatstring%d", c)
2889 } else {
2890 // large numbers of strings are passed to the runtime as a slice.
2891 namebuf = "concatstrings"
2892
Russ Cox382b44e2015-02-23 16:07:24 -05002893 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002894 t.Type = Types[TSTRING]
2895 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002896 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05002897 slice.Alloc = n.Alloc
2898 slice.List = args.Next // skip buf arg
2899 args = list1(buf)
2900 args = list(args, slice)
2901 slice.Esc = EscNone
2902 }
2903
Russ Cox382b44e2015-02-23 16:07:24 -05002904 cat := syslook(namebuf, 1)
2905 r := Nod(OCALL, cat, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002906 r.List = args
2907 typecheck(&r, Erv)
2908 walkexpr(&r, init)
2909 r.Type = n.Type
2910
2911 return r
2912}
2913
2914// expand append(l1, l2...) to
2915// init {
2916// s := l1
2917// if n := len(l1) + len(l2) - cap(s); n > 0 {
2918// s = growslice(s, n)
2919// }
2920// s = s[:len(l1)+len(l2)]
2921// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2922// }
2923// s
2924//
2925// l2 is allowed to be a string.
2926func appendslice(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002927 walkexprlistsafe(n.List, init)
2928
2929 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2930 // and n are name or literal, but those may index the slice we're
2931 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05002932 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002933 l.N = cheapexpr(l.N, init)
2934 }
2935
Russ Cox382b44e2015-02-23 16:07:24 -05002936 l1 := n.List.N
2937 l2 := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -05002938
Russ Cox382b44e2015-02-23 16:07:24 -05002939 s := temp(l1.Type) // var s []T
Russ Cox175929b2015-03-02 14:22:05 -05002940 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002941 l = list(l, Nod(OAS, s, l1)) // s = l1
2942
Russ Cox382b44e2015-02-23 16:07:24 -05002943 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002944
Russ Cox382b44e2015-02-23 16:07:24 -05002945 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002946
2947 // n := len(s) + len(l2) - cap(s)
2948 nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
2949
2950 nif.Ntest = Nod(OGT, nt, Nodintconst(0))
2951
2952 // instantiate growslice(Type*, []any, int64) []any
Russ Cox382b44e2015-02-23 16:07:24 -05002953 fn := syslook("growslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002954
2955 argtype(fn, s.Type.Type)
2956 argtype(fn, s.Type.Type)
2957
2958 // s = growslice(T, s, n)
2959 nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, conv(nt, Types[TINT64]))))
2960
2961 l = list(l, nif)
2962
2963 if haspointers(l1.Type.Type) {
2964 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002965 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 -05002966
2967 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002968 nptr2 := l2
2969 fn := syslook("typedslicecopy", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05002970 argtype(fn, l1.Type)
2971 argtype(fn, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002972 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
Russ Cox8c195bd2015-02-13 14:40:36 -05002973 l = list(l, nt)
2974 } else if flag_race != 0 {
2975 // rely on runtime to instrument copy.
2976 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002977 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 -05002978
2979 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002980 nptr2 := l2
2981 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002982 if l2.Type.Etype == TSTRING {
2983 fn = syslook("slicestringcopy", 1)
2984 } else {
2985 fn = syslook("slicecopy", 1)
2986 }
2987 argtype(fn, l1.Type)
2988 argtype(fn, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002989 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05002990 l = list(l, nt)
2991 } else {
2992 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002993 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002994
Russ Coxdc7b54b2015-02-17 22:13:49 -05002995 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002996 nptr1 = Nod(OADDR, nptr1, nil)
2997
Russ Cox382b44e2015-02-23 16:07:24 -05002998 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002999
Russ Cox382b44e2015-02-23 16:07:24 -05003000 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003001 argtype(fn, s.Type.Type) // 1 old []any
3002 argtype(fn, s.Type.Type) // 2 ret []any
3003
Russ Cox382b44e2015-02-23 16:07:24 -05003004 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
Russ Cox8c195bd2015-02-13 14:40:36 -05003005
3006 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Russ Cox382b44e2015-02-23 16:07:24 -05003007 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
Russ Cox8c195bd2015-02-13 14:40:36 -05003008 l = list(l, nt)
3009 }
3010
3011 // s = s[:len(l1)+len(l2)]
3012 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
3013
3014 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
3015 nt.Etype = 1
3016 l = list(l, Nod(OAS, s, nt))
3017
3018 typechecklist(l, Etop)
3019 walkstmtlist(l)
3020 *init = concat(*init, l)
3021 return s
3022}
3023
3024// expand append(src, a [, b]* ) to
3025//
3026// init {
3027// s := src
3028// const argc = len(args) - 1
3029// if cap(s) - len(s) < argc {
3030// s = growslice(s, argc)
3031// }
3032// n := len(s)
3033// s = s[:n+argc]
3034// s[n] = a
3035// s[n+1] = b
3036// ...
3037// }
3038// s
3039func walkappend(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003040 walkexprlistsafe(n.List, init)
3041
3042 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
3043 // and n are name or literal, but those may index the slice we're
3044 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05003045 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003046 l.N = cheapexpr(l.N, init)
3047 }
3048
Russ Cox382b44e2015-02-23 16:07:24 -05003049 nsrc := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -05003050
3051 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003052 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003053 nsrc.Type = nsrc.Type.Type.Type
3054 }
Russ Cox382b44e2015-02-23 16:07:24 -05003055 argc := count(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003056 if argc < 1 {
3057 return nsrc
3058 }
3059
Russ Cox175929b2015-03-02 14:22:05 -05003060 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003061
Russ Cox382b44e2015-02-23 16:07:24 -05003062 ns := temp(nsrc.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003063 l = list(l, Nod(OAS, ns, nsrc)) // s = src
3064
Russ Cox382b44e2015-02-23 16:07:24 -05003065 na := Nodintconst(int64(argc)) // const argc
3066 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox8c195bd2015-02-13 14:40:36 -05003067 nx.Ntest = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
3068
Russ Cox382b44e2015-02-23 16:07:24 -05003069 fn := syslook("growslice", 1) // growslice(<type>, old []T, n int64) (ret []T)
3070 argtype(fn, ns.Type.Type) // 1 old []any
3071 argtype(fn, ns.Type.Type) // 2 ret []any
Russ Cox8c195bd2015-02-13 14:40:36 -05003072
3073 nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, conv(na, Types[TINT64]))))
3074
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 }
3123 argtype(fn, n.Left.Type)
3124 argtype(fn, n.Right.Type)
3125 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3126 }
3127
3128 walkexpr(&n.Left, init)
3129 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003130 nl := temp(n.Left.Type)
3131 nr := temp(n.Right.Type)
Russ Cox175929b2015-03-02 14:22:05 -05003132 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003133 l = list(l, Nod(OAS, nl, n.Left))
3134 l = list(l, Nod(OAS, nr, n.Right))
3135
Russ Cox382b44e2015-02-23 16:07:24 -05003136 nfrm := Nod(OSPTR, nr, nil)
3137 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003138
Russ Cox382b44e2015-02-23 16:07:24 -05003139 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003140
3141 // n = len(to)
3142 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
3143
3144 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003145 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003146
3147 nif.Ntest = Nod(OGT, nlen, Nod(OLEN, nr, nil))
3148 nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
3149 l = list(l, nif)
3150
3151 // Call memmove.
Russ Cox382b44e2015-02-23 16:07:24 -05003152 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003153
3154 argtype(fn, nl.Type.Type)
3155 argtype(fn, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003156 nwid := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -05003157 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
3158 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
3159 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
3160
3161 typechecklist(l, Etop)
3162 walkstmtlist(l)
3163 *init = concat(*init, l)
3164 return nlen
3165}
3166
3167// Generate frontend part for OSLICE[3][ARR|STR]
3168//
3169func sliceany(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003170 var hb *Node
3171 var cb *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003172
3173 // print("before sliceany: %+N\n", n);
3174
Russ Cox382b44e2015-02-23 16:07:24 -05003175 src := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003176
Russ Cox382b44e2015-02-23 16:07:24 -05003177 lb := n.Right.Left
3178 slice3 := n.Op == OSLICE3 || n.Op == OSLICE3ARR
Russ Coxdc7b54b2015-02-17 22:13:49 -05003179 if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003180 hb = n.Right.Right.Left
3181 cb = n.Right.Right.Right
3182 } else {
3183 hb = n.Right.Right
3184 cb = nil
3185 }
3186
Russ Cox382b44e2015-02-23 16:07:24 -05003187 bounded := int(n.Etype)
Russ Cox8c195bd2015-02-13 14:40:36 -05003188
Russ Cox382b44e2015-02-23 16:07:24 -05003189 var bound *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003190 if n.Op == OSLICESTR {
3191 bound = Nod(OLEN, src, nil)
3192 } else {
3193 bound = Nod(OCAP, src, nil)
3194 }
3195
3196 typecheck(&bound, Erv)
3197 walkexpr(&bound, init) // if src is an array, bound will be a const now.
3198
3199 // static checks if possible
Russ Cox382b44e2015-02-23 16:07:24 -05003200 bv := int64(1 << 50)
Russ Cox8c195bd2015-02-13 14:40:36 -05003201
Russ Coxdc7b54b2015-02-17 22:13:49 -05003202 if Isconst(bound, CTINT) {
3203 if !Smallintconst(bound) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003204 Yyerror("array len too large")
3205 } else {
3206 bv = Mpgetfix(bound.Val.U.Xval)
3207 }
3208 }
3209
Russ Coxdc7b54b2015-02-17 22:13:49 -05003210 if Isconst(cb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003211 cbv := Mpgetfix(cb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003212 if cbv < 0 || cbv > bv {
3213 Yyerror("slice index out of bounds")
3214 }
3215 }
3216
Russ Coxdc7b54b2015-02-17 22:13:49 -05003217 if Isconst(hb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003218 hbv := Mpgetfix(hb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003219 if hbv < 0 || hbv > bv {
3220 Yyerror("slice index out of bounds")
3221 }
3222 }
3223
Russ Coxdc7b54b2015-02-17 22:13:49 -05003224 if Isconst(lb, CTINT) {
Russ Cox382b44e2015-02-23 16:07:24 -05003225 lbv := Mpgetfix(lb.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05003226 if lbv < 0 || lbv > bv {
3227 Yyerror("slice index out of bounds")
3228 lbv = -1
3229 }
3230
3231 if lbv == 0 {
3232 lb = nil
3233 }
3234 }
3235
3236 // Checking src[lb:hb:cb] or src[lb:hb].
3237 // if chk0 || chk1 || chk2 { panicslice() }
Russ Cox175929b2015-03-02 14:22:05 -05003238 var chk0 *Node // cap(src) < cb
3239 var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
3240 var chk2 *Node // hb < lb
Russ Cox8c195bd2015-02-13 14:40:36 -05003241
3242 // All comparisons are unsigned to avoid testing < 0.
Russ Cox382b44e2015-02-23 16:07:24 -05003243 bt := Types[Simtype[TUINT]]
Russ Cox8c195bd2015-02-13 14:40:36 -05003244
3245 if cb != nil && cb.Type.Width > 4 {
3246 bt = Types[TUINT64]
3247 }
3248 if hb != nil && hb.Type.Width > 4 {
3249 bt = Types[TUINT64]
3250 }
3251 if lb != nil && lb.Type.Width > 4 {
3252 bt = Types[TUINT64]
3253 }
3254
3255 bound = cheapexpr(conv(bound, bt), init)
3256
3257 if cb != nil {
3258 cb = cheapexpr(conv(cb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003259 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003260 chk0 = Nod(OLT, bound, cb)
3261 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003262 } else if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003263 // When we figure out what this means, implement it.
3264 Fatal("slice3 with cb == N") // rejected by parser
3265 }
3266
3267 if hb != nil {
3268 hb = cheapexpr(conv(hb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003269 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003270 if cb != nil {
3271 chk1 = Nod(OLT, cb, hb)
3272 } else {
3273 chk1 = Nod(OLT, bound, hb)
3274 }
3275 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003276 } else if slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003277 // When we figure out what this means, implement it.
3278 Fatal("slice3 with hb == N") // rejected by parser
3279 } else if n.Op == OSLICEARR {
3280 hb = bound
3281 } else {
3282 hb = Nod(OLEN, src, nil)
3283 typecheck(&hb, Erv)
3284 walkexpr(&hb, init)
3285 hb = cheapexpr(conv(hb, bt), init)
3286 }
3287
3288 if lb != nil {
3289 lb = cheapexpr(conv(lb, bt), init)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003290 if bounded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003291 chk2 = Nod(OLT, hb, lb)
3292 }
3293 }
3294
3295 if chk0 != nil || chk1 != nil || chk2 != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003296 chk := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003297 chk.Nbody = list1(mkcall("panicslice", nil, init))
3298 chk.Likely = -1
3299 if chk0 != nil {
3300 chk.Ntest = chk0
3301 }
3302 if chk1 != nil {
3303 if chk.Ntest == nil {
3304 chk.Ntest = chk1
3305 } else {
3306 chk.Ntest = Nod(OOROR, chk.Ntest, chk1)
3307 }
3308 }
3309
3310 if chk2 != nil {
3311 if chk.Ntest == nil {
3312 chk.Ntest = chk2
3313 } else {
3314 chk.Ntest = Nod(OOROR, chk.Ntest, chk2)
3315 }
3316 }
3317
3318 typecheck(&chk, Etop)
3319 walkstmt(&chk)
3320 *init = concat(*init, chk.Ninit)
3321 chk.Ninit = nil
3322 *init = list(*init, chk)
3323 }
3324
3325 // prepare new cap, len and offs for backend cgen_slice
3326 // cap = bound [ - lo ]
3327 n.Right = nil
3328
3329 n.List = nil
Russ Coxdc7b54b2015-02-17 22:13:49 -05003330 if !slice3 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003331 cb = bound
3332 }
3333 if lb == nil {
3334 bound = conv(cb, Types[Simtype[TUINT]])
3335 } else {
3336 bound = Nod(OSUB, conv(cb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
3337 }
3338 typecheck(&bound, Erv)
3339 walkexpr(&bound, init)
3340 n.List = list(n.List, bound)
3341
3342 // len = hi [ - lo]
3343 if lb == nil {
3344 hb = conv(hb, Types[Simtype[TUINT]])
3345 } else {
3346 hb = Nod(OSUB, conv(hb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
3347 }
3348 typecheck(&hb, Erv)
3349 walkexpr(&hb, init)
3350 n.List = list(n.List, hb)
3351
3352 // offs = [width *] lo, but omit if zero
3353 if lb != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003354 var w int64
Russ Cox8c195bd2015-02-13 14:40:36 -05003355 if n.Op == OSLICESTR {
3356 w = 1
3357 } else {
3358 w = n.Type.Type.Width
3359 }
3360 lb = conv(lb, Types[TUINTPTR])
3361 if w > 1 {
3362 lb = Nod(OMUL, Nodintconst(w), lb)
3363 }
3364 typecheck(&lb, Erv)
3365 walkexpr(&lb, init)
3366 n.List = list(n.List, lb)
3367 }
3368
3369 // print("after sliceany: %+N\n", n);
3370
3371 return n
3372}
3373
3374func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003375 // Should only arrive here with large memory or
3376 // a struct/array containing a non-memory field/element.
3377 // Small memory is handled inline, and single non-memory
3378 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003379 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003380
3381 if a != AMEM && a != -1 {
3382 Fatal("eqfor %v", Tconv(t, 0))
3383 }
3384
3385 if a == AMEM {
Russ Cox382b44e2015-02-23 16:07:24 -05003386 n := syslook("memequal", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003387 argtype(n, t)
3388 argtype(n, t)
3389 *needsize = 1
3390 return n
3391 }
3392
Russ Cox382b44e2015-02-23 16:07:24 -05003393 sym := typesymprefix(".eq", t)
3394 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003395 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003396 ntype := Nod(OTFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003397 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3398 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3399 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3400 typecheck(&ntype, Etype)
3401 n.Type = ntype.Type
3402 *needsize = 0
3403 return n
3404}
3405
3406func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003407 n := 0
3408 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003409 n++
3410 }
3411 return n
3412}
3413
3414func walkcompare(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003415 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003416
3417 // Given interface value l and concrete value r, rewrite
3418 // l == r
3419 // to
3420 // x, ok := l.(type(r)); ok && x == r
3421 // Handle != similarly.
3422 // This avoids the allocation that would be required
3423 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003424 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003425
Russ Cox175929b2015-03-02 14:22:05 -05003426 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003427 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003428 l = n.Left
3429 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003430 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003431 l = n.Right
3432 r = n.Left
3433 }
3434
Russ Cox382b44e2015-02-23 16:07:24 -05003435 var call *Node
3436 var a *Node
3437 var cmpl *Node
3438 var cmpr *Node
3439 var andor int
3440 var expr *Node
3441 var needsize int
3442 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003443 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003444 x := temp(r.Type)
3445 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003446
3447 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003448 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003449
3450 a.Type = r.Type
3451
3452 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003453 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003454
3455 expr.List = list1(x)
3456 expr.List = list(expr.List, ok)
3457 expr.Rlist = list1(a)
3458 typecheck(&expr, Etop)
3459 walkexpr(&expr, init)
3460
3461 if n.Op == OEQ {
3462 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3463 } else {
3464 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3465 }
3466 *init = list(*init, expr)
3467 goto ret
3468 }
3469
3470 // Must be comparison of array or struct.
3471 // Otherwise back end handles it.
3472 t = n.Left.Type
3473
3474 switch t.Etype {
3475 default:
3476 return
3477
3478 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003479 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003480 return
3481 }
3482
3483 case TSTRUCT:
3484 break
3485 }
3486
3487 cmpl = n.Left
3488 for cmpl != nil && cmpl.Op == OCONVNOP {
3489 cmpl = cmpl.Left
3490 }
3491 cmpr = n.Right
3492 for cmpr != nil && cmpr.Op == OCONVNOP {
3493 cmpr = cmpr.Left
3494 }
3495
Russ Coxdc7b54b2015-02-17 22:13:49 -05003496 if !islvalue(cmpl) || !islvalue(cmpr) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003497 Fatal("arguments of comparison must be lvalues - %v %v", Nconv(cmpl, 0), Nconv(cmpr, 0))
3498 }
3499
3500 l = temp(Ptrto(t))
3501 a = Nod(OAS, l, Nod(OADDR, cmpl, nil))
3502 a.Right.Etype = 1 // addr does not escape
3503 typecheck(&a, Etop)
3504 *init = list(*init, a)
3505
3506 r = temp(Ptrto(t))
3507 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3508 a.Right.Etype = 1 // addr does not escape
3509 typecheck(&a, Etop)
3510 *init = list(*init, a)
3511
3512 expr = nil
3513 andor = OANDAND
3514 if n.Op == ONE {
3515 andor = OOROR
3516 }
3517
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003518 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003519 // Four or fewer elements of a basic type.
3520 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003521 var li *Node
3522 var ri *Node
3523 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003524 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3525 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
3526 a = Nod(int(n.Op), li, ri)
3527 if expr == nil {
3528 expr = a
3529 } else {
3530 expr = Nod(andor, expr, a)
3531 }
3532 }
3533
3534 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003535 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003536 }
3537 r = expr
3538 goto ret
3539 }
3540
3541 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3542 // Struct of four or fewer fields.
3543 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003544 var li *Node
3545 var ri *Node
3546 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003547 if isblanksym(t1.Sym) {
3548 continue
3549 }
3550 li = Nod(OXDOT, l, newname(t1.Sym))
3551 ri = Nod(OXDOT, r, newname(t1.Sym))
3552 a = Nod(int(n.Op), li, ri)
3553 if expr == nil {
3554 expr = a
3555 } else {
3556 expr = Nod(andor, expr, a)
3557 }
3558 }
3559
3560 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003561 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003562 }
3563 r = expr
3564 goto ret
3565 }
3566
3567 // Chose not to inline. Call equality function directly.
3568 call = Nod(OCALL, eqfor(t, &needsize), nil)
3569
3570 call.List = list(call.List, l)
3571 call.List = list(call.List, r)
3572 if needsize != 0 {
3573 call.List = list(call.List, Nodintconst(t.Width))
3574 }
3575 r = call
3576 if n.Op != OEQ {
3577 r = Nod(ONOT, r, nil)
3578 }
3579 goto ret
3580
3581ret:
3582 typecheck(&r, Erv)
3583 walkexpr(&r, init)
3584 if r.Type != n.Type {
3585 r = Nod(OCONVNOP, r, nil)
3586 r.Type = n.Type
3587 r.Typecheck = 1
3588 }
3589
3590 *np = r
3591 return
3592}
3593
Russ Coxdc7b54b2015-02-17 22:13:49 -05003594func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003595 var ar *Node
3596 var br *Node
3597 for a != nil && b != nil && a.Op == b.Op {
3598 switch a.Op {
3599 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003600 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003601
3602 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003603 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003604
3605 case ODOT,
3606 ODOTPTR:
3607 ar = a.Right
3608 br = b.Right
3609 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003610 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003611 }
3612
3613 case OINDEX:
3614 ar = a.Right
3615 br = b.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003616 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.Xval, br.Val.U.Xval) != 0 {
3617 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003618 }
3619 }
3620
3621 a = a.Left
3622 b = b.Left
3623 }
3624
Russ Coxdc7b54b2015-02-17 22:13:49 -05003625 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003626}
3627
3628func walkrotate(np **Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003629 if Thearch.Thechar == '9' {
3630 return
3631 }
3632
Russ Cox382b44e2015-02-23 16:07:24 -05003633 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003634
3635 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003636 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003637
Russ Cox382b44e2015-02-23 16:07:24 -05003638 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003639 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 -05003640 return
3641 }
3642
3643 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003644 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003645 return
3646 }
3647
3648 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003649 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003650
Russ Coxdc7b54b2015-02-17 22:13:49 -05003651 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05003652 sl := int(Mpgetfix(l.Right.Val.U.Xval))
Russ Cox8c195bd2015-02-13 14:40:36 -05003653 if sl >= 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05003654 sr := int(Mpgetfix(r.Right.Val.U.Xval))
Russ Cox8c195bd2015-02-13 14:40:36 -05003655 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003656 // Rewrite left shift half to left rotate.
3657 if l.Op == OLSH {
3658 n = l
3659 } else {
3660 n = r
3661 }
3662 n.Op = OLROT
3663
3664 // Remove rotate 0 and rotate w.
3665 s := int(Mpgetfix(n.Right.Val.U.Xval))
3666
3667 if s == 0 || s == w {
3668 n = n.Left
3669 }
3670
3671 *np = n
3672 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003673 }
3674 }
3675 return
3676 }
3677
3678 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3679 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003680}
3681
3682/*
3683 * walkmul rewrites integer multiplication by powers of two as shifts.
3684 */
3685func walkmul(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003686 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003687 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003688 return
3689 }
3690
Russ Cox382b44e2015-02-23 16:07:24 -05003691 var nr *Node
3692 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003693 if n.Right.Op == OLITERAL {
3694 nl = n.Left
3695 nr = n.Right
3696 } else if n.Left.Op == OLITERAL {
3697 nl = n.Right
3698 nr = n.Left
3699 } else {
3700 return
3701 }
3702
Russ Cox382b44e2015-02-23 16:07:24 -05003703 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003704
3705 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003706 var pow int
3707 var w int
Russ Cox8c195bd2015-02-13 14:40:36 -05003708 if Mpgetfix(nr.Val.U.Xval) == 0 {
3709 cheapexpr(nl, init)
3710 Nodconst(n, n.Type, 0)
3711 goto ret
3712 }
3713
3714 // nr is a constant.
3715 pow = powtwo(nr)
3716
3717 if pow < 0 {
3718 return
3719 }
3720 if pow >= 1000 {
3721 // negative power of 2, like -16
3722 neg = 1
3723
3724 pow -= 1000
3725 }
3726
3727 w = int(nl.Type.Width * 8)
3728 if pow+1 >= w { // too big, shouldn't happen
3729 return
3730 }
3731
3732 nl = cheapexpr(nl, init)
3733
3734 if pow == 0 {
3735 // x*1 is x
3736 n = nl
3737
3738 goto ret
3739 }
3740
3741 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3742
3743ret:
3744 if neg != 0 {
3745 n = Nod(OMINUS, n, nil)
3746 }
3747
3748 typecheck(&n, Erv)
3749 walkexpr(&n, init)
3750 *np = n
3751}
3752
3753/*
3754 * walkdiv rewrites division by a constant as less expensive
3755 * operations.
3756 */
3757func walkdiv(np **Node, init **NodeList) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003758 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003759
3760 // TODO(minux)
3761 if Thearch.Thechar == '9' {
3762 return
3763 }
3764
Russ Cox382b44e2015-02-23 16:07:24 -05003765 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003766 if n.Right.Op != OLITERAL {
3767 return
3768 }
3769
3770 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003771 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003772
Russ Cox382b44e2015-02-23 16:07:24 -05003773 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003774
3775 // special cases of mod/div
3776 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003777 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003778
Russ Cox382b44e2015-02-23 16:07:24 -05003779 s := 0
3780 pow := powtwo(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003781 if pow >= 1000 {
3782 // negative power of 2
3783 s = 1
3784
3785 pow -= 1000
3786 }
3787
3788 if pow+1 >= w {
3789 // divisor too large.
3790 return
3791 }
3792
3793 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003794 // try to do division by multiply by (2^w)/d
3795 // see hacker's delight chapter 10
3796 // TODO: support 64-bit magic multiply here.
3797 var m Magic
3798 m.W = w
3799
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003800 if Issigned[nl.Type.Etype] {
Russ Cox79f727a2015-03-02 12:35:15 -05003801 m.Sd = Mpgetfix(nr.Val.U.Xval)
3802 Smagic(&m)
3803 } else {
3804 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
3805 Umagic(&m)
3806 }
3807
3808 if m.Bad != 0 {
3809 return
3810 }
3811
3812 // We have a quick division method so use it
3813 // for modulo too.
3814 if n.Op == OMOD {
3815 // rewrite as A%B = A - (A/B*B).
3816 n1 := Nod(ODIV, nl, nr)
3817
3818 n2 := Nod(OMUL, n1, nr)
3819 n = Nod(OSUB, nl, n2)
3820 goto ret
3821 }
3822
3823 switch Simtype[nl.Type.Etype] {
3824 default:
3825 return
3826
3827 // n1 = nl * magic >> w (HMUL)
3828 case TUINT8,
3829 TUINT16,
3830 TUINT32:
3831 nc := Nod(OXXX, nil, nil)
3832
3833 Nodconst(nc, nl.Type, int64(m.Um))
3834 n1 := Nod(OMUL, nl, nc)
3835 typecheck(&n1, Erv)
3836 n1.Op = OHMUL
3837 if m.Ua != 0 {
3838 // Select a Go type with (at least) twice the width.
3839 var twide *Type
3840 switch Simtype[nl.Type.Etype] {
3841 default:
3842 return
3843
3844 case TUINT8,
3845 TUINT16:
3846 twide = Types[TUINT32]
3847
3848 case TUINT32:
3849 twide = Types[TUINT64]
3850
3851 case TINT8,
3852 TINT16:
3853 twide = Types[TINT32]
3854
3855 case TINT32:
3856 twide = Types[TINT64]
3857 }
3858
3859 // add numerator (might overflow).
3860 // n2 = (n1 + nl)
3861 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3862
3863 // shift by m.s
3864 nc := Nod(OXXX, nil, nil)
3865
3866 Nodconst(nc, Types[TUINT], int64(m.S))
3867 n = conv(Nod(ORSH, n2, nc), nl.Type)
3868 } else {
3869 // n = n1 >> m.s
3870 nc := Nod(OXXX, nil, nil)
3871
3872 Nodconst(nc, Types[TUINT], int64(m.S))
3873 n = Nod(ORSH, n1, nc)
3874 }
3875
3876 // n1 = nl * magic >> w
3877 case TINT8,
3878 TINT16,
3879 TINT32:
3880 nc := Nod(OXXX, nil, nil)
3881
3882 Nodconst(nc, nl.Type, m.Sm)
3883 n1 := Nod(OMUL, nl, nc)
3884 typecheck(&n1, Erv)
3885 n1.Op = OHMUL
3886 if m.Sm < 0 {
3887 // add the numerator.
3888 n1 = Nod(OADD, n1, nl)
3889 }
3890
3891 // shift by m.s
3892 nc = Nod(OXXX, nil, nil)
3893
3894 Nodconst(nc, Types[TUINT], int64(m.S))
3895 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3896
3897 // add 1 iff n1 is negative.
3898 nc = Nod(OXXX, nil, nil)
3899
3900 Nodconst(nc, Types[TUINT], int64(w)-1)
3901 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3902 n = Nod(OSUB, n2, n3)
3903
3904 // apply sign.
3905 if m.Sd < 0 {
3906 n = Nod(OMINUS, n, nil)
3907 }
3908 }
3909
3910 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003911 }
3912
3913 switch pow {
3914 case 0:
3915 if n.Op == OMOD {
3916 // nl % 1 is zero.
3917 Nodconst(n, n.Type, 0)
3918 } else if s != 0 {
3919 // divide by -1
3920 n.Op = OMINUS
3921
3922 n.Right = nil
3923 } else {
3924 // divide by 1
3925 n = nl
3926 }
3927
3928 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003929 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003930 if n.Op == OMOD {
3931 // signed modulo 2^pow is like ANDing
3932 // with the last pow bits, but if nl < 0,
3933 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003934 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003935
3936 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003937 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003938 if pow == 1 {
3939 typecheck(&n1, Erv)
3940 n1 = cheapexpr(n1, init)
3941
3942 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003943 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003944
Russ Cox382b44e2015-02-23 16:07:24 -05003945 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003946 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003947 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003948 n = Nod(OADD, n3, n1)
3949 } else {
3950 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003951 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003952
3953 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003954 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003955 typecheck(&n2, Erv)
3956 n2 = cheapexpr(n2, init)
3957
Russ Cox382b44e2015-02-23 16:07:24 -05003958 n3 := Nod(OADD, nl, n2)
3959 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003960 n = Nod(OSUB, n4, n2)
3961 }
3962
3963 break
3964 } else {
3965 // arithmetic right shift does not give the correct rounding.
3966 // if nl >= 0, nl >> n == nl / nr
3967 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003968 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003969
3970 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003971 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003972 if pow == 1 {
3973 // nl+1 is nl-(-1)
3974 n.Left = Nod(OSUB, nl, n1)
3975 } else {
3976 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003977 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003978
3979 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003980 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003981 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3982 }
3983
3984 // n = (nl + 2^pow-1) >> pow
3985 n.Op = ORSH
3986
3987 nc = Nod(OXXX, nil, nil)
3988 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3989 n.Right = nc
3990 n.Typecheck = 0
3991 }
3992
3993 if s != 0 {
3994 n = Nod(OMINUS, n, nil)
3995 }
3996 break
3997 }
3998
Russ Cox382b44e2015-02-23 16:07:24 -05003999 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004000 if n.Op == OMOD {
4001 // n = nl & (nr-1)
4002 n.Op = OAND
4003
4004 Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.Xval)-1)
4005 } else {
4006 // n = nl >> pow
4007 n.Op = ORSH
4008
4009 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
4010 }
4011
4012 n.Typecheck = 0
4013 n.Right = nc
4014 }
4015
4016 goto ret
4017
Russ Cox8c195bd2015-02-13 14:40:36 -05004018ret:
4019 typecheck(&n, Erv)
4020 walkexpr(&n, init)
4021 *np = n
4022}
4023
4024// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05004025func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004026 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004027 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004028 }
4029
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004030 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05004031 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05004032
Russ Coxdc7b54b2015-02-17 22:13:49 -05004033 if Smallintconst(n) {
Russ Cox382b44e2015-02-23 16:07:24 -05004034 v := Mpgetfix(n.Val.U.Xval)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004035 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05004036 }
4037
4038 switch n.Op {
4039 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05004040 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004041 if Smallintconst(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05004042 v = Mpgetfix(n.Left.Val.U.Xval)
Russ Coxdc7b54b2015-02-17 22:13:49 -05004043 } else if Smallintconst(n.Right) {
Russ Cox8c195bd2015-02-13 14:40:36 -05004044 v = Mpgetfix(n.Right.Val.U.Xval)
4045 }
4046
4047 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004048 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004049 }
4050
4051 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004052 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004053 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004054 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004055 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004056 }
4057 }
4058
4059 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004060 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004061 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004062 for bits > 0 && v >= 2 {
4063 bits--
4064 v >>= 1
4065 }
4066 }
4067
4068 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004069 if !sign && Smallintconst(n.Right) {
Russ Cox382b44e2015-02-23 16:07:24 -05004070 v := Mpgetfix(n.Right.Val.U.Xval)
Russ Cox8c195bd2015-02-13 14:40:36 -05004071 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004072 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004073 }
4074 bits -= int32(v)
4075 }
4076 }
4077
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004078 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004079 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004080 }
4081
Russ Coxdc7b54b2015-02-17 22:13:49 -05004082 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004083}
4084
4085func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004086 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004087 return
4088 }
4089
4090 switch n.Op {
4091 default:
4092 Fatal("usefield %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05004093
4094 case ODOT,
4095 ODOTPTR:
4096 break
4097 }
4098
Russ Cox382b44e2015-02-23 16:07:24 -05004099 field := n.Paramfld
Russ Cox8c195bd2015-02-13 14:40:36 -05004100 if field == nil {
4101 Fatal("usefield %v %v without paramfld", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
4102 }
4103 if field.Note == nil || !strings.Contains(field.Note.S, "go:\"track\"") {
4104 return
4105 }
4106
4107 // dedup on list
4108 if field.Lastfn == Curfn {
4109 return
4110 }
4111 field.Lastfn = Curfn
4112 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00004113 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05004114 field.Outer = field.Outer.Type
4115 }
4116 if field.Outer.Sym == nil {
4117 Yyerror("tracked field must be in named struct type")
4118 }
4119 if !exportname(field.Sym.Name) {
4120 Yyerror("tracked field must be exported (upper case)")
4121 }
4122
Russ Cox382b44e2015-02-23 16:07:24 -05004123 l := typ(0)
Russ Cox8c195bd2015-02-13 14:40:36 -05004124 l.Type = field
4125 l.Down = Curfn.Paramfld
4126 Curfn.Paramfld = l
4127}
4128
Russ Coxdc7b54b2015-02-17 22:13:49 -05004129func candiscardlist(l *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004130 for ; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004131 if !candiscard(l.N) {
4132 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004133 }
4134 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004135 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004136}
4137
Russ Coxdc7b54b2015-02-17 22:13:49 -05004138func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004139 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004140 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004141 }
4142
4143 switch n.Op {
4144 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004145 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004146
4147 // Discardable as long as the subpieces are.
4148 case ONAME,
4149 ONONAME,
4150 OTYPE,
4151 OPACK,
4152 OLITERAL,
4153 OADD,
4154 OSUB,
4155 OOR,
4156 OXOR,
4157 OADDSTR,
4158 OADDR,
4159 OANDAND,
4160 OARRAYBYTESTR,
4161 OARRAYRUNESTR,
4162 OSTRARRAYBYTE,
4163 OSTRARRAYRUNE,
4164 OCAP,
4165 OCMPIFACE,
4166 OCMPSTR,
4167 OCOMPLIT,
4168 OMAPLIT,
4169 OSTRUCTLIT,
4170 OARRAYLIT,
4171 OPTRLIT,
4172 OCONV,
4173 OCONVIFACE,
4174 OCONVNOP,
4175 ODOT,
4176 OEQ,
4177 ONE,
4178 OLT,
4179 OLE,
4180 OGT,
4181 OGE,
4182 OKEY,
4183 OLEN,
4184 OMUL,
4185 OLSH,
4186 ORSH,
4187 OAND,
4188 OANDNOT,
4189 ONEW,
4190 ONOT,
4191 OCOM,
4192 OPLUS,
4193 OMINUS,
4194 OOROR,
4195 OPAREN,
4196 ORUNESTR,
4197 OREAL,
4198 OIMAG,
4199 OCOMPLEX:
4200 break
4201
4202 // Discardable as long as we know it's not division by zero.
4203 case ODIV,
4204 OMOD:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004205 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004206 break
4207 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004208 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.Fval, 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004209 break
4210 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004211 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004212
4213 // Discardable as long as we know it won't fail because of a bad size.
4214 case OMAKECHAN,
4215 OMAKEMAP:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004216 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004217 break
4218 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004219 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004220
4221 // Difficult to tell what sizes are okay.
4222 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004223 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004224 }
4225
Russ Coxdc7b54b2015-02-17 22:13:49 -05004226 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) {
4227 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004228 }
4229
Russ Coxdc7b54b2015-02-17 22:13:49 -05004230 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004231}
4232
4233// rewrite
4234// print(x, y, z)
4235// into
4236// func(a1, a2, a3) {
4237// print(a1, a2, a3)
4238// }(x, y, z)
4239// and same for println.
4240
4241var walkprintfunc_prgen int
4242
4243func walkprintfunc(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05004244 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05004245
4246 if n.Ninit != nil {
4247 walkstmtlist(n.Ninit)
4248 *init = concat(*init, n.Ninit)
4249 n.Ninit = nil
4250 }
4251
Russ Cox382b44e2015-02-23 16:07:24 -05004252 t := Nod(OTFUNC, nil, nil)
4253 num := 0
Russ Cox175929b2015-03-02 14:22:05 -05004254 var printargs *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05004255 var a *Node
4256 var buf string
4257 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05004258 buf = fmt.Sprintf("a%d", num)
4259 num++
4260 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
4261 t.List = list(t.List, a)
4262 printargs = list(printargs, a.Left)
4263 }
4264
Russ Cox382b44e2015-02-23 16:07:24 -05004265 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004266 walkprintfunc_prgen++
4267 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
4268 fn.Nname = newname(Lookup(buf))
4269 fn.Nname.Defn = fn
4270 fn.Nname.Ntype = t
4271 declare(fn.Nname, PFUNC)
4272
Russ Cox382b44e2015-02-23 16:07:24 -05004273 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004274 Curfn = nil
4275 funchdr(fn)
4276
4277 a = Nod(int(n.Op), nil, nil)
4278 a.List = printargs
4279 typecheck(&a, Etop)
4280 walkstmt(&a)
4281
4282 fn.Nbody = list1(a)
4283
4284 funcbody(fn)
4285
4286 typecheck(&fn, Etop)
4287 typechecklist(fn.Nbody, Etop)
4288 xtop = list(xtop, fn)
4289 Curfn = oldfn
4290
4291 a = Nod(OCALL, nil, nil)
4292 a.Left = fn.Nname
4293 a.List = n.List
4294 typecheck(&a, Etop)
4295 walkexpr(&a, init)
4296 *np = a
4297}