blob: f5ae9fbe21559ba140431b4bd3fb37de68f099a5 [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 Coxbd4fff62015-05-27 10:42:55 -040024 s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050025 dumplist(s, Curfn.Nbody)
26 }
27
Russ Cox382b44e2015-02-23 16:07:24 -050028 lno := int(lineno)
Russ Cox8c195bd2015-02-13 14:40:36 -050029
30 // Final typecheck for any unused variables.
31 // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070032 for l := fn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050033 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
34 typecheck(&l.N, Erv|Easgn)
35 }
36 }
37
38 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070039 for l := fn.Func.Dcl; l != nil; l = l.Next {
Russ Cox4fdd5362015-05-26 22:19:27 -040040 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used {
41 l.N.Name.Defn.Left.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -050042 }
43 }
44
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070045 for l := fn.Func.Dcl; l != nil; l = l.Next {
Dave Cheney44e90312015-03-06 21:18:41 +110046 if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050047 continue
48 }
Russ Cox4fdd5362015-05-26 22:19:27 -040049 if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
50 if defn.Left.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050051 continue
52 }
Russ Cox4fdd5362015-05-26 22:19:27 -040053 lineno = defn.Left.Lineno
Russ Cox17228f42015-04-17 12:03:22 -040054 Yyerror("%v declared and not used", l.N.Sym)
Russ Cox4fdd5362015-05-26 22:19:27 -040055 defn.Left.Used = true // suppress repeats
Russ Cox8c195bd2015-02-13 14:40:36 -050056 } else {
57 lineno = l.N.Lineno
Russ Cox17228f42015-04-17 12:03:22 -040058 Yyerror("%v declared and not used", l.N.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050059 }
60 }
61
62 lineno = int32(lno)
63 if nerrors != 0 {
64 return
65 }
66 walkstmtlist(Curfn.Nbody)
67 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040068 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050069 dumplist(s, Curfn.Nbody)
70 }
71
72 heapmoves()
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070073 if Debug['W'] != 0 && Curfn.Func.Enter != nil {
Russ Coxbd4fff62015-05-27 10:42:55 -040074 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070075 dumplist(s, Curfn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050076 }
77}
78
79func walkstmtlist(l *NodeList) {
80 for ; l != nil; l = l.Next {
81 walkstmt(&l.N)
82 }
83}
84
Russ Coxdc7b54b2015-02-17 22:13:49 -050085func samelist(a *NodeList, b *NodeList) bool {
Russ Coxd7f6d462015-03-09 00:31:13 -040086 for ; a != nil && b != nil; a, b = a.Next, b.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050087 if a.N != b.N {
Russ Coxdc7b54b2015-02-17 22:13:49 -050088 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050089 }
90 }
Russ Coxdc7b54b2015-02-17 22:13:49 -050091 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -050092}
93
Dave Cheneyb006d382015-03-06 18:42:58 +110094func paramoutheap(fn *Node) bool {
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070095 for l := fn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050096 switch l.N.Class {
97 case PPARAMOUT,
98 PPARAMOUT | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +110099 return l.N.Addrtaken
Russ Cox8c195bd2015-02-13 14:40:36 -0500100
101 // stop early - parameters are over
102 case PAUTO,
103 PAUTO | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +1100104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500105 }
106 }
107
Dave Cheneyb006d382015-03-06 18:42:58 +1100108 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500109}
110
111// adds "adjust" to all the argument locations for the call n.
112// n must be a defer or go node that has already been walked.
113func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500114 var arg *Node
115 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500116
Russ Cox382b44e2015-02-23 16:07:24 -0500117 callfunc := n.Left
118 for args := callfunc.List; args != nil; args = args.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500119 arg = args.N
120 if arg.Op != OAS {
121 Yyerror("call arg not assignment")
122 }
123 lhs = arg.Left
124 if lhs.Op == ONAME {
125 // This is a temporary introduced by reorder1.
126 // The real store to the stack appears later in the arg list.
127 continue
128 }
129
130 if lhs.Op != OINDREG {
131 Yyerror("call argument store does not use OINDREG")
132 }
133
134 // can't really check this in machine-indep code.
135 //if(lhs->val.u.reg != D_SP)
136 // yyerror("call arg assign not indreg(SP)");
137 lhs.Xoffset += int64(adjust)
138 }
139}
140
141func walkstmt(np **Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500142 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500143 if n == nil {
144 return
145 }
146 if n.Dodata == 2 { // don't walk, generated by anylit.
147 return
148 }
149
150 setlineno(n)
151
152 walkstmtlist(n.Ninit)
153
154 switch n.Op {
155 default:
156 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400157 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500158 } 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,
Russ Cox92c826b2015-04-03 12:23:28 -0400182 ORECOVER,
183 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500184 if n.Typecheck == 0 {
185 Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
186 }
Russ Cox382b44e2015-02-23 16:07:24 -0500187 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500188 n.Ninit = nil
189 walkexpr(&n, &init)
190 addinit(&n, init)
191 if (*np).Op == OCOPY && n.Op == OCONVNOP {
192 n.Op = OEMPTY // don't leave plain values as statements.
193 }
194
195 // special case for a receive where we throw away
196 // the value received.
197 case ORECV:
198 if n.Typecheck == 0 {
199 Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
200 }
Russ Cox382b44e2015-02-23 16:07:24 -0500201 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500202 n.Ninit = nil
203
204 walkexpr(&n.Left, &init)
205 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
206 walkexpr(&n, &init)
207
208 addinit(&n, init)
209
210 case OBREAK,
211 ODCL,
212 OCONTINUE,
213 OFALL,
214 OGOTO,
215 OLABEL,
216 ODCLCONST,
217 ODCLTYPE,
218 OCHECKNIL,
219 OVARKILL:
220 break
221
222 case OBLOCK:
223 walkstmtlist(n.List)
224
225 case OXCASE:
226 Yyerror("case statement out of place")
227 n.Op = OCASE
228 fallthrough
229
230 case OCASE:
231 walkstmt(&n.Right)
232
233 case ODEFER:
234 Hasdefer = 1
235 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700236 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500237 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:
Russ Cox66be1482015-05-26 21:30:20 -0400250 if n.Left != nil {
251 walkstmtlist(n.Left.Ninit)
252 init := n.Left.Ninit
253 n.Left.Ninit = nil
254 walkexpr(&n.Left, &init)
255 addinit(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500256 }
257
Russ Coxffef1802015-05-22 01:16:52 -0400258 walkstmt(&n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500259 walkstmtlist(n.Nbody)
260
261 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400262 walkexpr(&n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500263 walkstmtlist(n.Nbody)
Russ Coxffef1802015-05-22 01:16:52 -0400264 walkstmtlist(n.Rlist)
Russ Cox8c195bd2015-02-13 14:40:36 -0500265
266 case OPROC:
267 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700268 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500269 walkprintfunc(&n.Left, &n.Ninit)
270
271 case OCOPY:
272 n.Left = copyany(n.Left, &n.Ninit, 1)
273
274 default:
275 walkexpr(&n.Left, &n.Ninit)
276 }
277
278 // make room for size & fn arguments.
279 adjustargs(n, 2*Widthptr)
280
281 case ORETURN:
282 walkexprlist(n.List, &n.Ninit)
283 if n.List == nil {
284 break
285 }
Dave Cheneyb006d382015-03-06 18:42:58 +1100286 if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500287 // assign to the function out parameters,
288 // so that reorder3 can fix up conflicts
Russ Cox175929b2015-03-02 14:22:05 -0500289 var rl *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500290
Josh Bleecher Snyder102b8062015-03-27 12:00:07 -0700291 var cl uint8
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700292 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
Josh Bleecher Snyder102b8062015-03-27 12:00:07 -0700293 cl = ll.N.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500294 if cl == PAUTO {
295 break
296 }
297 if cl == PPARAMOUT {
298 rl = list(rl, ll.N)
299 }
300 }
301
Russ Coxdc7b54b2015-02-17 22:13:49 -0500302 if samelist(rl, n.List) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500303 // special return in disguise
304 n.List = nil
305
306 break
307 }
308
309 if count(n.List) == 1 && count(rl) > 1 {
310 // OAS2FUNC in disguise
Russ Cox382b44e2015-02-23 16:07:24 -0500311 f := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500312
313 if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
Russ Cox17228f42015-04-17 12:03:22 -0400314 Fatal("expected return of call, have %v", f)
Russ Cox8c195bd2015-02-13 14:40:36 -0500315 }
316 n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
317 break
318 }
319
320 // move function calls out, to make reorder3's job easier.
321 walkexprlistsafe(n.List, &n.Ninit)
322
Russ Cox382b44e2015-02-23 16:07:24 -0500323 ll := ascompatee(int(n.Op), rl, n.List, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500324 n.List = reorder3(ll)
325 break
326 }
327
Dave Cheneyd3287562015-03-09 16:24:07 +1100328 ll := ascompatte(int(n.Op), nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500329 n.List = ll
330
331 case ORETJMP:
332 break
333
334 case OSELECT:
335 walkselect(n)
336
337 case OSWITCH:
338 walkswitch(n)
339
340 case ORANGE:
341 walkrange(n)
342
343 case OXFALL:
344 Yyerror("fallthrough statement out of place")
345 n.Op = OFALL
346 }
347
348 if n.Op == ONAME {
349 Fatal("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
350 }
351
352 *np = n
353}
354
David Chasee5060c72015-05-20 15:16:34 -0400355func isSmallMakeSlice(n *Node) bool {
356 if n.Op != OMAKESLICE {
357 return false
358 }
359 l := n.Left
360 r := n.Right
361 if r == nil {
362 r = l
363 }
364 t := n.Type
365
Russ Cox81d58102015-05-27 00:47:05 -0400366 return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val().U.(*Mpint)) < (1<<16)/t.Type.Width)
David Chasee5060c72015-05-20 15:16:34 -0400367}
368
Russ Cox8c195bd2015-02-13 14:40:36 -0500369/*
370 * walk the whole tree of the body of an
371 * expression or simple statement.
372 * the types expressions are calculated.
373 * compile-time constants are evaluated.
374 * complex side effects like statements are appended to init
375 */
376func walkexprlist(l *NodeList, init **NodeList) {
377 for ; l != nil; l = l.Next {
378 walkexpr(&l.N, init)
379 }
380}
381
382func walkexprlistsafe(l *NodeList, init **NodeList) {
383 for ; l != nil; l = l.Next {
384 l.N = safeexpr(l.N, init)
385 walkexpr(&l.N, init)
386 }
387}
388
389func walkexprlistcheap(l *NodeList, init **NodeList) {
390 for ; l != nil; l = l.Next {
391 l.N = cheapexpr(l.N, init)
392 walkexpr(&l.N, init)
393 }
394}
395
396func walkexpr(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -0500397 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500398
399 if n == nil {
400 return
401 }
402
403 if init == &n.Ninit {
404 // not okay to use n->ninit when walking n,
405 // because we might replace n with some other node
406 // and would lose the init list.
407 Fatal("walkexpr init == &n->ninit")
408 }
409
410 if n.Ninit != nil {
411 walkstmtlist(n.Ninit)
412 *init = concat(*init, n.Ninit)
413 n.Ninit = nil
414 }
415
416 // annoying case - not typechecked
417 if n.Op == OKEY {
418 walkexpr(&n.Left, init)
419 walkexpr(&n.Right, init)
420 return
421 }
422
Russ Cox382b44e2015-02-23 16:07:24 -0500423 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500424
425 if Debug['w'] > 1 {
426 Dump("walk-before", n)
427 }
428
429 if n.Typecheck != 1 {
430 Fatal("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
431 }
432
433 switch n.Op {
434 default:
435 Dump("walk", n)
436 Fatal("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
437
438 case OTYPE,
439 ONONAME,
440 OINDREG,
441 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400442 OPARAM,
443 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500444 goto ret
445
446 case ONOT,
447 OMINUS,
448 OPLUS,
449 OCOM,
450 OREAL,
451 OIMAG,
452 ODOTMETH,
453 ODOTINTER:
454 walkexpr(&n.Left, init)
455 goto ret
456
457 case OIND:
458 walkexpr(&n.Left, init)
459 goto ret
460
461 case ODOT:
462 usefield(n)
463 walkexpr(&n.Left, init)
464 goto ret
465
466 case ODOTPTR:
467 usefield(n)
468 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
469 // No actual copy will be generated, so emit an explicit nil check.
470 n.Left = cheapexpr(n.Left, init)
471
472 checknil(n.Left, init)
473 }
474
475 walkexpr(&n.Left, init)
476 goto ret
477
478 case OEFACE:
479 walkexpr(&n.Left, init)
480 walkexpr(&n.Right, init)
481 goto ret
482
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700483 case OSPTR, OITAB:
Russ Cox8c195bd2015-02-13 14:40:36 -0500484 walkexpr(&n.Left, init)
485 goto ret
486
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700487 case OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500488 walkexpr(&n.Left, init)
489
490 // replace len(*[10]int) with 10.
491 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500492 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500493
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000494 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500495 t = t.Type
496 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500497 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500498 safeexpr(n.Left, init)
499 Nodconst(n, n.Type, t.Bound)
500 n.Typecheck = 1
501 }
502
503 goto ret
504
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700505 case OLSH, ORSH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500506 walkexpr(&n.Left, init)
507 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500508 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500509 n.Bounded = bounded(n.Right, 8*t.Width)
510 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500511 Warn("shift bounds check elided")
512 }
513 goto ret
514
515 // Use results from call expression as arguments for complex.
516 case OAND,
517 OSUB,
518 OHMUL,
519 OLT,
520 OLE,
521 OGE,
522 OGT,
523 OADD,
524 OCOMPLEX,
525 OLROT:
526 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
527 n.Left = n.List.N
528 n.Right = n.List.Next.N
529 }
530
531 walkexpr(&n.Left, init)
532 walkexpr(&n.Right, init)
533 goto ret
534
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700535 case OOR, OXOR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500536 walkexpr(&n.Left, init)
537 walkexpr(&n.Right, init)
538 walkrotate(&n)
539 goto ret
540
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700541 case OEQ, ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500542 walkexpr(&n.Left, init)
543 walkexpr(&n.Right, init)
544
545 // Disable safemode while compiling this code: the code we
546 // generate internally can refer to unsafe.Pointer.
547 // In this case it can happen if we need to generate an ==
548 // for a struct containing a reflect.Value, which itself has
549 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500550 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500551
552 safemode = 0
553 walkcompare(&n, init)
554 safemode = old_safemode
555 goto ret
556
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700557 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500558 walkexpr(&n.Left, init)
559
David Chaseffe7fbf2015-03-27 12:34:45 -0400560 // cannot put side effects from n.Right on init,
561 // because they cannot run before n.Left is checked.
562 // save elsewhere and store on the eventual n.Right.
Russ Cox175929b2015-03-02 14:22:05 -0500563 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500564
565 walkexpr(&n.Right, &ll)
566 addinit(&n.Right, ll)
567 goto ret
568
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700569 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500570 walkexprlist(n.List, init)
571 n = walkprint(n, init)
572 goto ret
573
574 case OPANIC:
575 n = mkcall("gopanic", nil, init, n.Left)
576 goto ret
577
578 case ORECOVER:
579 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
580 goto ret
581
582 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700583 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500584 goto ret
585
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700586 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700587 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500588 goto ret
589
590 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500591 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700592 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500593 }
594 goto ret
595
596 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500597 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500598 if n.List != nil && n.List.N.Op == OAS {
599 goto ret
600 }
601 walkexpr(&n.Left, init)
602 walkexprlist(n.List, init)
Dave Cheneyd3287562015-03-09 16:24:07 +1100603 ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500604 n.List = reorder1(ll)
605 goto ret
606
607 case OCALLFUNC:
608 if n.Left.Op == OCLOSURE {
609 // Transform direct call of a closure to call of a normal function.
610 // transformclosure already did all preparation work.
611
612 // Append captured variables to argument list.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700613 n.List = concat(n.List, n.Left.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -0500614
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700615 n.Left.Func.Enter = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500616
617 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400618 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500619
620 // Update type of OCALLFUNC node.
621 // Output arguments had not changed, but their offsets could.
622 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500623 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500624 if t.Etype == TFIELD {
625 t = t.Type
626 }
627 n.Type = t
628 } else {
629 n.Type = getoutargx(n.Left.Type)
630 }
631 }
632
Russ Cox382b44e2015-02-23 16:07:24 -0500633 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500634 if n.List != nil && n.List.N.Op == OAS {
635 goto ret
636 }
637
638 walkexpr(&n.Left, init)
639 walkexprlist(n.List, init)
640
Russ Cox92dba0d2015-04-01 16:02:34 -0400641 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
642 switch Thearch.Thechar {
Shenghou Ma764c7512015-04-03 18:15:26 -0400643 case '5', '6', '7':
Russ Cox92dba0d2015-04-01 16:02:34 -0400644 n.Op = OSQRT
645 n.Left = n.List.N
646 n.List = nil
647 goto ret
648 }
649 }
650
Dave Cheneyd3287562015-03-09 16:24:07 +1100651 ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500652 n.List = reorder1(ll)
653 goto ret
654
655 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500656 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500657 if n.List != nil && n.List.N.Op == OAS {
658 goto ret
659 }
660 walkexpr(&n.Left, init)
661 walkexprlist(n.List, init)
Dave Cheneyd3287562015-03-09 16:24:07 +1100662 ll := ascompatte(int(n.Op), n, false, getthis(t), list1(n.Left.Left), 0, init)
663 lr := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500664 ll = concat(ll, lr)
665 n.Left.Left = nil
666 ullmancalc(n.Left)
667 n.List = reorder1(ll)
668 goto ret
669
670 case OAS:
671 *init = concat(*init, n.Ninit)
672 n.Ninit = nil
673
674 walkexpr(&n.Left, init)
675 n.Left = safeexpr(n.Left, init)
676
Russ Coxdc7b54b2015-02-17 22:13:49 -0500677 if oaslit(n, init) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500678 goto ret
679 }
680
Russ Coxdc7b54b2015-02-17 22:13:49 -0500681 if n.Right == nil || iszero(n.Right) && flag_race == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500682 goto ret
683 }
684
685 switch n.Right.Op {
686 default:
687 walkexpr(&n.Right, init)
688
Russ Cox8c195bd2015-02-13 14:40:36 -0500689 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400690 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
691 // It needs to be removed in all three places.
692 // That would allow inlining x.(struct{*int}) the same as x.(*int).
693 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && flag_race == 0 {
694 // handled directly during cgen
695 walkexpr(&n.Right, init)
696 break
697 }
698
David Chaseffe7fbf2015-03-27 12:34:45 -0400699 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400700 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500701 walkexpr(&n.Right.Left, init)
702
Russ Cox382b44e2015-02-23 16:07:24 -0500703 n1 := Nod(OADDR, n.Left, nil)
704 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500705
Russ Cox4224d812015-03-20 00:06:10 -0400706 if Debug_typeassert > 0 {
707 Warn("type assertion not inlined")
708 }
709
Russ Cox01af7272015-03-19 23:38:24 +0000710 buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
Russ Cox382b44e2015-02-23 16:07:24 -0500711 fn := syslook(buf, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400712 substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500713
714 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
715 walkexpr(&n, init)
716 goto ret
717
Russ Cox8c195bd2015-02-13 14:40:36 -0500718 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400719 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400720 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500721 walkexpr(&n.Right.Left, init)
722
Russ Cox382b44e2015-02-23 16:07:24 -0500723 n1 := Nod(OADDR, n.Left, nil)
724 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500725 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
726 walkexpr(&n, init)
727 goto ret
Russ Cox85520472015-05-06 12:34:30 -0400728
729 case OAPPEND:
730 // x = append(...)
731 r := n.Right
732 if r.Isddd {
733 r = appendslice(r, init) // also works for append(slice, string).
734 } else {
735 r = walkappend(r, init, n)
736 }
737 n.Right = r
738 if r.Op == OAPPEND {
739 // Left in place for back end.
740 // Do not add a new write barrier.
741 goto ret
742 }
743 // Otherwise, lowered for race detector.
744 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500745 }
746
747 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500748 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500749 r.Dodata = n.Dodata
750 n = r
751 n = applywritebarrier(n, init)
752 }
753
754 goto ret
755
756 case OAS2:
757 *init = concat(*init, n.Ninit)
758 n.Ninit = nil
759 walkexprlistsafe(n.List, init)
760 walkexprlistsafe(n.Rlist, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500761 ll := ascompatee(OAS, n.List, n.Rlist, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500762 ll = reorder3(ll)
Russ Cox382b44e2015-02-23 16:07:24 -0500763 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500764 lr.N = applywritebarrier(lr.N, init)
765 }
766 n = liststmt(ll)
767 goto ret
768
769 // a,b,... = fn()
770 case OAS2FUNC:
771 *init = concat(*init, n.Ninit)
772
773 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500774 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500775 walkexprlistsafe(n.List, init)
776 walkexpr(&r, init)
777
Russ Cox382b44e2015-02-23 16:07:24 -0500778 ll := ascompatet(int(n.Op), n.List, &r.Type, 0, init)
779 for lr := ll; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500780 lr.N = applywritebarrier(lr.N, init)
781 }
782 n = liststmt(concat(list1(r), ll))
783 goto ret
784
785 // x, y = <-c
786 // orderstmt made sure x is addressable.
787 case OAS2RECV:
788 *init = concat(*init, n.Ninit)
789
790 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500791 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500792 walkexprlistsafe(n.List, init)
793 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500794 var n1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 if isblank(n.List.N) {
796 n1 = nodnil()
797 } else {
798 n1 = Nod(OADDR, n.List.N, nil)
799 }
800 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500801 fn := chanfn("chanrecv2", 2, r.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500802 r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
803 n = Nod(OAS, n.List.Next.N, r)
804 typecheck(&n, Etop)
805 goto ret
806
807 // a,b = m[i];
808 case OAS2MAPR:
809 *init = concat(*init, n.Ninit)
810
811 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500812 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500813 walkexprlistsafe(n.List, init)
814 walkexpr(&r.Left, init)
815 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500816 t := r.Left.Type
817 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500818 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
819 switch Simsimtype(t.Down) {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700820 case TINT32, TUINT32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500821 p = "mapaccess2_fast32"
822
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700823 case TINT64, TUINT64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500824 p = "mapaccess2_fast64"
825
826 case TSTRING:
827 p = "mapaccess2_faststr"
828 }
829 }
830
Russ Cox382b44e2015-02-23 16:07:24 -0500831 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500832 if p != "" {
833 // fast versions take key by value
834 key = r.Right
835 } else {
836 // standard version takes key by reference
837 // orderexpr made sure key is addressable.
838 key = Nod(OADDR, r.Right, nil)
839
840 p = "mapaccess2"
841 }
842
843 // from:
844 // a,b = m[i]
845 // to:
846 // var,b = mapaccess2*(t, m, i)
847 // a = *var
Russ Cox382b44e2015-02-23 16:07:24 -0500848 a := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500849
Russ Cox382b44e2015-02-23 16:07:24 -0500850 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500851 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
852
853 // mapaccess2* returns a typed bool, but due to spec changes,
854 // the boolean result of i.(T) is now untyped so we make it the
855 // same type as the variable on the lhs.
856 if !isblank(n.List.Next.N) {
857 r.Type.Type.Down.Type = n.List.Next.N.Type
858 }
859 n.Rlist = list1(r)
860 n.Op = OAS2FUNC
861
862 // don't generate a = *var if a is _
863 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500864 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500865 var_.Typecheck = 1
866 n.List.N = var_
867 walkexpr(&n, init)
868 *init = list(*init, n)
869 n = Nod(OAS, a, Nod(OIND, var_, nil))
870 }
871
872 typecheck(&n, Etop)
873 walkexpr(&n, init)
874
875 // mapaccess needs a zero value to be at least this big.
876 if zerosize < t.Type.Width {
877 zerosize = t.Type.Width
878 }
879
880 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
881 goto ret
882
883 case ODELETE:
884 *init = concat(*init, n.Ninit)
885 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500886 map_ := n.List.N
887 key := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500888 walkexpr(&map_, init)
889 walkexpr(&key, init)
890
891 // orderstmt made sure key is addressable.
892 key = Nod(OADDR, key, nil)
893
Russ Cox382b44e2015-02-23 16:07:24 -0500894 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500895 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
896 goto ret
897
Russ Cox8c195bd2015-02-13 14:40:36 -0500898 case OAS2DOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400899 e := n.Rlist.N // i.(T)
900 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
901 // It needs to be removed in all three places.
902 // That would allow inlining x.(struct{*int}) the same as x.(*int).
903 if isdirectiface(e.Type) && !Isfat(e.Type) && flag_race == 0 {
904 // handled directly during gen.
905 walkexprlistsafe(n.List, init)
906 walkexpr(&e.Left, init)
907 goto ret
908 }
909
910 // res, ok = i.(T)
911 // orderstmt made sure a is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500912 *init = concat(*init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500913 n.Ninit = nil
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700914
Russ Cox8c195bd2015-02-13 14:40:36 -0500915 walkexprlistsafe(n.List, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700916 walkexpr(&e.Left, init)
917 t := e.Type // T
918 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500919
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700920 oktype := Types[TBOOL]
Russ Cox382b44e2015-02-23 16:07:24 -0500921 ok := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500922 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700923 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500924 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700925
Russ Cox01af7272015-03-19 23:38:24 +0000926 fromKind := type2IET(from.Type)
927 toKind := type2IET(t)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700928
929 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
930 // This is faster and shorter and allows the corresponding assertX2X2
931 // routines to skip nil checks on their last argument.
932 if isblank(n.List.N) {
933 var fast *Node
934 switch {
935 case fromKind == "E" && toKind == "T":
936 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
937 typ := Nod(OCONVNOP, typename(t), nil)
938 typ.Type = Ptrto(Types[TUINTPTR])
939 fast = Nod(OEQ, tab, typ)
940 case fromKind == "I" && toKind == "E",
941 fromKind == "E" && toKind == "E":
942 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700943 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700944 }
945 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400946 if Debug_typeassert > 0 {
947 Warn("type assertion (ok only) inlined")
948 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700949 n = Nod(OAS, ok, fast)
950 typecheck(&n, Etop)
951 goto ret
952 }
953 }
954
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700955 var resptr *Node // &res
956 if isblank(n.List.N) {
957 resptr = nodnil()
958 } else {
959 resptr = Nod(OADDR, n.List.N, nil)
960 }
961 resptr.Etype = 1 // addr does not escape
962
Russ Cox4224d812015-03-20 00:06:10 -0400963 if Debug_typeassert > 0 {
964 Warn("type assertion not inlined")
965 }
Russ Cox01af7272015-03-19 23:38:24 +0000966 buf := "assert" + fromKind + "2" + toKind + "2"
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700967 fn := syslook(buf, 1)
968 substArgTypes(fn, from.Type, t)
969 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
970 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500971 typecheck(&n, Etop)
972 goto ret
973
Russ Cox4224d812015-03-20 00:06:10 -0400974 case ODOTTYPE, ODOTTYPE2:
975 if !isdirectiface(n.Type) || Isfat(n.Type) {
976 Fatal("walkexpr ODOTTYPE") // should see inside OAS only
977 }
978 walkexpr(&n.Left, init)
979 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -0500980
981 case OCONVIFACE:
982 walkexpr(&n.Left, init)
983
984 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500985 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500986 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500987 l.Type = n.Type
988 l.Typecheck = n.Typecheck
989 n = l
990 goto ret
991 }
992
Russ Cox01af7272015-03-19 23:38:24 +0000993 // Build name of function: convI2E etc.
994 // Not all names are possible
995 // (e.g., we'll never generate convE2E or convE2I).
996 buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
997 fn := syslook(buf, 1)
Russ Cox175929b2015-03-02 14:22:05 -0500998 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -0500999 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001000 ll = list(ll, typename(n.Left.Type))
1001 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001002 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001003 ll = list(ll, typename(n.Type))
1004 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001005 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Coxc8198342015-03-12 18:45:30 -04001006 sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -05001007 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -05001008 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001009 l.Sym = sym
1010 l.Type = Ptrto(Types[TUINT8])
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001011 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001012 l.Class = PEXTERN
1013 l.Xoffset = 0
1014 sym.Def = l
1015 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
1016 }
1017
Russ Cox382b44e2015-02-23 16:07:24 -05001018 l := Nod(OADDR, sym.Def, nil)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001019 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001020 ll = list(ll, l)
1021
Russ Coxdc7b54b2015-02-17 22:13:49 -05001022 if isdirectiface(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001023 /* For pointer types, we can make a special form of optimization
1024 *
1025 * These statements are put onto the expression init list:
1026 * Itab *tab = atomicloadtype(&cache);
1027 * if(tab == nil)
1028 * tab = typ2Itab(type, itype, &cache);
1029 *
1030 * The CONVIFACE expression is replaced with this:
1031 * OEFACE{tab, ptr};
1032 */
Russ Cox382b44e2015-02-23 16:07:24 -05001033 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001034
Russ Cox382b44e2015-02-23 16:07:24 -05001035 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001036 typecheck(&n1, Etop)
1037 *init = list(*init, n1)
1038
Russ Cox382b44e2015-02-23 16:07:24 -05001039 fn := syslook("typ2Itab", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001040 n1 = Nod(OCALL, fn, nil)
1041 n1.List = ll
1042 typecheck(&n1, Erv)
1043 walkexpr(&n1, init)
1044
Russ Cox382b44e2015-02-23 16:07:24 -05001045 n2 := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -04001046 n2.Left = Nod(OEQ, l, nodnil())
Russ Cox8c195bd2015-02-13 14:40:36 -05001047 n2.Nbody = list1(Nod(OAS, l, n1))
1048 n2.Likely = -1
1049 typecheck(&n2, Etop)
1050 *init = list(*init, n2)
1051
1052 l = Nod(OEFACE, l, n.Left)
1053 l.Typecheck = n.Typecheck
1054 l.Type = n.Type
1055 n = l
1056 goto ret
1057 }
1058 }
1059
Russ Coxdc7b54b2015-02-17 22:13:49 -05001060 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001061 ll = list(ll, n.Left)
1062 } else {
1063 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001064 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001065 // the conversions it could see. comparison of an interface
1066 // with a non-interface, especially in a switch on interface value
1067 // with non-interface cases, is not visible to orderstmt, so we
1068 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001069 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001070 ll = list(ll, Nod(OADDR, n.Left, nil))
1071 } else {
1072 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1073 }
David Chase22701332015-03-27 11:21:14 -04001074 dowidth(n.Left.Type)
1075 r := nodnil()
1076 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1077 // Allocate stack buffer for value stored in interface.
1078 r = temp(n.Left.Type)
1079 r = Nod(OAS, r, nil) // zero temp
1080 typecheck(&r, Etop)
1081 *init = list(*init, r)
1082 r = Nod(OADDR, r.Left, nil)
1083 typecheck(&r, Erv)
1084 }
1085 ll = list(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001086 }
1087
David Chase22701332015-03-27 11:21:14 -04001088 if !Isinter(n.Left.Type) {
1089 substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
1090 } else {
1091 substArgTypes(fn, n.Left.Type, n.Type)
1092 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001093 dowidth(fn.Type)
1094 n = Nod(OCALL, fn, nil)
1095 n.List = ll
1096 typecheck(&n, Erv)
1097 walkexpr(&n, init)
1098 goto ret
1099
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001100 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001101 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001102 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001103 if n.Type.Etype == TINT64 {
1104 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1105 goto ret
1106 }
1107
1108 if n.Type.Etype == TUINT64 {
1109 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1110 goto ret
1111 }
1112 }
1113
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001114 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001115 if n.Left.Type.Etype == TINT64 {
1116 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
1117 goto ret
1118 }
1119
1120 if n.Left.Type.Etype == TUINT64 {
1121 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
1122 goto ret
1123 }
1124 }
1125 }
1126
1127 walkexpr(&n.Left, init)
1128 goto ret
1129
1130 case OANDNOT:
1131 walkexpr(&n.Left, init)
1132 n.Op = OAND
1133 n.Right = Nod(OCOM, n.Right, nil)
1134 typecheck(&n.Right, Erv)
1135 walkexpr(&n.Right, init)
1136 goto ret
1137
1138 case OMUL:
1139 walkexpr(&n.Left, init)
1140 walkexpr(&n.Right, init)
1141 walkmul(&n, init)
1142 goto ret
1143
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001144 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001145 walkexpr(&n.Left, init)
1146 walkexpr(&n.Right, init)
1147
1148 /*
1149 * rewrite complex div into function call.
1150 */
Russ Cox382b44e2015-02-23 16:07:24 -05001151 et := int(n.Left.Type.Etype)
Russ Cox8c195bd2015-02-13 14:40:36 -05001152
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001153 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001154 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001155 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1156 n = conv(n, t)
1157 goto ret
1158 }
1159
1160 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001161 if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001162 goto ret
1163 }
1164
1165 // Try rewriting as shifts or magic multiplies.
1166 walkdiv(&n, init)
1167
1168 /*
1169 * rewrite 64-bit div and mod into function calls
1170 * on 32-bit architectures.
1171 */
1172 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001173 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001174 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
1175 goto ret
1176 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001177 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001178 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001179 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001180 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001181 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001182 }
1183 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001184 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001185 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001186 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001187 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001188 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001189
1190 default:
1191 break
1192 }
1193
1194 goto ret
1195
1196 case OINDEX:
1197 walkexpr(&n.Left, init)
1198
1199 // save the original node for bounds checking elision.
1200 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001201 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001202
1203 walkexpr(&n.Right, init)
1204
1205 // if range of type cannot exceed static array bound,
1206 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001207 if n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001208 goto ret
1209 }
Russ Cox382b44e2015-02-23 16:07:24 -05001210 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001211 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001212 t = t.Type
1213 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001214 if Isfixedarray(t) {
1215 n.Bounded = bounded(r, t.Bound)
1216 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001217 Warn("index bounds check elided")
1218 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001219 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001220 Yyerror("index out of bounds")
1221 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001222 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001223 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001224 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001225 Warn("index bounds check elided")
1226 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001227 if Smallintconst(n.Right) {
1228 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001229 Yyerror("index out of bounds")
1230 } else {
1231 // replace "abc"[1] with 'b'.
1232 // delayed until now because "abc"[1] is not
1233 // an ideal constant.
Russ Cox81d58102015-05-27 00:47:05 -04001234 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05001235
Russ Cox81d58102015-05-27 00:47:05 -04001236 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001237 n.Typecheck = 1
1238 }
1239 }
1240 }
1241
Russ Coxdc7b54b2015-02-17 22:13:49 -05001242 if Isconst(n.Right, CTINT) {
Russ Cox81d58102015-05-27 00:47:05 -04001243 if Mpcmpfixfix(n.Right.Val().U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001244 Yyerror("index out of bounds")
1245 }
1246 }
1247 goto ret
1248
1249 case OINDEXMAP:
1250 if n.Etype == 1 {
1251 goto ret
1252 }
1253 walkexpr(&n.Left, init)
1254 walkexpr(&n.Right, init)
1255
Russ Cox382b44e2015-02-23 16:07:24 -05001256 t := n.Left.Type
1257 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001258 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
1259 switch Simsimtype(t.Down) {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001260 case TINT32, TUINT32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001261 p = "mapaccess1_fast32"
1262
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001263 case TINT64, TUINT64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001264 p = "mapaccess1_fast64"
1265
1266 case TSTRING:
1267 p = "mapaccess1_faststr"
1268 }
1269 }
1270
Russ Cox382b44e2015-02-23 16:07:24 -05001271 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001272 if p != "" {
1273 // fast versions take key by value
1274 key = n.Right
1275 } else {
1276 // standard version takes key by reference.
1277 // orderexpr made sure key is addressable.
1278 key = Nod(OADDR, n.Right, nil)
1279
1280 p = "mapaccess1"
1281 }
1282
1283 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1284 n = Nod(OIND, n, nil)
1285 n.Type = t.Type
1286 n.Typecheck = 1
1287
1288 // mapaccess needs a zero value to be at least this big.
1289 if zerosize < t.Type.Width {
1290 zerosize = t.Type.Width
1291 }
1292 goto ret
1293
1294 case ORECV:
1295 Fatal("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001296
Russ Coxd4472792015-05-06 12:35:53 -04001297 case OSLICE, OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001298 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001299 walkexpr(&n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001300 if n.Right.Left != nil && iszero(n.Right.Left) {
1301 // Reduce x[0:j] to x[:j].
1302 n.Right.Left = nil
1303 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001304 walkexpr(&n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001305 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001306 goto ret
1307
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001308 case OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -04001309 walkexpr(&n.Left, init)
1310 walkexpr(&n.Right.Left, init)
1311 if n.Right.Left != nil && iszero(n.Right.Left) {
1312 // Reduce x[0:j:k] to x[:j:k].
1313 n.Right.Left = nil
1314 }
1315 walkexpr(&n.Right.Right.Left, init)
1316 walkexpr(&n.Right.Right.Right, init)
1317
1318 r := n.Right.Right.Right
1319 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1320 // Reduce x[i:j:cap(x)] to x[i:j].
1321 n.Right.Right = n.Right.Right.Left
1322 if n.Op == OSLICE3 {
1323 n.Op = OSLICE
1324 } else {
1325 n.Op = OSLICEARR
1326 }
1327 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001328 goto ret
1329 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001330 goto ret
1331
1332 case OADDR:
1333 walkexpr(&n.Left, init)
1334 goto ret
1335
1336 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001337 if n.Esc == EscNone {
1338 if n.Type.Type.Width >= 1<<16 {
Russ Cox3c3019a2015-05-27 00:44:05 -04001339 Fatal("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001340 }
Russ Cox382b44e2015-02-23 16:07:24 -05001341 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001342 r = Nod(OAS, r, nil) // zero temp
1343 typecheck(&r, Etop)
1344 *init = list(*init, r)
1345 r = Nod(OADDR, r.Left, nil)
1346 typecheck(&r, Erv)
1347 n = r
1348 } else {
1349 n = callnew(n.Type.Type)
1350 }
1351
1352 goto ret
1353
1354 // If one argument to the comparison is an empty string,
1355 // comparing the lengths instead will yield the same result
1356 // without the function call.
1357 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001358 if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
Russ Cox382b44e2015-02-23 16:07:24 -05001359 r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001360 typecheck(&r, Erv)
1361 walkexpr(&r, init)
1362 r.Type = n.Type
1363 n = r
1364 goto ret
1365 }
1366
1367 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Russ Coxdc7b54b2015-02-17 22:13:49 -05001368 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 -05001369 r := Nod(int(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001370 typecheck(&r, Erv)
1371 walkexpr(&r, init)
1372 r.Type = n.Type
1373 n = r
1374 goto ret
1375 }
1376
Russ Cox382b44e2015-02-23 16:07:24 -05001377 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001378 if n.Etype == OEQ || n.Etype == ONE {
1379 // prepare for rewrite below
1380 n.Left = cheapexpr(n.Left, init)
1381
1382 n.Right = cheapexpr(n.Right, init)
1383
1384 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1385
1386 // quick check of len before full compare for == or !=
1387 // eqstring assumes that the lengths are equal
1388 if n.Etype == OEQ {
1389 // len(left) == len(right) && eqstring(left, right)
1390 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1391 } else {
1392 // len(left) != len(right) || !eqstring(left, right)
1393 r = Nod(ONOT, r, nil)
1394
1395 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1396 }
1397
1398 typecheck(&r, Erv)
1399 walkexpr(&r, nil)
1400 } else {
1401 // sys_cmpstring(s1, s2) :: 0
1402 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1403
1404 r = Nod(int(n.Etype), r, Nodintconst(0))
1405 }
1406
1407 typecheck(&r, Erv)
1408 if n.Type.Etype != TBOOL {
Russ Cox17228f42015-04-17 12:03:22 -04001409 Fatal("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001410 }
1411 r.Type = n.Type
1412 n = r
1413 goto ret
1414
1415 case OADDSTR:
1416 n = addstr(n, init)
1417 goto ret
1418
1419 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001420 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
1421 Fatal("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001422
1423 case OCOPY:
1424 n = copyany(n, init, flag_race)
1425 goto ret
1426
1427 // cannot use chanfn - closechan takes any, not chan any
1428 case OCLOSE:
Russ Cox382b44e2015-02-23 16:07:24 -05001429 fn := syslook("closechan", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001430
Russ Cox13f9c8b2015-03-08 13:33:49 -04001431 substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001432 n = mkcall1(fn, nil, init, n.Left)
1433 goto ret
1434
1435 case OMAKECHAN:
1436 n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
1437 goto ret
1438
1439 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001440 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001441
Russ Cox382b44e2015-02-23 16:07:24 -05001442 fn := syslook("makemap", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001443
Russ Cox382b44e2015-02-23 16:07:24 -05001444 a := nodnil() // hmap buffer
1445 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001446 if n.Esc == EscNone {
1447 // Allocate hmap buffer on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001448 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001449
1450 a = Nod(OAS, var_, nil) // zero temp
1451 typecheck(&a, Etop)
1452 *init = list(*init, a)
1453 a = Nod(OADDR, var_, nil)
1454
1455 // Allocate one bucket on stack.
1456 // Maximum key/value size is 128 bytes, larger objects
1457 // are stored with an indirection. So max bucket size is 2048+eps.
1458 var_ = temp(mapbucket(t))
1459
1460 r = Nod(OAS, var_, nil) // zero temp
1461 typecheck(&r, Etop)
1462 *init = list(*init, r)
1463 r = Nod(OADDR, var_, nil)
1464 }
1465
Russ Cox13f9c8b2015-03-08 13:33:49 -04001466 substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001467 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
1468 goto ret
1469
1470 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001471 l := n.Left
1472 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001473 if r == nil {
1474 r = safeexpr(l, init)
1475 l = r
1476 }
Russ Cox382b44e2015-02-23 16:07:24 -05001477 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001478 if n.Esc == EscNone {
1479 if !isSmallMakeSlice(n) {
Russ Cox3c3019a2015-05-27 00:44:05 -04001480 Fatal("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001481 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001482 // var arr [r]T
1483 // n = arr[:l]
1484 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001485 var_ := temp(t)
1486 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001487 typecheck(&a, Etop)
1488 *init = list(*init, a)
Russ Cox382b44e2015-02-23 16:07:24 -05001489 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001490 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001491 typecheck(&r, Erv)
1492 walkexpr(&r, init)
1493 n = r
1494 } else {
1495 // makeslice(t *Type, nel int64, max int64) (ary []any)
Russ Cox382b44e2015-02-23 16:07:24 -05001496 fn := syslook("makeslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001497
Russ Cox13f9c8b2015-03-08 13:33:49 -04001498 substArgTypes(fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001499 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1500 }
1501
1502 goto ret
1503
1504 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001505 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001506 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001507 t := aindex(Nodintconst(4), Types[TUINT8])
1508 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001509 a = Nod(OADDR, var_, nil)
1510 }
1511
1512 // intstring(*[4]byte, rune)
1513 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1514
1515 goto ret
1516
1517 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001518 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001519 if n.Esc == EscNone {
1520 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001521 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001522
1523 a = Nod(OADDR, temp(t), nil)
1524 }
1525
1526 // slicebytetostring(*[32]byte, []byte) string;
1527 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1528
1529 goto ret
1530
1531 // slicebytetostringtmp([]byte) string;
1532 case OARRAYBYTESTRTMP:
1533 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1534
1535 goto ret
1536
1537 // slicerunetostring(*[32]byte, []rune) string;
1538 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001539 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001540
1541 if n.Esc == EscNone {
1542 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001543 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001544
1545 a = Nod(OADDR, temp(t), nil)
1546 }
1547
1548 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
1549 goto ret
1550
1551 // stringtoslicebyte(*32[byte], string) []byte;
1552 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001553 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001554
1555 if n.Esc == EscNone {
1556 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001557 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001558
1559 a = Nod(OADDR, temp(t), nil)
1560 }
1561
1562 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
1563 goto ret
1564
1565 // stringtoslicebytetmp(string) []byte;
1566 case OSTRARRAYBYTETMP:
1567 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1568
1569 goto ret
1570
1571 // stringtoslicerune(*[32]rune, string) []rune
1572 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001573 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001574
1575 if n.Esc == EscNone {
1576 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001577 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001578
1579 a = Nod(OADDR, temp(t), nil)
1580 }
1581
1582 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
1583 goto ret
1584
1585 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1586 case OCMPIFACE:
1587 if !Eqtype(n.Left.Type, n.Right.Type) {
Russ Cox17228f42015-04-17 12:03:22 -04001588 Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001589 }
Russ Cox382b44e2015-02-23 16:07:24 -05001590 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001591 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001592 fn = syslook("efaceeq", 1)
1593 } else {
1594 fn = syslook("ifaceeq", 1)
1595 }
1596
1597 n.Right = cheapexpr(n.Right, init)
1598 n.Left = cheapexpr(n.Left, init)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001599 substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001600 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05001601 if n.Etype == ONE {
1602 r = Nod(ONOT, r, nil)
1603 }
1604
1605 // check itable/type before full compare.
1606 if n.Etype == OEQ {
1607 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1608 } else {
1609 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1610 }
1611 typecheck(&r, Erv)
1612 walkexpr(&r, init)
1613 r.Type = n.Type
1614 n = r
1615 goto ret
1616
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001617 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001618 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001619 anylit(0, n, var_, init)
1620 n = var_
1621 goto ret
1622
1623 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001624 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001625 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1626 walkexpr(&n1, init)
1627 n1 = Nod(OADDR, n1, nil)
1628 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
1629 goto ret
1630
1631 case OCLOSURE:
1632 n = walkclosure(n, init)
1633 goto ret
1634
1635 case OCALLPART:
1636 n = walkpartialcall(n, init)
1637 goto ret
1638 }
1639
1640 Fatal("missing switch %v", Oconv(int(n.Op), 0))
1641
1642 // Expressions that are constant at run time but not
1643 // considered const by the language spec are not turned into
1644 // constants until walk. For example, if n is y%1 == 0, the
1645 // walk of y%1 may have replaced it by 0.
1646 // Check whether n with its updated args is itself now a constant.
1647ret:
Russ Cox382b44e2015-02-23 16:07:24 -05001648 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001649
1650 evconst(n)
1651 n.Type = t
1652 if n.Op == OLITERAL {
1653 typecheck(&n, Erv)
1654 }
1655
1656 ullmancalc(n)
1657
1658 if Debug['w'] != 0 && n != nil {
1659 Dump("walk", n)
1660 }
1661
1662 lineno = lno
1663 *np = n
1664}
1665
Russ Coxd4472792015-05-06 12:35:53 -04001666func reduceSlice(n *Node) *Node {
1667 r := n.Right.Right
1668 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1669 // Reduce x[i:len(x)] to x[i:].
1670 n.Right.Right = nil
1671 }
1672 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1673 // Reduce x[:] to x.
1674 if Debug_slice > 0 {
1675 Warn("slice: omit slice operation")
1676 }
1677 return n.Left
1678 }
1679 return n
1680}
1681
Russ Cox8c195bd2015-02-13 14:40:36 -05001682func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001683 // convas will turn map assigns into function calls,
1684 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001685 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001686
1687 if l.Op == OINDEXMAP {
1688 return n
1689 }
1690
1691 return convas(n, init)
1692}
1693
1694func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001695 /*
1696 * check assign expression list to
1697 * a expression list. called in
1698 * expr-list = expr-list
1699 */
1700
1701 // ensure order of evaluation for function calls
Russ Coxc8198342015-03-12 18:45:30 -04001702 for ll := nl; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001703 ll.N = safeexpr(ll.N, init)
1704 }
Russ Coxc8198342015-03-12 18:45:30 -04001705 for lr := nr; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001706 lr.N = safeexpr(lr.N, init)
1707 }
1708
Russ Cox175929b2015-03-02 14:22:05 -05001709 var nn *NodeList
Russ Coxc8198342015-03-12 18:45:30 -04001710 ll := nl
1711 lr := nr
Russ Coxd7f6d462015-03-09 00:31:13 -04001712 for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001713 // Do not generate 'x = x' during return. See issue 4014.
1714 if op == ORETURN && ll.N == lr.N {
1715 continue
1716 }
1717 nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
1718 }
1719
1720 // cannot happen: caller checked that lists had same length
1721 if ll != nil || lr != nil {
Russ Coxbd4fff62015-05-27 10:42:55 -04001722 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.Func.Nname.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -05001723 }
1724 return nn
1725}
1726
1727/*
1728 * l is an lv and rt is the type of an rv
1729 * return 1 if this implies a function call
1730 * evaluating the lv or a function call
1731 * in the conversion of the types
1732 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001733func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001734 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001735 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001736 }
Russ Cox175929b2015-03-02 14:22:05 -05001737 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001738 if needwritebarrier(l, &r) {
1739 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001740 }
1741 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001742 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001743 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001744 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001745}
1746
1747func ascompatet(op int, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
1748 var l *Node
1749 var tmp *Node
1750 var a *Node
1751 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001752 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001753
1754 /*
1755 * check assign type list to
1756 * a expression list. called in
1757 * expr-list = func()
1758 */
Russ Cox382b44e2015-02-23 16:07:24 -05001759 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001760
Russ Cox175929b2015-03-02 14:22:05 -05001761 var nn *NodeList
1762 var mm *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001763 ucount := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001764 for ll = nl; ll != nil; ll = ll.Next {
1765 if r == nil {
1766 break
1767 }
1768 l = ll.N
1769 if isblank(l) {
1770 r = structnext(&saver)
1771 continue
1772 }
1773
1774 // any lv that causes a fn call must be
1775 // deferred until all the return arguments
1776 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001777 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001778 tmp = temp(r.Type)
1779 typecheck(&tmp, Erv)
1780 a = Nod(OAS, l, tmp)
1781 a = convas(a, init)
1782 mm = list(mm, a)
1783 l = tmp
1784 }
1785
1786 a = Nod(OAS, l, nodarg(r, fp))
1787 a = convas(a, init)
1788 ullmancalc(a)
1789 if a.Ullman >= UINF {
1790 Dump("ascompatet ucount", a)
1791 ucount++
1792 }
1793
1794 nn = list(nn, a)
1795 r = structnext(&saver)
1796 }
1797
1798 if ll != nil || r != nil {
1799 Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
1800 }
1801
1802 if ucount != 0 {
1803 Fatal("ascompatet: too many function calls evaluating parameters")
1804 }
1805 return concat(nn, mm)
1806}
1807
1808/*
1809* package all the arguments that match a ... T parameter into a []T.
1810 */
1811func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
David Chase7fbb1b32015-03-26 16:36:15 -04001812 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001813 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001814 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001815 }
1816
Russ Cox382b44e2015-02-23 16:07:24 -05001817 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001818 tslice.Type = l.Type.Type
1819 tslice.Bound = -1
1820
Russ Cox382b44e2015-02-23 16:07:24 -05001821 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001822 if count(lr0) == 0 {
1823 n = nodnil()
1824 n.Type = tslice
1825 } else {
1826 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001827 if ddd != nil && prealloc[ddd] != nil {
1828 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001829 }
1830 n.List = lr0
Dave Cheneye4981812015-03-10 09:58:01 +11001831 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 typecheck(&n, Erv)
1833 if n.Type == nil {
1834 Fatal("mkdotargslice: typecheck failed")
1835 }
1836 walkexpr(&n, init)
1837 }
1838
Russ Cox382b44e2015-02-23 16:07:24 -05001839 a := Nod(OAS, nodarg(l, fp), n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001840 nn = list(nn, convas(a, init))
1841 return nn
1842}
1843
1844/*
1845 * helpers for shape errors
1846 */
1847func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001848 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001849
Russ Cox382b44e2015-02-23 16:07:24 -05001850 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001851 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001852 first := 1
1853 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001854 if first != 0 {
1855 first = 0
1856 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001857 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001858 }
Russ Coxc8198342015-03-12 18:45:30 -04001859 fmt_ += Tconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001860 }
1861
1862 if first != 0 {
1863 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1864 }
1865 return fmt_
1866}
1867
1868func dumpnodetypes(l *NodeList, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001869 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001870
Russ Cox382b44e2015-02-23 16:07:24 -05001871 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001872 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001873 first := 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001874 for ; l != nil; l = l.Next {
1875 r = l.N
1876 if first != 0 {
1877 first = 0
1878 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001879 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001880 }
Russ Coxc8198342015-03-12 18:45:30 -04001881 fmt_ += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001882 }
1883
1884 if first != 0 {
1885 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1886 }
1887 return fmt_
1888}
1889
1890/*
1891 * check assign expression list to
1892 * a type list. called in
1893 * return expr-list
1894 * func(expr-list)
1895 */
Dave Cheneyd3287562015-03-09 16:24:07 +11001896func ascompatte(op int, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001897 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001898
Russ Cox382b44e2015-02-23 16:07:24 -05001899 lr0 := lr
1900 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001901 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001902 if lr != nil {
1903 r = lr.N
1904 }
Russ Cox175929b2015-03-02 14:22:05 -05001905 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001906
1907 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001908 var a *Node
1909 var l2 string
1910 var ll *Type
1911 var l1 string
Russ Cox8c195bd2015-02-13 14:40:36 -05001912 if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg != 0 {
1913 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001914 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001915 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001916 r = Nod(OCONVNOP, r, nil)
1917 r.Type = a.Type
1918 nn = list1(convas(Nod(OAS, a, r), init))
1919 goto ret
1920 }
1921
1922 // conversions involved.
1923 // copy into temporaries.
Russ Cox175929b2015-03-02 14:22:05 -05001924 var alist *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001925
Russ Cox382b44e2015-02-23 16:07:24 -05001926 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001927 a = temp(l.Type)
1928 alist = list(alist, a)
1929 }
1930
1931 a = Nod(OAS2, nil, nil)
1932 a.List = alist
1933 a.Rlist = lr
1934 typecheck(&a, Etop)
1935 walkstmt(&a)
1936 *init = list(*init, a)
1937 lr = alist
1938 r = lr.N
1939 l = Structfirst(&savel, nl)
1940 }
1941
1942loop:
Dave Cheneyd3287562015-03-09 16:24:07 +11001943 if l != nil && l.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001944 // the ddd parameter must be last
1945 ll = structnext(&savel)
1946
1947 if ll != nil {
1948 Yyerror("... must be last argument")
1949 }
1950
1951 // special case --
1952 // only if we are assigning a single ddd
1953 // argument to a ddd parameter then it is
1954 // passed thru unencapsulated
Dave Cheneyd3287562015-03-09 16:24:07 +11001955 if r != nil && lr.Next == nil && isddd && Eqtype(l.Type, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001956 a = Nod(OAS, nodarg(l, fp), r)
1957 a = convas(a, init)
1958 nn = list(nn, a)
1959 goto ret
1960 }
1961
1962 // normal case -- make a slice of all
1963 // remaining arguments and pass it to
1964 // the ddd parameter.
1965 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1966
1967 goto ret
1968 }
1969
1970 if l == nil || r == nil {
1971 if l != nil || r != nil {
1972 l1 = dumptypes(nl, "expected")
1973 l2 = dumpnodetypes(lr0, "given")
1974 if l != nil {
1975 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1976 } else {
1977 Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1978 }
1979 }
1980
1981 goto ret
1982 }
1983
1984 a = Nod(OAS, nodarg(l, fp), r)
1985 a = convas(a, init)
1986 nn = list(nn, a)
1987
1988 l = structnext(&savel)
1989 r = nil
1990 lr = lr.Next
1991 if lr != nil {
1992 r = lr.N
1993 }
1994 goto loop
1995
1996ret:
1997 for lr = nn; lr != nil; lr = lr.Next {
1998 lr.N.Typecheck = 1
1999 }
2000 return nn
2001}
2002
2003// generate code for print
2004func walkprint(nn *Node, init **NodeList) *Node {
2005 var r *Node
2006 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002007 var on *Node
2008 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002009 var et int
Russ Cox8c195bd2015-02-13 14:40:36 -05002010
Russ Cox382b44e2015-02-23 16:07:24 -05002011 op := int(nn.Op)
2012 all := nn.List
Russ Cox175929b2015-03-02 14:22:05 -05002013 var calls *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002014 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05002015
2016 // Hoist all the argument evaluation up before the lock.
2017 walkexprlistcheap(all, init)
2018
2019 calls = list(calls, mkcall("printlock", nil, init))
2020
Russ Cox382b44e2015-02-23 16:07:24 -05002021 for l := all; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002022 if notfirst {
Russ Cox8c195bd2015-02-13 14:40:36 -05002023 calls = list(calls, mkcall("printsp", nil, init))
2024 }
2025
Russ Coxdc7b54b2015-02-17 22:13:49 -05002026 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05002027
2028 n = l.N
2029 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002030 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002031 case CTRUNE:
2032 defaultlit(&n, runetype)
2033
2034 case CTINT:
2035 defaultlit(&n, Types[TINT64])
2036
2037 case CTFLT:
2038 defaultlit(&n, Types[TFLOAT64])
2039 }
2040 }
2041
2042 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
2043 defaultlit(&n, Types[TINT64])
2044 }
2045 defaultlit(&n, nil)
2046 l.N = n
2047 if n.Type == nil || n.Type.Etype == TFORW {
2048 continue
2049 }
2050
2051 t = n.Type
2052 et = int(n.Type.Etype)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002053 if Isinter(n.Type) {
2054 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002055 on = syslook("printeface", 1)
2056 } else {
2057 on = syslook("printiface", 1)
2058 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002059 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002060 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Russ Cox8c195bd2015-02-13 14:40:36 -05002061 on = syslook("printpointer", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002062 substArgTypes(on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05002063 } else if Isslice(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002064 on = syslook("printslice", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002065 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002066 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002067 if et == TUINT64 {
2068 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
2069 on = syslook("printhex", 0)
2070 } else {
2071 on = syslook("printuint", 0)
2072 }
2073 } else {
2074 on = syslook("printint", 0)
2075 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002076 } else if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002077 on = syslook("printfloat", 0)
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002078 } else if Iscomplex[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002079 on = syslook("printcomplex", 0)
2080 } else if et == TBOOL {
2081 on = syslook("printbool", 0)
2082 } else if et == TSTRING {
2083 on = syslook("printstring", 0)
2084 } else {
2085 badtype(OPRINT, n.Type, nil)
2086 continue
2087 }
2088
2089 t = *getinarg(on.Type)
2090 if t != nil {
2091 t = t.Type
2092 }
2093 if t != nil {
2094 t = t.Type
2095 }
2096
2097 if !Eqtype(t, n.Type) {
2098 n = Nod(OCONV, n, nil)
2099 n.Type = t
2100 }
2101
2102 r = Nod(OCALL, on, nil)
2103 r.List = list1(n)
2104 calls = list(calls, r)
2105 }
2106
2107 if op == OPRINTN {
2108 calls = list(calls, mkcall("printnl", nil, nil))
2109 }
2110
2111 calls = list(calls, mkcall("printunlock", nil, init))
2112
2113 typechecklist(calls, Etop)
2114 walkexprlist(calls, init)
2115
2116 r = Nod(OEMPTY, nil, nil)
2117 typecheck(&r, Etop)
2118 walkexpr(&r, init)
2119 r.Ninit = calls
2120 return r
2121}
2122
2123func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002124 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -05002125 fn := syslook("newobject", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002126 substArgTypes(fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002127 return mkcall1(fn, Ptrto(t), nil, typename(t))
2128}
2129
Russ Coxdc7b54b2015-02-17 22:13:49 -05002130func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002131 n = outervalue(n)
2132
2133 // If n is *autotmp and autotmp = &foo, replace n with foo.
2134 // We introduce such temps when initializing struct literals.
2135 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002136 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002137 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2138 n = defn.Right.Left
2139 }
2140 }
2141
2142 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002143 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002144 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002145
2146 case ONAME:
2147 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002148 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002149 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002150 }
2151 }
2152
Russ Coxdc7b54b2015-02-17 22:13:49 -05002153 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002154}
2155
Russ Coxdc7b54b2015-02-17 22:13:49 -05002156func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002157 n = outervalue(n)
2158
2159 switch n.Op {
2160 case ONAME:
2161 switch n.Class {
2162 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002163 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002164 }
2165 }
2166
Russ Coxdc7b54b2015-02-17 22:13:49 -05002167 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002168}
2169
2170// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002171func needwritebarrier(l *Node, r *Node) bool {
2172 if use_writebarrier == 0 {
2173 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002174 }
2175
2176 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002177 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002178 }
2179
2180 // No write barrier for write of non-pointers.
2181 dowidth(l.Type)
2182
2183 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002184 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002185 }
2186
2187 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002188 if isstack(l) {
2189 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002190 }
2191
2192 // No write barrier for implicit or explicit zeroing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002193 if r == nil || iszero(r) {
2194 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002195 }
2196
2197 // No write barrier for initialization to constant.
2198 if r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002199 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002200 }
2201
2202 // No write barrier for storing static (read-only) data.
2203 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002204 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002205 }
2206
2207 // No write barrier for storing address of stack values,
2208 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002209 if r.Op == OADDR && isstack(r.Left) {
2210 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002211 }
2212
2213 // No write barrier for storing address of global, which
2214 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002215 if r.Op == OADDR && isglobal(r.Left) {
2216 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002217 }
2218
Russ Cox8c195bd2015-02-13 14:40:36 -05002219 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002220 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002221}
2222
2223// TODO(rsc): Perhaps componentgen should run before this.
2224
Russ Cox01531372015-03-02 21:25:33 -05002225var applywritebarrier_bv Bvec
Russ Cox8c195bd2015-02-13 14:40:36 -05002226
2227func applywritebarrier(n *Node, init **NodeList) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002228 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002229 if Debug_wb > 1 {
2230 Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002231 }
Russ Cox972a4782015-05-21 15:00:06 -04002232 n.Op = OASWB
2233 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002235 return n
2236}
2237
2238func convas(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002239 if n.Op != OAS {
2240 Fatal("convas: not OAS %v", Oconv(int(n.Op), 0))
2241 }
2242
2243 n.Typecheck = 1
2244
Russ Cox382b44e2015-02-23 16:07:24 -05002245 var lt *Type
2246 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002247 if n.Left == nil || n.Right == nil {
2248 goto out
2249 }
2250
2251 lt = n.Left.Type
2252 rt = n.Right.Type
2253 if lt == nil || rt == nil {
2254 goto out
2255 }
2256
2257 if isblank(n.Left) {
2258 defaultlit(&n.Right, nil)
2259 goto out
2260 }
2261
2262 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002263 map_ := n.Left.Left
2264 key := n.Left.Right
2265 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002266 walkexpr(&map_, init)
2267 walkexpr(&key, init)
2268 walkexpr(&val, init)
2269
2270 // orderexpr made sure key and val are addressable.
2271 key = Nod(OADDR, key, nil)
2272
2273 val = Nod(OADDR, val, nil)
2274 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2275 goto out
2276 }
2277
2278 if !Eqtype(lt, rt) {
2279 n.Right = assignconv(n.Right, lt, "assignment")
2280 walkexpr(&n.Right, init)
2281 }
2282
2283out:
2284 ullmancalc(n)
2285 return n
2286}
2287
2288/*
2289 * from ascompat[te]
2290 * evaluating actual function arguments.
2291 * f(a,b)
2292 * if there is exactly one function expr,
2293 * then it is done first. otherwise must
2294 * make temp variables
2295 */
2296func reorder1(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002297 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002298
Russ Cox382b44e2015-02-23 16:07:24 -05002299 c := 0 // function calls
2300 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002301
Russ Cox382b44e2015-02-23 16:07:24 -05002302 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002303 n = l.N
2304 t++
2305 ullmancalc(n)
2306 if n.Ullman >= UINF {
2307 c++
2308 }
2309 }
2310
2311 if c == 0 || t == 1 {
2312 return all
2313 }
2314
Russ Cox175929b2015-03-02 14:22:05 -05002315 var g *NodeList // fncalls assigned to tempnames
2316 var f *Node // last fncall assigned to stack
2317 var r *NodeList // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002318 d := 0
2319 var a *Node
2320 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002321 n = l.N
2322 if n.Ullman < UINF {
2323 r = list(r, n)
2324 continue
2325 }
2326
2327 d++
2328 if d == c {
2329 f = n
2330 continue
2331 }
2332
2333 // make assignment of fncall to tempname
2334 a = temp(n.Right.Type)
2335
2336 a = Nod(OAS, a, n.Right)
2337 g = list(g, a)
2338
2339 // put normal arg assignment on list
2340 // with fncall replaced by tempname
2341 n.Right = a.Left
2342
2343 r = list(r, n)
2344 }
2345
2346 if f != nil {
2347 g = list(g, f)
2348 }
2349 return concat(g, r)
2350}
2351
2352/*
2353 * from ascompat[ee]
2354 * a,b = c,d
2355 * simultaneous assignment. there cannot
2356 * be later use of an earlier lvalue.
2357 *
2358 * function calls have been removed.
2359 */
2360func reorder3(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002361 var l *Node
2362
2363 // If a needed expression may be affected by an
2364 // earlier assignment, make an early copy of that
2365 // expression and use the copy instead.
Russ Cox175929b2015-03-02 14:22:05 -05002366 var early *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002367
Russ Cox175929b2015-03-02 14:22:05 -05002368 var mapinit *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002369 for list := all; list != nil; list = list.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002370 l = list.N.Left
2371
2372 // Save subexpressions needed on left side.
2373 // Drill through non-dereferences.
2374 for {
2375 if l.Op == ODOT || l.Op == OPAREN {
2376 l = l.Left
2377 continue
2378 }
2379
Russ Coxdc7b54b2015-02-17 22:13:49 -05002380 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002381 reorder3save(&l.Right, all, list, &early)
2382 l = l.Left
2383 continue
2384 }
2385
2386 break
2387 }
2388
2389 switch l.Op {
2390 default:
2391 Fatal("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002392
2393 case ONAME:
2394 break
2395
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002396 case OINDEX, OINDEXMAP:
Russ Cox8c195bd2015-02-13 14:40:36 -05002397 reorder3save(&l.Left, all, list, &early)
2398 reorder3save(&l.Right, all, list, &early)
2399 if l.Op == OINDEXMAP {
2400 list.N = convas(list.N, &mapinit)
2401 }
2402
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002403 case OIND, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05002404 reorder3save(&l.Left, all, list, &early)
2405 }
2406
2407 // Save expression on right side.
2408 reorder3save(&list.N.Right, all, list, &early)
2409 }
2410
2411 early = concat(mapinit, early)
2412 return concat(early, all)
2413}
2414
2415/*
2416 * if the evaluation of *np would be affected by the
2417 * assignments in all up to but not including stop,
2418 * copy into a temporary during *early and
2419 * replace *np with that temp.
2420 */
2421func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05002422 n := *np
Russ Coxdc7b54b2015-02-17 22:13:49 -05002423 if !aliased(n, all, stop) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002424 return
2425 }
2426
Russ Cox382b44e2015-02-23 16:07:24 -05002427 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002428 q = Nod(OAS, q, n)
2429 typecheck(&q, Etop)
2430 *early = list(*early, q)
2431 *np = q.Left
2432}
2433
2434/*
2435 * what's the outer value that a write to n affects?
2436 * outer value means containing struct or array.
2437 */
2438func outervalue(n *Node) *Node {
2439 for {
2440 if n.Op == OXDOT {
2441 Fatal("OXDOT in walk")
2442 }
2443 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2444 n = n.Left
2445 continue
2446 }
2447
Russ Coxdc7b54b2015-02-17 22:13:49 -05002448 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002449 n = n.Left
2450 continue
2451 }
2452
2453 break
2454 }
2455
2456 return n
2457}
2458
2459/*
2460 * Is it possible that the computation of n might be
2461 * affected by writes in as up to but not including stop?
2462 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002463func aliased(n *Node, all *NodeList, stop *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002464 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002465 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002466 }
2467
2468 // Look for obvious aliasing: a variable being assigned
2469 // during the all list and appearing in n.
2470 // Also record whether there are any writes to main memory.
2471 // Also record whether there are any writes to variables
2472 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002473 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002474
Russ Cox382b44e2015-02-23 16:07:24 -05002475 varwrite := 0
2476 var a *Node
2477 for l := all; l != stop; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002478 a = outervalue(l.N.Left)
2479 if a.Op != ONAME {
2480 memwrite = 1
2481 continue
2482 }
2483
2484 switch n.Class {
2485 default:
2486 varwrite = 1
2487 continue
2488
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002489 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002490 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002491 varwrite = 1
2492 continue
2493 }
2494
Russ Coxdc7b54b2015-02-17 22:13:49 -05002495 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002496 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002497 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002498 }
2499 }
2500 }
2501
2502 // The variables being written do not appear in n.
2503 // However, n might refer to computed addresses
2504 // that are being written.
2505
2506 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002507 if memwrite == 0 && varwrite == 0 {
2508 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002509 }
2510
2511 // If n does not refer to computed addresses
2512 // (that is, if n only refers to variables whose addresses
2513 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002514 if varexpr(n) {
2515 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002516 }
2517
2518 // Otherwise, both the writes and n refer to computed memory addresses.
2519 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002520 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002521}
2522
2523/*
2524 * does the evaluation of n only refer to variables
2525 * whose addresses have not been taken?
2526 * (and no other memory)
2527 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002528func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002529 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002530 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002531 }
2532
2533 switch n.Op {
2534 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002535 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002536
2537 case ONAME:
2538 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002539 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002540 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002541 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002542 }
2543 }
2544
Russ Coxdc7b54b2015-02-17 22:13:49 -05002545 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002546
2547 case OADD,
2548 OSUB,
2549 OOR,
2550 OXOR,
2551 OMUL,
2552 ODIV,
2553 OMOD,
2554 OLSH,
2555 ORSH,
2556 OAND,
2557 OANDNOT,
2558 OPLUS,
2559 OMINUS,
2560 OCOM,
2561 OPAREN,
2562 OANDAND,
2563 OOROR,
2564 ODOT, // but not ODOTPTR
2565 OCONV,
2566 OCONVNOP,
2567 OCONVIFACE,
2568 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002569 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002570 }
2571
2572 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002573 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002574}
2575
2576/*
2577 * is the name l mentioned in r?
2578 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002579func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002580 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002581 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002582 }
2583 switch r.Op {
2584 // match each right given left
2585 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002586 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002587
2588 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002589 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002590 }
2591
Russ Coxdc7b54b2015-02-17 22:13:49 -05002592 if vmatch2(l, r.Left) {
2593 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002594 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002595 if vmatch2(l, r.Right) {
2596 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002597 }
Russ Cox382b44e2015-02-23 16:07:24 -05002598 for ll := r.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002599 if vmatch2(l, ll.N) {
2600 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002601 }
2602 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002603 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002604}
2605
2606/*
2607 * is any name mentioned in l also mentioned in r?
Keith Randallcd5b1442015-03-11 12:58:47 -07002608 * called by sinit.go
Russ Cox8c195bd2015-02-13 14:40:36 -05002609 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05002610func vmatch1(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002611 /*
2612 * isolate all left sides
2613 */
2614 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002615 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002616 }
2617 switch l.Op {
2618 case ONAME:
2619 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002620 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002621 break
2622
2623 // assignment to non-stack variable
2624 // must be delayed if right has function calls.
2625 default:
2626 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002627 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002628 }
2629 }
2630
2631 return vmatch2(l, r)
2632
2633 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002634 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002635 }
2636
Russ Coxdc7b54b2015-02-17 22:13:49 -05002637 if vmatch1(l.Left, r) {
2638 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002639 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002640 if vmatch1(l.Right, r) {
2641 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002642 }
Russ Cox382b44e2015-02-23 16:07:24 -05002643 for ll := l.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002644 if vmatch1(ll.N, r) {
2645 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002646 }
2647 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002648 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002649}
2650
2651/*
2652 * walk through argin parameters.
2653 * generate and return code to allocate
2654 * copies of escaped parameters to the heap.
2655 */
2656func paramstoheap(argin **Type, out int) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002657 var savet Iter
2658 var v *Node
2659 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002660
Russ Cox175929b2015-03-02 14:22:05 -05002661 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002662 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002663 v = t.Nname
2664 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2665 v = nil
2666 }
2667
2668 // For precise stacks, the garbage collector assumes results
2669 // are always live, so zero them always.
2670 if out != 0 {
2671 // Defer might stop a panic and show the
2672 // return values as they exist at the time of panic.
2673 // Make sure to zero them on entry to the function.
2674 nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
2675 }
2676
Russ Coxdc7b54b2015-02-17 22:13:49 -05002677 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002678 continue
2679 }
2680
2681 // generate allocation & copying code
2682 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002683 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002684 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002685 if prealloc[v] == nil {
2686 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002687 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002688 nn = list(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002689 if v.Class&^PHEAP != PPARAMOUT {
Russ Coxbd4fff62015-05-27 10:42:55 -04002690 as = Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002691 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002692 typecheck(&as, Etop)
2693 as = applywritebarrier(as, &nn)
2694 nn = list(nn, as)
2695 }
2696 }
2697
2698 return nn
2699}
2700
2701/*
2702 * walk through argout parameters copying back to stack
2703 */
2704func returnsfromheap(argin **Type) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002705 var savet Iter
2706 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002707
Russ Cox175929b2015-03-02 14:22:05 -05002708 var nn *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002709 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002710 v = t.Nname
2711 if v == nil || v.Class != PHEAP|PPARAMOUT {
2712 continue
2713 }
Russ Cox3c3019a2015-05-27 00:44:05 -04002714 nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002715 }
2716
2717 return nn
2718}
2719
2720/*
2721 * take care of migrating any function in/out args
2722 * between the stack and the heap. adds code to
2723 * curfn's before and after lists.
2724 */
2725func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002726 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002727 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002728 nn := paramstoheap(getthis(Curfn.Type), 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05002729 nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
2730 nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002731 Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
2732 lineno = Curfn.Func.Endlineno
2733 Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05002734 lineno = lno
2735}
2736
2737func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002738 if fn.Type == nil || fn.Type.Etype != TFUNC {
Russ Cox17228f42015-04-17 12:03:22 -04002739 Fatal("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002740 }
2741
Russ Cox175929b2015-03-02 14:22:05 -05002742 var args *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002743 n := fn.Type.Intuple
2744 for i := 0; i < n; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05002745 args = list(args, va[i])
2746 }
2747
Russ Cox382b44e2015-02-23 16:07:24 -05002748 r := Nod(OCALL, fn, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002749 r.List = args
2750 if fn.Type.Outtuple > 0 {
2751 typecheck(&r, Erv|Efnstruct)
2752 } else {
2753 typecheck(&r, Etop)
2754 }
2755 walkexpr(&r, init)
2756 r.Type = t
2757 return r
2758}
2759
2760func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
2761 return vmkcall(syslook(name, 0), t, init, args)
2762}
2763
2764func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
2765 return vmkcall(fn, t, init, args)
2766}
2767
2768func conv(n *Node, t *Type) *Node {
2769 if Eqtype(n.Type, t) {
2770 return n
2771 }
2772 n = Nod(OCONV, n, nil)
2773 n.Type = t
2774 typecheck(&n, Erv)
2775 return n
2776}
2777
2778func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002779 if t.Etype != TCHAN {
Russ Cox17228f42015-04-17 12:03:22 -04002780 Fatal("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002781 }
Russ Cox382b44e2015-02-23 16:07:24 -05002782 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002783 switch n {
2784 default:
2785 Fatal("chanfn %d", n)
2786 case 1:
2787 substArgTypes(fn, t.Type)
2788 case 2:
2789 substArgTypes(fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002790 }
2791 return fn
2792}
2793
2794func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002795 if t.Etype != TMAP {
Russ Cox17228f42015-04-17 12:03:22 -04002796 Fatal("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002797 }
Russ Cox382b44e2015-02-23 16:07:24 -05002798 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002799 substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002800 return fn
2801}
2802
2803func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002804 if t.Etype != TMAP {
Russ Cox17228f42015-04-17 12:03:22 -04002805 Fatal("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002806 }
Russ Cox382b44e2015-02-23 16:07:24 -05002807 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002808 substArgTypes(fn, t.Down, t.Type, t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05002809 return fn
2810}
2811
2812func writebarrierfn(name string, l *Type, r *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002813 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002814 substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002815 return fn
2816}
2817
2818func addstr(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002819 // orderexpr rewrote OADDSTR to have a list of strings.
Russ Cox382b44e2015-02-23 16:07:24 -05002820 c := count(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002821
2822 if c < 2 {
2823 Yyerror("addstr count %d too small", c)
2824 }
2825
Russ Cox382b44e2015-02-23 16:07:24 -05002826 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002827 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002828 sz := int64(0)
2829 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002830 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002831 sz += int64(len(n.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002832 }
2833 }
2834
2835 // Don't allocate the buffer if the result won't fit.
2836 if sz < tmpstringbufsize {
2837 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002838 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002839
2840 buf = Nod(OADDR, temp(t), nil)
2841 }
2842 }
2843
2844 // build list of string arguments
Russ Cox382b44e2015-02-23 16:07:24 -05002845 args := list1(buf)
Russ Cox8c195bd2015-02-13 14:40:36 -05002846
Russ Cox382b44e2015-02-23 16:07:24 -05002847 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002848 args = list(args, conv(l.N, Types[TSTRING]))
2849 }
2850
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002851 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002852 if c <= 5 {
2853 // small numbers of strings use direct runtime helpers.
2854 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002855 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002856 } else {
2857 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002858 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002859
Russ Cox382b44e2015-02-23 16:07:24 -05002860 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002861 t.Type = Types[TSTRING]
2862 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002863 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002864 if prealloc[n] != nil {
2865 prealloc[slice] = prealloc[n]
2866 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002867 slice.List = args.Next // skip buf arg
2868 args = list1(buf)
2869 args = list(args, slice)
2870 slice.Esc = EscNone
2871 }
2872
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002873 cat := syslook(fn, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05002874 r := Nod(OCALL, cat, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002875 r.List = args
2876 typecheck(&r, Erv)
2877 walkexpr(&r, init)
2878 r.Type = n.Type
2879
2880 return r
2881}
2882
2883// expand append(l1, l2...) to
2884// init {
2885// s := l1
2886// if n := len(l1) + len(l2) - cap(s); n > 0 {
Russ Cox32fddad2015-06-25 19:27:20 -04002887// s = growslice_n(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002888// }
2889// s = s[:len(l1)+len(l2)]
2890// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2891// }
2892// s
2893//
2894// l2 is allowed to be a string.
2895func appendslice(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002896 walkexprlistsafe(n.List, init)
2897
2898 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2899 // and n are name or literal, but those may index the slice we're
2900 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05002901 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002902 l.N = cheapexpr(l.N, init)
2903 }
2904
Russ Cox382b44e2015-02-23 16:07:24 -05002905 l1 := n.List.N
2906 l2 := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -05002907
Russ Cox382b44e2015-02-23 16:07:24 -05002908 s := temp(l1.Type) // var s []T
Russ Cox175929b2015-03-02 14:22:05 -05002909 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002910 l = list(l, Nod(OAS, s, l1)) // s = l1
2911
Russ Cox382b44e2015-02-23 16:07:24 -05002912 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002913
Russ Cox382b44e2015-02-23 16:07:24 -05002914 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002915
2916 // n := len(s) + len(l2) - cap(s)
2917 nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
2918
Russ Cox66be1482015-05-26 21:30:20 -04002919 nif.Left = Nod(OGT, nt, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002920
Russ Cox32fddad2015-06-25 19:27:20 -04002921 // instantiate growslice_n(Type*, []any, int) []any
2922 fn := syslook("growslice_n", 1) // growslice_n(<type>, old []T, n int64) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002923 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002924
Russ Cox32fddad2015-06-25 19:27:20 -04002925 // s = growslice_n(T, s, n)
Matthew Dempsky81d40722015-02-27 15:13:05 +09002926 nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002927
2928 l = list(l, nif)
2929
2930 if haspointers(l1.Type.Type) {
2931 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002932 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 -05002933
2934 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002935 nptr2 := l2
2936 fn := syslook("typedslicecopy", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002937 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002938 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
Russ Cox8c195bd2015-02-13 14:40:36 -05002939 l = list(l, nt)
2940 } else if flag_race != 0 {
2941 // rely on runtime to instrument copy.
2942 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002943 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 -05002944
2945 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002946 nptr2 := l2
2947 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002948 if l2.Type.Etype == TSTRING {
2949 fn = syslook("slicestringcopy", 1)
2950 } else {
2951 fn = syslook("slicecopy", 1)
2952 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002953 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002954 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05002955 l = list(l, nt)
2956 } else {
2957 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002958 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002959
Russ Coxdc7b54b2015-02-17 22:13:49 -05002960 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002961 nptr1 = Nod(OADDR, nptr1, nil)
2962
Russ Cox382b44e2015-02-23 16:07:24 -05002963 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002964
Russ Cox382b44e2015-02-23 16:07:24 -05002965 fn := syslook("memmove", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002966 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002967
Russ Cox382b44e2015-02-23 16:07:24 -05002968 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
Russ Cox8c195bd2015-02-13 14:40:36 -05002969
2970 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Russ Cox382b44e2015-02-23 16:07:24 -05002971 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
Russ Cox8c195bd2015-02-13 14:40:36 -05002972 l = list(l, nt)
2973 }
2974
2975 // s = s[:len(l1)+len(l2)]
2976 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
2977
2978 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
2979 nt.Etype = 1
2980 l = list(l, Nod(OAS, s, nt))
2981
2982 typechecklist(l, Etop)
2983 walkstmtlist(l)
2984 *init = concat(*init, l)
2985 return s
2986}
2987
Russ Cox85520472015-05-06 12:34:30 -04002988// Rewrite append(src, x, y, z) so that any side effects in
2989// x, y, z (including runtime panics) are evaluated in
2990// initialization statements before the append.
2991// For normal code generation, stop there and leave the
2992// rest to cgen_append.
2993//
2994// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002995//
2996// init {
2997// s := src
2998// const argc = len(args) - 1
2999// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04003000// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003001// }
3002// n := len(s)
3003// s = s[:n+argc]
3004// s[n] = a
3005// s[n+1] = b
3006// ...
3007// }
3008// s
Russ Cox85520472015-05-06 12:34:30 -04003009func walkappend(n *Node, init **NodeList, dst *Node) *Node {
3010 if !samesafeexpr(dst, n.List.N) {
3011 l := n.List
3012 l.N = safeexpr(l.N, init)
3013 walkexpr(&l.N, init)
3014 }
3015 walkexprlistsafe(n.List.Next, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003016
3017 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
3018 // and n are name or literal, but those may index the slice we're
3019 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04003020 // Using cheapexpr also makes sure that the evaluation
3021 // of all arguments (and especially any panics) happen
3022 // before we begin to modify the slice in a visible way.
3023 for l := n.List.Next; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003024 l.N = cheapexpr(l.N, init)
3025 }
3026
Russ Cox382b44e2015-02-23 16:07:24 -05003027 nsrc := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -05003028
3029 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003030 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003031 nsrc.Type = nsrc.Type.Type.Type
3032 }
Russ Cox382b44e2015-02-23 16:07:24 -05003033 argc := count(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003034 if argc < 1 {
3035 return nsrc
3036 }
3037
Russ Cox85520472015-05-06 12:34:30 -04003038 // General case, with no function calls left as arguments.
3039 // Leave for gen, except that race detector requires old form
3040 if flag_race == 0 {
3041 return n
3042 }
3043
Russ Cox175929b2015-03-02 14:22:05 -05003044 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003045
Russ Cox382b44e2015-02-23 16:07:24 -05003046 ns := temp(nsrc.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003047 l = list(l, Nod(OAS, ns, nsrc)) // s = src
3048
Russ Cox382b44e2015-02-23 16:07:24 -05003049 na := Nodintconst(int64(argc)) // const argc
3050 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04003051 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05003052
Russ Cox32fddad2015-06-25 19:27:20 -04003053 fn := syslook("growslice", 1) // growslice(<type>, old []T, mincap int) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003054 substArgTypes(fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003055
Russ Cox32fddad2015-06-25 19:27:20 -04003056 nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05003057
3058 l = list(l, nx)
3059
Russ Cox382b44e2015-02-23 16:07:24 -05003060 nn := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003061 l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
3062
3063 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
3064 nx.Etype = 1
3065 l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
3066
Russ Cox382b44e2015-02-23 16:07:24 -05003067 for a := n.List.Next; a != nil; a = a.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003068 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003069 nx.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05003070 l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg
3071 if a.Next != nil {
3072 l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
3073 }
3074 }
3075
3076 typechecklist(l, Etop)
3077 walkstmtlist(l)
3078 *init = concat(*init, l)
3079 return ns
3080}
3081
3082// Lower copy(a, b) to a memmove call or a runtime call.
3083//
3084// init {
3085// n := len(a)
3086// if n > len(b) { n = len(b) }
3087// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3088// }
3089// n;
3090//
3091// Also works if b is a string.
3092//
3093func copyany(n *Node, init **NodeList, runtimecall int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003094 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05003095 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003096 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
3097 }
3098
3099 if runtimecall != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05003100 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003101 if n.Right.Type.Etype == TSTRING {
3102 fn = syslook("slicestringcopy", 1)
3103 } else {
3104 fn = syslook("slicecopy", 1)
3105 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04003106 substArgTypes(fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003107 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3108 }
3109
3110 walkexpr(&n.Left, init)
3111 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003112 nl := temp(n.Left.Type)
3113 nr := temp(n.Right.Type)
Russ Cox175929b2015-03-02 14:22:05 -05003114 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003115 l = list(l, Nod(OAS, nl, n.Left))
3116 l = list(l, Nod(OAS, nr, n.Right))
3117
Russ Cox382b44e2015-02-23 16:07:24 -05003118 nfrm := Nod(OSPTR, nr, nil)
3119 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003120
Russ Cox382b44e2015-02-23 16:07:24 -05003121 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003122
3123 // n = len(to)
3124 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
3125
3126 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003127 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003128
Russ Cox66be1482015-05-26 21:30:20 -04003129 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003130 nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
3131 l = list(l, nif)
3132
3133 // Call memmove.
Russ Cox382b44e2015-02-23 16:07:24 -05003134 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003135
Russ Cox13f9c8b2015-03-08 13:33:49 -04003136 substArgTypes(fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003137 nwid := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -05003138 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
3139 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
3140 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
3141
3142 typechecklist(l, Etop)
3143 walkstmtlist(l)
3144 *init = concat(*init, l)
3145 return nlen
3146}
3147
Russ Cox8c195bd2015-02-13 14:40:36 -05003148func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003149 // Should only arrive here with large memory or
3150 // a struct/array containing a non-memory field/element.
3151 // Small memory is handled inline, and single non-memory
3152 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003153 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003154
3155 if a != AMEM && a != -1 {
Russ Cox17228f42015-04-17 12:03:22 -04003156 Fatal("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003157 }
3158
3159 if a == AMEM {
Russ Cox382b44e2015-02-23 16:07:24 -05003160 n := syslook("memequal", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003161 substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003162 *needsize = 1
3163 return n
3164 }
3165
Russ Cox382b44e2015-02-23 16:07:24 -05003166 sym := typesymprefix(".eq", t)
3167 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003168 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003169 ntype := Nod(OTFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003170 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3171 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3172 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3173 typecheck(&ntype, Etype)
3174 n.Type = ntype.Type
3175 *needsize = 0
3176 return n
3177}
3178
3179func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003180 n := 0
3181 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003182 n++
3183 }
3184 return n
3185}
3186
3187func walkcompare(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003188 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003189
3190 // Given interface value l and concrete value r, rewrite
3191 // l == r
3192 // to
3193 // x, ok := l.(type(r)); ok && x == r
3194 // Handle != similarly.
3195 // This avoids the allocation that would be required
3196 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003197 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003198
Russ Cox175929b2015-03-02 14:22:05 -05003199 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003200 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 l = n.Left
3202 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003203 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003204 l = n.Right
3205 r = n.Left
3206 }
3207
3208 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003209 x := temp(r.Type)
3210 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003211
3212 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003213 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003214
3215 a.Type = r.Type
3216
3217 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003218 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003219
3220 expr.List = list1(x)
3221 expr.List = list(expr.List, ok)
3222 expr.Rlist = list1(a)
3223 typecheck(&expr, Etop)
3224 walkexpr(&expr, init)
3225
3226 if n.Op == OEQ {
3227 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3228 } else {
3229 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3230 }
3231 *init = list(*init, expr)
Russ Cox44928112015-03-02 20:34:22 -05003232 finishcompare(np, n, r, init)
3233 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003234 }
3235
3236 // Must be comparison of array or struct.
3237 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003238 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003239
3240 switch t.Etype {
3241 default:
3242 return
3243
3244 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003245 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003246 return
3247 }
3248
3249 case TSTRUCT:
3250 break
3251 }
3252
Russ Cox44928112015-03-02 20:34:22 -05003253 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003254 for cmpl != nil && cmpl.Op == OCONVNOP {
3255 cmpl = cmpl.Left
3256 }
Russ Cox44928112015-03-02 20:34:22 -05003257 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003258 for cmpr != nil && cmpr.Op == OCONVNOP {
3259 cmpr = cmpr.Left
3260 }
3261
Russ Coxdc7b54b2015-02-17 22:13:49 -05003262 if !islvalue(cmpl) || !islvalue(cmpr) {
Russ Cox17228f42015-04-17 12:03:22 -04003263 Fatal("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003264 }
3265
3266 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003267 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003268 a.Right.Etype = 1 // addr does not escape
3269 typecheck(&a, Etop)
3270 *init = list(*init, a)
3271
3272 r = temp(Ptrto(t))
3273 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3274 a.Right.Etype = 1 // addr does not escape
3275 typecheck(&a, Etop)
3276 *init = list(*init, a)
3277
Russ Cox44928112015-03-02 20:34:22 -05003278 andor := OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003279 if n.Op == ONE {
3280 andor = OOROR
3281 }
3282
Russ Cox44928112015-03-02 20:34:22 -05003283 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003284 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003285 // Four or fewer elements of a basic type.
3286 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003287 var li *Node
3288 var ri *Node
3289 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003290 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3291 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
3292 a = Nod(int(n.Op), li, ri)
3293 if expr == nil {
3294 expr = a
3295 } else {
3296 expr = Nod(andor, expr, a)
3297 }
3298 }
3299
3300 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003301 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003302 }
Russ Cox44928112015-03-02 20:34:22 -05003303 finishcompare(np, n, expr, init)
3304 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003305 }
3306
3307 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3308 // Struct of four or fewer fields.
3309 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003310 var li *Node
3311 var ri *Node
3312 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003313 if isblanksym(t1.Sym) {
3314 continue
3315 }
3316 li = Nod(OXDOT, l, newname(t1.Sym))
3317 ri = Nod(OXDOT, r, newname(t1.Sym))
3318 a = Nod(int(n.Op), li, ri)
3319 if expr == nil {
3320 expr = a
3321 } else {
3322 expr = Nod(andor, expr, a)
3323 }
3324 }
3325
3326 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003327 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003328 }
Russ Cox44928112015-03-02 20:34:22 -05003329 finishcompare(np, n, expr, init)
3330 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003331 }
3332
3333 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003334 var needsize int
3335 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003336
3337 call.List = list(call.List, l)
3338 call.List = list(call.List, r)
3339 if needsize != 0 {
3340 call.List = list(call.List, Nodintconst(t.Width))
3341 }
3342 r = call
3343 if n.Op != OEQ {
3344 r = Nod(ONOT, r, nil)
3345 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003346
Russ Cox44928112015-03-02 20:34:22 -05003347 finishcompare(np, n, r, init)
3348 return
3349}
3350
3351func finishcompare(np **Node, n, r *Node, init **NodeList) {
3352 // Using np here to avoid passing &r to typecheck.
3353 *np = r
3354 typecheck(np, Erv)
3355 walkexpr(np, init)
3356 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003357 if r.Type != n.Type {
3358 r = Nod(OCONVNOP, r, nil)
3359 r.Type = n.Type
3360 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003361 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003362 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003363}
3364
Russ Coxdc7b54b2015-02-17 22:13:49 -05003365func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003366 var ar *Node
3367 var br *Node
3368 for a != nil && b != nil && a.Op == b.Op {
3369 switch a.Op {
3370 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003371 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003372
3373 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003374 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003375
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003376 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003377 ar = a.Right
3378 br = b.Right
3379 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003380 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003381 }
3382
3383 case OINDEX:
3384 ar = a.Right
3385 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003386 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003387 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003388 }
3389 }
3390
3391 a = a.Left
3392 b = b.Left
3393 }
3394
Russ Coxdc7b54b2015-02-17 22:13:49 -05003395 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003396}
3397
3398func walkrotate(np **Node) {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +01003399 if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003400 return
3401 }
3402
Russ Cox382b44e2015-02-23 16:07:24 -05003403 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003404
3405 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003406 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003407
Russ Cox382b44e2015-02-23 16:07:24 -05003408 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003409 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 -05003410 return
3411 }
3412
3413 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003414 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003415 return
3416 }
3417
3418 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003419 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003420
Russ Coxdc7b54b2015-02-17 22:13:49 -05003421 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003422 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003423 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003424 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003425 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003426 // Rewrite left shift half to left rotate.
3427 if l.Op == OLSH {
3428 n = l
3429 } else {
3430 n = r
3431 }
3432 n.Op = OLROT
3433
3434 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003435 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003436
3437 if s == 0 || s == w {
3438 n = n.Left
3439 }
3440
3441 *np = n
3442 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003443 }
3444 }
3445 return
3446 }
3447
3448 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3449 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003450}
3451
3452/*
3453 * walkmul rewrites integer multiplication by powers of two as shifts.
3454 */
3455func walkmul(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003456 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003457 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003458 return
3459 }
3460
Russ Cox382b44e2015-02-23 16:07:24 -05003461 var nr *Node
3462 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003463 if n.Right.Op == OLITERAL {
3464 nl = n.Left
3465 nr = n.Right
3466 } else if n.Left.Op == OLITERAL {
3467 nl = n.Right
3468 nr = n.Left
3469 } else {
3470 return
3471 }
3472
Russ Cox382b44e2015-02-23 16:07:24 -05003473 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003474
3475 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003476 var pow int
3477 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003478 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003479 cheapexpr(nl, init)
3480 Nodconst(n, n.Type, 0)
3481 goto ret
3482 }
3483
3484 // nr is a constant.
3485 pow = powtwo(nr)
3486
3487 if pow < 0 {
3488 return
3489 }
3490 if pow >= 1000 {
3491 // negative power of 2, like -16
3492 neg = 1
3493
3494 pow -= 1000
3495 }
3496
3497 w = int(nl.Type.Width * 8)
3498 if pow+1 >= w { // too big, shouldn't happen
3499 return
3500 }
3501
3502 nl = cheapexpr(nl, init)
3503
3504 if pow == 0 {
3505 // x*1 is x
3506 n = nl
3507
3508 goto ret
3509 }
3510
3511 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3512
3513ret:
3514 if neg != 0 {
3515 n = Nod(OMINUS, n, nil)
3516 }
3517
3518 typecheck(&n, Erv)
3519 walkexpr(&n, init)
3520 *np = n
3521}
3522
3523/*
3524 * walkdiv rewrites division by a constant as less expensive
3525 * operations.
3526 */
3527func walkdiv(np **Node, init **NodeList) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003528 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003529
3530 // TODO(minux)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +01003531 if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003532 return
3533 }
3534
Russ Cox382b44e2015-02-23 16:07:24 -05003535 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003536 if n.Right.Op != OLITERAL {
3537 return
3538 }
3539
3540 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003541 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003542
Russ Cox382b44e2015-02-23 16:07:24 -05003543 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003544
3545 // special cases of mod/div
3546 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003547 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003548
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003549 s := 0 // 1 if nr is negative.
3550 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003551 if pow >= 1000 {
3552 // negative power of 2
3553 s = 1
3554
3555 pow -= 1000
3556 }
3557
3558 if pow+1 >= w {
3559 // divisor too large.
3560 return
3561 }
3562
3563 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003564 // try to do division by multiply by (2^w)/d
3565 // see hacker's delight chapter 10
3566 // TODO: support 64-bit magic multiply here.
3567 var m Magic
3568 m.W = w
3569
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003570 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003571 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003572 Smagic(&m)
3573 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003574 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003575 Umagic(&m)
3576 }
3577
3578 if m.Bad != 0 {
3579 return
3580 }
3581
3582 // We have a quick division method so use it
3583 // for modulo too.
3584 if n.Op == OMOD {
3585 // rewrite as A%B = A - (A/B*B).
3586 n1 := Nod(ODIV, nl, nr)
3587
3588 n2 := Nod(OMUL, n1, nr)
3589 n = Nod(OSUB, nl, n2)
3590 goto ret
3591 }
3592
3593 switch Simtype[nl.Type.Etype] {
3594 default:
3595 return
3596
3597 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003598 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003599 nc := Nod(OXXX, nil, nil)
3600
3601 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003602 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003603 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003604 if m.Ua != 0 {
3605 // Select a Go type with (at least) twice the width.
3606 var twide *Type
3607 switch Simtype[nl.Type.Etype] {
3608 default:
3609 return
3610
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003611 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003612 twide = Types[TUINT32]
3613
3614 case TUINT32:
3615 twide = Types[TUINT64]
3616
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003617 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003618 twide = Types[TINT32]
3619
3620 case TINT32:
3621 twide = Types[TINT64]
3622 }
3623
3624 // add numerator (might overflow).
3625 // n2 = (n1 + nl)
3626 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3627
3628 // shift by m.s
3629 nc := Nod(OXXX, nil, nil)
3630
3631 Nodconst(nc, Types[TUINT], int64(m.S))
3632 n = conv(Nod(ORSH, n2, nc), nl.Type)
3633 } else {
3634 // n = n1 >> m.s
3635 nc := Nod(OXXX, nil, nil)
3636
3637 Nodconst(nc, Types[TUINT], int64(m.S))
3638 n = Nod(ORSH, n1, nc)
3639 }
3640
3641 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003642 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003643 nc := Nod(OXXX, nil, nil)
3644
3645 Nodconst(nc, nl.Type, m.Sm)
Todd Neal765c0f32015-06-23 18:59:52 -05003646 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003647 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003648 if m.Sm < 0 {
3649 // add the numerator.
3650 n1 = Nod(OADD, n1, nl)
3651 }
3652
3653 // shift by m.s
3654 nc = Nod(OXXX, nil, nil)
3655
3656 Nodconst(nc, Types[TUINT], int64(m.S))
3657 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3658
3659 // add 1 iff n1 is negative.
3660 nc = Nod(OXXX, nil, nil)
3661
3662 Nodconst(nc, Types[TUINT], int64(w)-1)
3663 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3664 n = Nod(OSUB, n2, n3)
3665
3666 // apply sign.
3667 if m.Sd < 0 {
3668 n = Nod(OMINUS, n, nil)
3669 }
3670 }
3671
3672 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003673 }
3674
3675 switch pow {
3676 case 0:
3677 if n.Op == OMOD {
3678 // nl % 1 is zero.
3679 Nodconst(n, n.Type, 0)
3680 } else if s != 0 {
3681 // divide by -1
3682 n.Op = OMINUS
3683
3684 n.Right = nil
3685 } else {
3686 // divide by 1
3687 n = nl
3688 }
3689
3690 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003691 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003692 if n.Op == OMOD {
3693 // signed modulo 2^pow is like ANDing
3694 // with the last pow bits, but if nl < 0,
3695 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003696 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003697
3698 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003699 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003700 if pow == 1 {
3701 typecheck(&n1, Erv)
3702 n1 = cheapexpr(n1, init)
3703
3704 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003705 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003706
Russ Cox382b44e2015-02-23 16:07:24 -05003707 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003708 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003709 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003710 n = Nod(OADD, n3, n1)
3711 } else {
3712 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003713 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003714
3715 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003716 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003717 typecheck(&n2, Erv)
3718 n2 = cheapexpr(n2, init)
3719
Russ Cox382b44e2015-02-23 16:07:24 -05003720 n3 := Nod(OADD, nl, n2)
3721 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003722 n = Nod(OSUB, n4, n2)
3723 }
3724
3725 break
3726 } else {
3727 // arithmetic right shift does not give the correct rounding.
3728 // if nl >= 0, nl >> n == nl / nr
3729 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003730 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003731
3732 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003733 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003734 if pow == 1 {
3735 // nl+1 is nl-(-1)
3736 n.Left = Nod(OSUB, nl, n1)
3737 } else {
3738 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003739 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003740
3741 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003742 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003743 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3744 }
3745
3746 // n = (nl + 2^pow-1) >> pow
3747 n.Op = ORSH
3748
3749 nc = Nod(OXXX, nil, nil)
3750 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3751 n.Right = nc
3752 n.Typecheck = 0
3753 }
3754
3755 if s != 0 {
3756 n = Nod(OMINUS, n, nil)
3757 }
3758 break
3759 }
3760
Russ Cox382b44e2015-02-23 16:07:24 -05003761 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003762 if n.Op == OMOD {
3763 // n = nl & (nr-1)
3764 n.Op = OAND
3765
Russ Cox81d58102015-05-27 00:47:05 -04003766 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003767 } else {
3768 // n = nl >> pow
3769 n.Op = ORSH
3770
3771 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3772 }
3773
3774 n.Typecheck = 0
3775 n.Right = nc
3776 }
3777
3778 goto ret
3779
Russ Cox8c195bd2015-02-13 14:40:36 -05003780ret:
3781 typecheck(&n, Erv)
3782 walkexpr(&n, init)
3783 *np = n
3784}
3785
3786// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003787func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003788 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003789 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003790 }
3791
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003792 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003793 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003794
Russ Coxdc7b54b2015-02-17 22:13:49 -05003795 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003796 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003797 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003798 }
3799
3800 switch n.Op {
3801 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003802 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003803 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003804 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003805 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003806 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003807 }
3808
3809 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003810 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 }
3812
3813 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003814 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003815 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003816 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003817 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003818 }
3819 }
3820
3821 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003822 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003823 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003824 for bits > 0 && v >= 2 {
3825 bits--
3826 v >>= 1
3827 }
3828 }
3829
3830 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003831 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003832 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003833 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003834 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003835 }
3836 bits -= int32(v)
3837 }
3838 }
3839
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003840 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003841 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003842 }
3843
Russ Coxdc7b54b2015-02-17 22:13:49 -05003844 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003845}
3846
3847func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003848 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003849 return
3850 }
3851
3852 switch n.Op {
3853 default:
3854 Fatal("usefield %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003855
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003856 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003857 break
3858 }
3859
Russ Cox496ad0a2015-05-26 21:49:31 -04003860 t := n.Left.Type
3861 if Isptr[t.Etype] {
3862 t = t.Type
3863 }
3864 field := dotField[typeSym{t, n.Right.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003865 if field == nil {
Russ Cox17228f42015-04-17 12:03:22 -04003866 Fatal("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003867 }
Russ Coxbed1f902015-03-02 16:03:26 -05003868 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003869 return
3870 }
3871
3872 // dedup on list
3873 if field.Lastfn == Curfn {
3874 return
3875 }
3876 field.Lastfn = Curfn
3877 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003878 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003879 field.Outer = field.Outer.Type
3880 }
3881 if field.Outer.Sym == nil {
3882 Yyerror("tracked field must be in named struct type")
3883 }
3884 if !exportname(field.Sym.Name) {
3885 Yyerror("tracked field must be exported (upper case)")
3886 }
3887
Russ Cox496ad0a2015-05-26 21:49:31 -04003888 Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
Russ Cox8c195bd2015-02-13 14:40:36 -05003889}
3890
Russ Coxdc7b54b2015-02-17 22:13:49 -05003891func candiscardlist(l *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003892 for ; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003893 if !candiscard(l.N) {
3894 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003895 }
3896 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003897 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003898}
3899
Russ Coxdc7b54b2015-02-17 22:13:49 -05003900func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003901 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003902 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003903 }
3904
3905 switch n.Op {
3906 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003907 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003908
3909 // Discardable as long as the subpieces are.
3910 case ONAME,
3911 ONONAME,
3912 OTYPE,
3913 OPACK,
3914 OLITERAL,
3915 OADD,
3916 OSUB,
3917 OOR,
3918 OXOR,
3919 OADDSTR,
3920 OADDR,
3921 OANDAND,
3922 OARRAYBYTESTR,
3923 OARRAYRUNESTR,
3924 OSTRARRAYBYTE,
3925 OSTRARRAYRUNE,
3926 OCAP,
3927 OCMPIFACE,
3928 OCMPSTR,
3929 OCOMPLIT,
3930 OMAPLIT,
3931 OSTRUCTLIT,
3932 OARRAYLIT,
3933 OPTRLIT,
3934 OCONV,
3935 OCONVIFACE,
3936 OCONVNOP,
3937 ODOT,
3938 OEQ,
3939 ONE,
3940 OLT,
3941 OLE,
3942 OGT,
3943 OGE,
3944 OKEY,
3945 OLEN,
3946 OMUL,
3947 OLSH,
3948 ORSH,
3949 OAND,
3950 OANDNOT,
3951 ONEW,
3952 ONOT,
3953 OCOM,
3954 OPLUS,
3955 OMINUS,
3956 OOROR,
3957 OPAREN,
3958 ORUNESTR,
3959 OREAL,
3960 OIMAG,
3961 OCOMPLEX:
3962 break
3963
3964 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003965 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003966 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003967 break
3968 }
Russ Cox81d58102015-05-27 00:47:05 -04003969 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003970 break
3971 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003972 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003973
3974 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003975 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003976 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003977 break
3978 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003979 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003980
3981 // Difficult to tell what sizes are okay.
3982 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003983 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003984 }
3985
Russ Cox66be1482015-05-26 21:30:20 -04003986 if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003987 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003988 }
3989
Russ Coxdc7b54b2015-02-17 22:13:49 -05003990 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003991}
3992
3993// rewrite
3994// print(x, y, z)
3995// into
3996// func(a1, a2, a3) {
3997// print(a1, a2, a3)
3998// }(x, y, z)
3999// and same for println.
4000
4001var walkprintfunc_prgen int
4002
4003func walkprintfunc(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05004004 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05004005
4006 if n.Ninit != nil {
4007 walkstmtlist(n.Ninit)
4008 *init = concat(*init, n.Ninit)
4009 n.Ninit = nil
4010 }
4011
Russ Cox382b44e2015-02-23 16:07:24 -05004012 t := Nod(OTFUNC, nil, nil)
4013 num := 0
Russ Cox175929b2015-03-02 14:22:05 -05004014 var printargs *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05004015 var a *Node
4016 var buf string
4017 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05004018 buf = fmt.Sprintf("a%d", num)
4019 num++
4020 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
4021 t.List = list(t.List, a)
4022 printargs = list(printargs, a.Left)
4023 }
4024
Russ Cox382b44e2015-02-23 16:07:24 -05004025 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004026 walkprintfunc_prgen++
4027 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04004028 fn.Func.Nname = newname(Lookup(buf))
4029 fn.Func.Nname.Name.Defn = fn
4030 fn.Func.Nname.Name.Param.Ntype = t
4031 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05004032
Russ Cox382b44e2015-02-23 16:07:24 -05004033 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004034 Curfn = nil
4035 funchdr(fn)
4036
4037 a = Nod(int(n.Op), nil, nil)
4038 a.List = printargs
4039 typecheck(&a, Etop)
4040 walkstmt(&a)
4041
4042 fn.Nbody = list1(a)
4043
4044 funcbody(fn)
4045
4046 typecheck(&fn, Etop)
4047 typechecklist(fn.Nbody, Etop)
4048 xtop = list(xtop, fn)
4049 Curfn = oldfn
4050
4051 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004052 a.Left = fn.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -05004053 a.List = n.List
4054 typecheck(&a, Etop)
4055 walkexpr(&a, init)
4056 *np = a
4057}