blob: 09888f8b9e6740b71e5b492ffc42620f70750819 [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.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080032 for i, ln := range fn.Func.Dcl {
33 if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
34 typecheck(&ln, Erv|Easgn)
35 fn.Func.Dcl[i] = ln
Russ Cox8c195bd2015-02-13 14:40:36 -050036 }
37 }
38
39 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080040 for _, ln := range fn.Func.Dcl {
41 if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
42 ln.Name.Defn.Left.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -050043 }
44 }
45
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080046 for _, ln := range fn.Func.Dcl {
47 if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050048 continue
49 }
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080050 if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
Russ Cox4fdd5362015-05-26 22:19:27 -040051 if defn.Left.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050052 continue
53 }
Russ Cox4fdd5362015-05-26 22:19:27 -040054 lineno = defn.Left.Lineno
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080055 Yyerror("%v declared and not used", ln.Sym)
Russ Cox4fdd5362015-05-26 22:19:27 -040056 defn.Left.Used = true // suppress repeats
Russ Cox8c195bd2015-02-13 14:40:36 -050057 } else {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080058 lineno = ln.Lineno
59 Yyerror("%v declared and not used", ln.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050060 }
61 }
62
63 lineno = int32(lno)
64 if nerrors != 0 {
65 return
66 }
67 walkstmtlist(Curfn.Nbody)
68 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040069 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050070 dumplist(s, Curfn.Nbody)
71 }
72
73 heapmoves()
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080074 if Debug['W'] != 0 && len(Curfn.Func.Enter.Slice()) > 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040075 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080076 dumpslice(s, Curfn.Func.Enter.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -050077 }
78}
79
80func walkstmtlist(l *NodeList) {
81 for ; l != nil; l = l.Next {
82 walkstmt(&l.N)
83 }
84}
85
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080086func walkstmtslice(l []*Node) {
87 for i := range l {
88 walkstmt(&l[i])
89 }
90}
91
Russ Coxdc7b54b2015-02-17 22:13:49 -050092func samelist(a *NodeList, b *NodeList) bool {
Russ Coxd7f6d462015-03-09 00:31:13 -040093 for ; a != nil && b != nil; a, b = a.Next, b.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050094 if a.N != b.N {
Russ Coxdc7b54b2015-02-17 22:13:49 -050095 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050096 }
97 }
Russ Coxdc7b54b2015-02-17 22:13:49 -050098 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -050099}
100
Dave Cheneyb006d382015-03-06 18:42:58 +1100101func paramoutheap(fn *Node) bool {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800102 for _, ln := range fn.Func.Dcl {
103 switch ln.Class {
Russ Cox8c195bd2015-02-13 14:40:36 -0500104 case PPARAMOUT,
105 PPARAMOUT | PHEAP:
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800106 return ln.Addrtaken
Russ Cox8c195bd2015-02-13 14:40:36 -0500107
108 // stop early - parameters are over
109 case PAUTO,
110 PAUTO | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +1100111 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500112 }
113 }
114
Dave Cheneyb006d382015-03-06 18:42:58 +1100115 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500116}
117
118// adds "adjust" to all the argument locations for the call n.
119// n must be a defer or go node that has already been walked.
120func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500121 var arg *Node
122 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500123
Russ Cox382b44e2015-02-23 16:07:24 -0500124 callfunc := n.Left
125 for args := callfunc.List; args != nil; args = args.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500126 arg = args.N
127 if arg.Op != OAS {
128 Yyerror("call arg not assignment")
129 }
130 lhs = arg.Left
131 if lhs.Op == ONAME {
132 // This is a temporary introduced by reorder1.
133 // The real store to the stack appears later in the arg list.
134 continue
135 }
136
137 if lhs.Op != OINDREG {
138 Yyerror("call argument store does not use OINDREG")
139 }
140
141 // can't really check this in machine-indep code.
142 //if(lhs->val.u.reg != D_SP)
143 // yyerror("call arg assign not indreg(SP)");
144 lhs.Xoffset += int64(adjust)
145 }
146}
147
148func walkstmt(np **Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500149 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500150 if n == nil {
151 return
152 }
153 if n.Dodata == 2 { // don't walk, generated by anylit.
154 return
155 }
156
157 setlineno(n)
158
159 walkstmtlist(n.Ninit)
160
161 switch n.Op {
162 default:
163 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400164 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500165 } else {
166 Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0))
167 }
168 Dump("nottop", n)
169
170 case OAS,
171 OASOP,
172 OAS2,
173 OAS2DOTTYPE,
174 OAS2RECV,
175 OAS2FUNC,
176 OAS2MAPR,
177 OCLOSE,
178 OCOPY,
179 OCALLMETH,
180 OCALLINTER,
181 OCALL,
182 OCALLFUNC,
183 ODELETE,
184 OSEND,
185 OPRINT,
186 OPRINTN,
187 OPANIC,
188 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400189 ORECOVER,
190 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500191 if n.Typecheck == 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200192 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500193 }
Russ Cox382b44e2015-02-23 16:07:24 -0500194 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 n.Ninit = nil
196 walkexpr(&n, &init)
197 addinit(&n, init)
198 if (*np).Op == OCOPY && n.Op == OCONVNOP {
199 n.Op = OEMPTY // don't leave plain values as statements.
200 }
201
202 // special case for a receive where we throw away
203 // the value received.
204 case ORECV:
205 if n.Typecheck == 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200206 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500207 }
Russ Cox382b44e2015-02-23 16:07:24 -0500208 init := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500209 n.Ninit = nil
210
211 walkexpr(&n.Left, &init)
212 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
213 walkexpr(&n, &init)
214
215 addinit(&n, init)
216
217 case OBREAK,
218 ODCL,
219 OCONTINUE,
220 OFALL,
221 OGOTO,
222 OLABEL,
223 ODCLCONST,
224 ODCLTYPE,
225 OCHECKNIL,
Russ Cox1ac637c2016-01-13 00:46:28 -0500226 OVARKILL,
227 OVARLIVE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500228 break
229
230 case OBLOCK:
231 walkstmtlist(n.List)
232
233 case OXCASE:
234 Yyerror("case statement out of place")
235 n.Op = OCASE
236 fallthrough
237
238 case OCASE:
239 walkstmt(&n.Right)
240
241 case ODEFER:
HĂ¥vard Haugen25946642015-09-07 22:19:30 +0200242 hasdefer = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500243 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700244 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500245 walkprintfunc(&n.Left, &n.Ninit)
246
247 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700248 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500249
250 default:
251 walkexpr(&n.Left, &n.Ninit)
252 }
253
254 // make room for size & fn arguments.
255 adjustargs(n, 2*Widthptr)
256
257 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400258 if n.Left != nil {
259 walkstmtlist(n.Left.Ninit)
260 init := n.Left.Ninit
261 n.Left.Ninit = nil
262 walkexpr(&n.Left, &init)
263 addinit(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500264 }
265
Russ Coxffef1802015-05-22 01:16:52 -0400266 walkstmt(&n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500267 walkstmtlist(n.Nbody)
268
269 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400270 walkexpr(&n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500271 walkstmtlist(n.Nbody)
Russ Coxffef1802015-05-22 01:16:52 -0400272 walkstmtlist(n.Rlist)
Russ Cox8c195bd2015-02-13 14:40:36 -0500273
274 case OPROC:
275 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700276 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500277 walkprintfunc(&n.Left, &n.Ninit)
278
279 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700280 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500281
282 default:
283 walkexpr(&n.Left, &n.Ninit)
284 }
285
286 // make room for size & fn arguments.
287 adjustargs(n, 2*Widthptr)
288
289 case ORETURN:
290 walkexprlist(n.List, &n.Ninit)
291 if n.List == nil {
292 break
293 }
Marvin Stenger9ac0fff2015-09-08 03:51:30 +0200294 if (Curfn.Type.Outnamed && count(n.List) > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500295 // assign to the function out parameters,
296 // so that reorder3 can fix up conflicts
Russ Cox175929b2015-03-02 14:22:05 -0500297 var rl *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500298
Robert Griesemercd7d7382015-10-26 14:57:36 -0700299 var cl Class
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800300 for _, ln := range Curfn.Func.Dcl {
301 cl = ln.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500302 if cl == PAUTO {
303 break
304 }
305 if cl == PPARAMOUT {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800306 rl = list(rl, ln)
Russ Cox8c195bd2015-02-13 14:40:36 -0500307 }
308 }
309
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800310 if got, want := count(n.List), count(rl); got != want {
311 // order should have rewritten multi-value function calls
312 // with explicit OAS2FUNC nodes.
313 Fatalf("expected %v return arguments, have %v", want, got)
314 }
315
Russ Coxdc7b54b2015-02-17 22:13:49 -0500316 if samelist(rl, n.List) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500317 // special return in disguise
318 n.List = nil
319
320 break
321 }
322
Russ Cox8c195bd2015-02-13 14:40:36 -0500323 // move function calls out, to make reorder3's job easier.
324 walkexprlistsafe(n.List, &n.Ninit)
325
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200326 ll := ascompatee(n.Op, rl, n.List, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500327 n.List = reorder3(ll)
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800328 for lr := n.List; lr != nil; lr = lr.Next {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800329 lr.N = applywritebarrier(lr.N)
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800330 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500331 break
332 }
333
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200334 ll := ascompatte(n.Op, nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500335 n.List = ll
336
337 case ORETJMP:
338 break
339
340 case OSELECT:
341 walkselect(n)
342
343 case OSWITCH:
344 walkswitch(n)
345
346 case ORANGE:
347 walkrange(n)
348
349 case OXFALL:
350 Yyerror("fallthrough statement out of place")
351 n.Op = OFALL
352 }
353
354 if n.Op == ONAME {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200355 Fatalf("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500356 }
357
358 *np = n
359}
360
David Chasee5060c72015-05-20 15:16:34 -0400361func isSmallMakeSlice(n *Node) bool {
362 if n.Op != OMAKESLICE {
363 return false
364 }
365 l := n.Left
366 r := n.Right
367 if r == nil {
368 r = l
369 }
370 t := n.Type
371
Russ Cox81d58102015-05-27 00:47:05 -0400372 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 -0400373}
374
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900375// walk the whole tree of the body of an
376// expression or simple statement.
377// the types expressions are calculated.
378// compile-time constants are evaluated.
379// complex side effects like statements are appended to init
Russ Cox8c195bd2015-02-13 14:40:36 -0500380func walkexprlist(l *NodeList, init **NodeList) {
381 for ; l != nil; l = l.Next {
382 walkexpr(&l.N, init)
383 }
384}
385
386func walkexprlistsafe(l *NodeList, init **NodeList) {
387 for ; l != nil; l = l.Next {
388 l.N = safeexpr(l.N, init)
389 walkexpr(&l.N, init)
390 }
391}
392
393func walkexprlistcheap(l *NodeList, init **NodeList) {
394 for ; l != nil; l = l.Next {
395 l.N = cheapexpr(l.N, init)
396 walkexpr(&l.N, init)
397 }
398}
399
400func walkexpr(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -0500401 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500402
403 if n == nil {
404 return
405 }
406
407 if init == &n.Ninit {
408 // not okay to use n->ninit when walking n,
409 // because we might replace n with some other node
410 // and would lose the init list.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200411 Fatalf("walkexpr init == &n->ninit")
Russ Cox8c195bd2015-02-13 14:40:36 -0500412 }
413
414 if n.Ninit != nil {
415 walkstmtlist(n.Ninit)
416 *init = concat(*init, n.Ninit)
417 n.Ninit = nil
418 }
419
420 // annoying case - not typechecked
421 if n.Op == OKEY {
422 walkexpr(&n.Left, init)
423 walkexpr(&n.Right, init)
424 return
425 }
426
Russ Cox382b44e2015-02-23 16:07:24 -0500427 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500428
429 if Debug['w'] > 1 {
430 Dump("walk-before", n)
431 }
432
433 if n.Typecheck != 1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200434 Fatalf("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500435 }
436
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200437opswitch:
Russ Cox8c195bd2015-02-13 14:40:36 -0500438 switch n.Op {
439 default:
440 Dump("walk", n)
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200441 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500442
443 case OTYPE,
444 ONONAME,
445 OINDREG,
446 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400447 OPARAM,
448 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500449
450 case ONOT,
451 OMINUS,
452 OPLUS,
453 OCOM,
454 OREAL,
455 OIMAG,
456 ODOTMETH,
457 ODOTINTER:
458 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500459
460 case OIND:
461 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500462
463 case ODOT:
464 usefield(n)
465 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500466
467 case ODOTPTR:
468 usefield(n)
469 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
470 // No actual copy will be generated, so emit an explicit nil check.
471 n.Left = cheapexpr(n.Left, init)
472
473 checknil(n.Left, init)
474 }
475
476 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500477
478 case OEFACE:
479 walkexpr(&n.Left, init)
480 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500481
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700482 case OSPTR, OITAB:
Russ Cox8c195bd2015-02-13 14:40:36 -0500483 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500484
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700485 case OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500486 walkexpr(&n.Left, init)
487
488 // replace len(*[10]int) with 10.
489 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500490 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500491
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000492 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500493 t = t.Type
494 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500495 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500496 safeexpr(n.Left, init)
497 Nodconst(n, n.Type, t.Bound)
498 n.Typecheck = 1
499 }
500
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700501 case OLSH, ORSH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500502 walkexpr(&n.Left, init)
503 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500504 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500505 n.Bounded = bounded(n.Right, 8*t.Width)
506 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500507 Warn("shift bounds check elided")
508 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500509
510 // Use results from call expression as arguments for complex.
511 case OAND,
512 OSUB,
513 OHMUL,
514 OLT,
515 OLE,
516 OGE,
517 OGT,
518 OADD,
519 OCOMPLEX,
520 OLROT:
521 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
522 n.Left = n.List.N
523 n.Right = n.List.Next.N
524 }
525
526 walkexpr(&n.Left, init)
527 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500528
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700529 case OOR, OXOR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500530 walkexpr(&n.Left, init)
531 walkexpr(&n.Right, init)
532 walkrotate(&n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500533
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700534 case OEQ, ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500535 walkexpr(&n.Left, init)
536 walkexpr(&n.Right, init)
537
538 // Disable safemode while compiling this code: the code we
539 // generate internally can refer to unsafe.Pointer.
540 // In this case it can happen if we need to generate an ==
541 // for a struct containing a reflect.Value, which itself has
542 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500543 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500544
545 safemode = 0
546 walkcompare(&n, init)
547 safemode = old_safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500548
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700549 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500550 walkexpr(&n.Left, init)
551
David Chaseffe7fbf2015-03-27 12:34:45 -0400552 // cannot put side effects from n.Right on init,
553 // because they cannot run before n.Left is checked.
554 // save elsewhere and store on the eventual n.Right.
Russ Cox175929b2015-03-02 14:22:05 -0500555 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500556
557 walkexpr(&n.Right, &ll)
558 addinit(&n.Right, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500559
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700560 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500561 walkexprlist(n.List, init)
562 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500563
564 case OPANIC:
565 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500566
567 case ORECOVER:
568 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500569
570 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700571 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500572
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700573 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700574 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500575
576 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500577 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700578 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500579 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500580
581 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500582 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500583 if n.List != nil && n.List.N.Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200584 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500585 }
586 walkexpr(&n.Left, init)
587 walkexprlist(n.List, init)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200588 ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500589 n.List = reorder1(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500590
591 case OCALLFUNC:
592 if n.Left.Op == OCLOSURE {
593 // Transform direct call of a closure to call of a normal function.
594 // transformclosure already did all preparation work.
595
David Chase731dcda2015-07-23 14:17:07 -0400596 // Prepend captured variables to argument list.
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800597 n.List = concat(n.Left.Func.Enter.NodeList(), n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500598
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800599 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500600
601 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400602 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500603
604 // Update type of OCALLFUNC node.
605 // Output arguments had not changed, but their offsets could.
606 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500607 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500608 if t.Etype == TFIELD {
609 t = t.Type
610 }
611 n.Type = t
612 } else {
613 n.Type = getoutargx(n.Left.Type)
614 }
615 }
616
Russ Cox382b44e2015-02-23 16:07:24 -0500617 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500618 if n.List != nil && n.List.N.Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200619 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500620 }
621
622 walkexpr(&n.Left, init)
623 walkexprlist(n.List, init)
624
Russ Cox92dba0d2015-04-01 16:02:34 -0400625 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
626 switch Thearch.Thechar {
Shenghou Ma764c7512015-04-03 18:15:26 -0400627 case '5', '6', '7':
Russ Cox92dba0d2015-04-01 16:02:34 -0400628 n.Op = OSQRT
629 n.Left = n.List.N
630 n.List = nil
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200631 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400632 }
633 }
634
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200635 ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500636 n.List = reorder1(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500637
638 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500639 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500640 if n.List != nil && n.List.N.Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200641 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500642 }
643 walkexpr(&n.Left, init)
644 walkexprlist(n.List, init)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200645 ll := ascompatte(n.Op, n, false, getthis(t), list1(n.Left.Left), 0, init)
646 lr := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500647 ll = concat(ll, lr)
648 n.Left.Left = nil
649 ullmancalc(n.Left)
650 n.List = reorder1(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500651
652 case OAS:
653 *init = concat(*init, n.Ninit)
654 n.Ninit = nil
655
656 walkexpr(&n.Left, init)
657 n.Left = safeexpr(n.Left, init)
658
Russ Coxdc7b54b2015-02-17 22:13:49 -0500659 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200660 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 }
662
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700663 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200664 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500665 }
666
667 switch n.Right.Op {
668 default:
669 walkexpr(&n.Right, init)
670
Russ Cox8c195bd2015-02-13 14:40:36 -0500671 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400672 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
673 // It needs to be removed in all three places.
674 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700675 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400676 // handled directly during cgen
677 walkexpr(&n.Right, init)
678 break
679 }
680
David Chaseffe7fbf2015-03-27 12:34:45 -0400681 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400682 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500683 walkexpr(&n.Right.Left, init)
684
Russ Cox382b44e2015-02-23 16:07:24 -0500685 n1 := Nod(OADDR, n.Left, nil)
686 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500687
Russ Cox4224d812015-03-20 00:06:10 -0400688 if Debug_typeassert > 0 {
689 Warn("type assertion not inlined")
690 }
691
Russ Cox01af7272015-03-19 23:38:24 +0000692 buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
Russ Cox382b44e2015-02-23 16:07:24 -0500693 fn := syslook(buf, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400694 substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500695
696 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
697 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200698 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500699
Russ Cox8c195bd2015-02-13 14:40:36 -0500700 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400701 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400702 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500703 walkexpr(&n.Right.Left, init)
704
Russ Cox382b44e2015-02-23 16:07:24 -0500705 n1 := Nod(OADDR, n.Left, nil)
706 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500707 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
708 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200709 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400710
711 case OAPPEND:
712 // x = append(...)
713 r := n.Right
714 if r.Isddd {
715 r = appendslice(r, init) // also works for append(slice, string).
716 } else {
717 r = walkappend(r, init, n)
718 }
719 n.Right = r
720 if r.Op == OAPPEND {
721 // Left in place for back end.
722 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200723 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400724 }
725 // Otherwise, lowered for race detector.
726 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500727 }
728
729 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500730 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500731 r.Dodata = n.Dodata
732 n = r
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800733 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500734 }
735
Russ Cox8c195bd2015-02-13 14:40:36 -0500736 case OAS2:
737 *init = concat(*init, n.Ninit)
738 n.Ninit = nil
739 walkexprlistsafe(n.List, init)
740 walkexprlistsafe(n.Rlist, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500741 ll := ascompatee(OAS, n.List, n.Rlist, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500742 ll = reorder3(ll)
Russ Cox382b44e2015-02-23 16:07:24 -0500743 for lr := ll; lr != nil; lr = lr.Next {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800744 lr.N = applywritebarrier(lr.N)
Russ Cox8c195bd2015-02-13 14:40:36 -0500745 }
746 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500747
748 // a,b,... = fn()
749 case OAS2FUNC:
750 *init = concat(*init, n.Ninit)
751
752 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500753 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500754 walkexprlistsafe(n.List, init)
755 walkexpr(&r, init)
756
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200757 ll := ascompatet(n.Op, n.List, &r.Type, 0, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500758 for lr := ll; lr != nil; lr = lr.Next {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800759 lr.N = applywritebarrier(lr.N)
Russ Cox8c195bd2015-02-13 14:40:36 -0500760 }
761 n = liststmt(concat(list1(r), ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500762
763 // x, y = <-c
764 // orderstmt made sure x is addressable.
765 case OAS2RECV:
766 *init = concat(*init, n.Ninit)
767
768 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500769 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500770 walkexprlistsafe(n.List, init)
771 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500772 var n1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500773 if isblank(n.List.N) {
774 n1 = nodnil()
775 } else {
776 n1 = Nod(OADDR, n.List.N, nil)
777 }
778 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500779 fn := chanfn("chanrecv2", 2, r.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500780 r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
781 n = Nod(OAS, n.List.Next.N, r)
782 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500783
784 // a,b = m[i];
785 case OAS2MAPR:
786 *init = concat(*init, n.Ninit)
787
788 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500789 r := n.Rlist.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500790 walkexprlistsafe(n.List, init)
791 walkexpr(&r.Left, init)
792 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500793 t := r.Left.Type
794 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800796 switch algtype(t.Down) {
797 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500798 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800799 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500800 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800801 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500802 p = "mapaccess2_faststr"
803 }
804 }
805
Russ Cox382b44e2015-02-23 16:07:24 -0500806 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500807 if p != "" {
808 // fast versions take key by value
809 key = r.Right
810 } else {
811 // standard version takes key by reference
812 // orderexpr made sure key is addressable.
813 key = Nod(OADDR, r.Right, nil)
814
815 p = "mapaccess2"
816 }
817
818 // from:
819 // a,b = m[i]
820 // to:
821 // var,b = mapaccess2*(t, m, i)
822 // a = *var
Russ Cox382b44e2015-02-23 16:07:24 -0500823 a := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500824
Russ Cox382b44e2015-02-23 16:07:24 -0500825 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500826 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
827
828 // mapaccess2* returns a typed bool, but due to spec changes,
829 // the boolean result of i.(T) is now untyped so we make it the
830 // same type as the variable on the lhs.
831 if !isblank(n.List.Next.N) {
832 r.Type.Type.Down.Type = n.List.Next.N.Type
833 }
834 n.Rlist = list1(r)
835 n.Op = OAS2FUNC
836
837 // don't generate a = *var if a is _
838 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500839 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500840 var_.Typecheck = 1
841 n.List.N = var_
842 walkexpr(&n, init)
843 *init = list(*init, n)
844 n = Nod(OAS, a, Nod(OIND, var_, nil))
845 }
846
847 typecheck(&n, Etop)
848 walkexpr(&n, init)
849
Russ Cox8c195bd2015-02-13 14:40:36 -0500850 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
Russ Cox8c195bd2015-02-13 14:40:36 -0500851
852 case ODELETE:
853 *init = concat(*init, n.Ninit)
854 n.Ninit = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500855 map_ := n.List.N
856 key := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500857 walkexpr(&map_, init)
858 walkexpr(&key, init)
859
860 // orderstmt made sure key is addressable.
861 key = Nod(OADDR, key, nil)
862
Russ Cox382b44e2015-02-23 16:07:24 -0500863 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500864 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500865
Russ Cox8c195bd2015-02-13 14:40:36 -0500866 case OAS2DOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400867 e := n.Rlist.N // i.(T)
868 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
869 // It needs to be removed in all three places.
870 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700871 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400872 // handled directly during gen.
873 walkexprlistsafe(n.List, init)
874 walkexpr(&e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200875 break
Russ Cox4224d812015-03-20 00:06:10 -0400876 }
877
878 // res, ok = i.(T)
879 // orderstmt made sure a is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500880 *init = concat(*init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500881 n.Ninit = nil
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700882
Russ Cox8c195bd2015-02-13 14:40:36 -0500883 walkexprlistsafe(n.List, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700884 walkexpr(&e.Left, init)
885 t := e.Type // T
886 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500887
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700888 oktype := Types[TBOOL]
Russ Cox382b44e2015-02-23 16:07:24 -0500889 ok := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500890 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700891 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500892 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700893
Russ Cox01af7272015-03-19 23:38:24 +0000894 fromKind := type2IET(from.Type)
895 toKind := type2IET(t)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700896
897 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
898 // This is faster and shorter and allows the corresponding assertX2X2
899 // routines to skip nil checks on their last argument.
900 if isblank(n.List.N) {
901 var fast *Node
902 switch {
903 case fromKind == "E" && toKind == "T":
904 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
905 typ := Nod(OCONVNOP, typename(t), nil)
906 typ.Type = Ptrto(Types[TUINTPTR])
907 fast = Nod(OEQ, tab, typ)
908 case fromKind == "I" && toKind == "E",
909 fromKind == "E" && toKind == "E":
910 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700911 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700912 }
913 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400914 if Debug_typeassert > 0 {
915 Warn("type assertion (ok only) inlined")
916 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700917 n = Nod(OAS, ok, fast)
918 typecheck(&n, Etop)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200919 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700920 }
921 }
922
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700923 var resptr *Node // &res
924 if isblank(n.List.N) {
925 resptr = nodnil()
926 } else {
927 resptr = Nod(OADDR, n.List.N, nil)
928 }
929 resptr.Etype = 1 // addr does not escape
930
Russ Cox4224d812015-03-20 00:06:10 -0400931 if Debug_typeassert > 0 {
932 Warn("type assertion not inlined")
933 }
Russ Cox01af7272015-03-19 23:38:24 +0000934 buf := "assert" + fromKind + "2" + toKind + "2"
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700935 fn := syslook(buf, 1)
936 substArgTypes(fn, from.Type, t)
937 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
938 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500939 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500940
Russ Cox4224d812015-03-20 00:06:10 -0400941 case ODOTTYPE, ODOTTYPE2:
942 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200943 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -0400944 }
945 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500946
947 case OCONVIFACE:
948 walkexpr(&n.Left, init)
949
950 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500951 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500952 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500953 l.Type = n.Type
954 l.Typecheck = n.Typecheck
955 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200956 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500957 }
958
Russ Cox01af7272015-03-19 23:38:24 +0000959 // Build name of function: convI2E etc.
960 // Not all names are possible
961 // (e.g., we'll never generate convE2E or convE2I).
962 buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
963 fn := syslook(buf, 1)
Russ Cox175929b2015-03-02 14:22:05 -0500964 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -0500965 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500966 ll = list(ll, typename(n.Left.Type))
967 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500968 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500969 ll = list(ll, typename(n.Type))
970 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500971 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Coxc8198342015-03-12 18:45:30 -0400972 sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500973 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500974 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500975 l.Sym = sym
976 l.Type = Ptrto(Types[TUINT8])
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700977 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500978 l.Class = PEXTERN
979 l.Xoffset = 0
980 sym.Def = l
981 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
982 }
983
Russ Cox382b44e2015-02-23 16:07:24 -0500984 l := Nod(OADDR, sym.Def, nil)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700985 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500986 ll = list(ll, l)
987
Russ Coxdc7b54b2015-02-17 22:13:49 -0500988 if isdirectiface(n.Left.Type) {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900989 // For pointer types, we can make a special form of optimization
990 //
991 // These statements are put onto the expression init list:
992 // Itab *tab = atomicloadtype(&cache);
993 // if(tab == nil)
994 // tab = typ2Itab(type, itype, &cache);
995 //
996 // The CONVIFACE expression is replaced with this:
997 // OEFACE{tab, ptr};
Russ Cox382b44e2015-02-23 16:07:24 -0500998 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500999
Russ Cox382b44e2015-02-23 16:07:24 -05001000 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001001 typecheck(&n1, Etop)
1002 *init = list(*init, n1)
1003
Russ Cox382b44e2015-02-23 16:07:24 -05001004 fn := syslook("typ2Itab", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001005 n1 = Nod(OCALL, fn, nil)
1006 n1.List = ll
1007 typecheck(&n1, Erv)
1008 walkexpr(&n1, init)
1009
Russ Cox382b44e2015-02-23 16:07:24 -05001010 n2 := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -04001011 n2.Left = Nod(OEQ, l, nodnil())
Russ Cox8c195bd2015-02-13 14:40:36 -05001012 n2.Nbody = list1(Nod(OAS, l, n1))
1013 n2.Likely = -1
1014 typecheck(&n2, Etop)
1015 *init = list(*init, n2)
1016
1017 l = Nod(OEFACE, l, n.Left)
1018 l.Typecheck = n.Typecheck
1019 l.Type = n.Type
1020 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001021 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001022 }
1023 }
1024
Russ Coxdc7b54b2015-02-17 22:13:49 -05001025 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001026 ll = list(ll, n.Left)
1027 } else {
1028 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001029 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001030 // the conversions it could see. comparison of an interface
1031 // with a non-interface, especially in a switch on interface value
1032 // with non-interface cases, is not visible to orderstmt, so we
1033 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001034 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001035 ll = list(ll, Nod(OADDR, n.Left, nil))
1036 } else {
1037 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1038 }
David Chase22701332015-03-27 11:21:14 -04001039 dowidth(n.Left.Type)
1040 r := nodnil()
1041 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1042 // Allocate stack buffer for value stored in interface.
1043 r = temp(n.Left.Type)
1044 r = Nod(OAS, r, nil) // zero temp
1045 typecheck(&r, Etop)
1046 *init = list(*init, r)
1047 r = Nod(OADDR, r.Left, nil)
1048 typecheck(&r, Erv)
1049 }
1050 ll = list(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001051 }
1052
David Chase22701332015-03-27 11:21:14 -04001053 if !Isinter(n.Left.Type) {
1054 substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
1055 } else {
1056 substArgTypes(fn, n.Left.Type, n.Type)
1057 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001058 dowidth(fn.Type)
1059 n = Nod(OCALL, fn, nil)
1060 n.List = ll
1061 typecheck(&n, Erv)
1062 walkexpr(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001063
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001064 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001065 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001066 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001067 if n.Type.Etype == TINT64 {
1068 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001069 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001070 }
1071
1072 if n.Type.Etype == TUINT64 {
1073 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001074 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001075 }
1076 }
1077
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001078 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001079 if n.Left.Type.Etype == TINT64 {
1080 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001081 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001082 }
1083
1084 if n.Left.Type.Etype == TUINT64 {
1085 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001086 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001087 }
1088 }
1089 }
1090
1091 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001092
1093 case OANDNOT:
1094 walkexpr(&n.Left, init)
1095 n.Op = OAND
1096 n.Right = Nod(OCOM, n.Right, nil)
1097 typecheck(&n.Right, Erv)
1098 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001099
1100 case OMUL:
1101 walkexpr(&n.Left, init)
1102 walkexpr(&n.Right, init)
1103 walkmul(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001104
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001105 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001106 walkexpr(&n.Left, init)
1107 walkexpr(&n.Right, init)
1108
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001109 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001110 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001111
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001112 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001113 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001114 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1115 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001116 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001117 }
1118
1119 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001120 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001121 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001122 }
1123
1124 // Try rewriting as shifts or magic multiplies.
1125 walkdiv(&n, init)
1126
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001127 // rewrite 64-bit div and mod into function calls
1128 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001129 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001130 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001131 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001132 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001133 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001134 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001135 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001136 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001137 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001138 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001139 }
1140 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001141 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001142 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001143 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001144 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001145 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001146 }
1147
Russ Cox8c195bd2015-02-13 14:40:36 -05001148 case OINDEX:
1149 walkexpr(&n.Left, init)
1150
1151 // save the original node for bounds checking elision.
1152 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001153 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001154
1155 walkexpr(&n.Right, init)
1156
1157 // if range of type cannot exceed static array bound,
1158 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001159 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001160 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001161 }
Russ Cox382b44e2015-02-23 16:07:24 -05001162 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001163 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001164 t = t.Type
1165 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001166 if Isfixedarray(t) {
1167 n.Bounded = bounded(r, t.Bound)
1168 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001169 Warn("index bounds check elided")
1170 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001171 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001172 Yyerror("index out of bounds")
1173 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001174 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001175 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001176 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001177 Warn("index bounds check elided")
1178 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001179 if Smallintconst(n.Right) {
1180 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001181 Yyerror("index out of bounds")
1182 } else {
1183 // replace "abc"[1] with 'b'.
1184 // delayed until now because "abc"[1] is not
1185 // an ideal constant.
Russ Cox81d58102015-05-27 00:47:05 -04001186 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05001187
Russ Cox81d58102015-05-27 00:47:05 -04001188 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001189 n.Typecheck = 1
1190 }
1191 }
1192 }
1193
Russ Coxdc7b54b2015-02-17 22:13:49 -05001194 if Isconst(n.Right, CTINT) {
Russ Cox81d58102015-05-27 00:47:05 -04001195 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 -05001196 Yyerror("index out of bounds")
1197 }
1198 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001199
1200 case OINDEXMAP:
1201 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001202 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001203 }
1204 walkexpr(&n.Left, init)
1205 walkexpr(&n.Right, init)
1206
Russ Cox382b44e2015-02-23 16:07:24 -05001207 t := n.Left.Type
1208 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001209 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001210 switch algtype(t.Down) {
1211 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001212 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001213 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001214 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001215 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001216 p = "mapaccess1_faststr"
1217 }
1218 }
1219
Russ Cox382b44e2015-02-23 16:07:24 -05001220 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001221 if p != "" {
1222 // fast versions take key by value
1223 key = n.Right
1224 } else {
1225 // standard version takes key by reference.
1226 // orderexpr made sure key is addressable.
1227 key = Nod(OADDR, n.Right, nil)
1228
1229 p = "mapaccess1"
1230 }
1231
1232 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1233 n = Nod(OIND, n, nil)
1234 n.Type = t.Type
1235 n.Typecheck = 1
1236
Russ Cox8c195bd2015-02-13 14:40:36 -05001237 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001238 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001239
Russ Coxd4472792015-05-06 12:35:53 -04001240 case OSLICE, OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001241 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001242 walkexpr(&n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001243 if n.Right.Left != nil && iszero(n.Right.Left) {
1244 // Reduce x[0:j] to x[:j].
1245 n.Right.Left = nil
1246 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001247 walkexpr(&n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001248 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001249
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001250 case OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -04001251 walkexpr(&n.Left, init)
1252 walkexpr(&n.Right.Left, init)
1253 if n.Right.Left != nil && iszero(n.Right.Left) {
1254 // Reduce x[0:j:k] to x[:j:k].
1255 n.Right.Left = nil
1256 }
1257 walkexpr(&n.Right.Right.Left, init)
1258 walkexpr(&n.Right.Right.Right, init)
1259
1260 r := n.Right.Right.Right
1261 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1262 // Reduce x[i:j:cap(x)] to x[i:j].
1263 n.Right.Right = n.Right.Right.Left
1264 if n.Op == OSLICE3 {
1265 n.Op = OSLICE
1266 } else {
1267 n.Op = OSLICEARR
1268 }
1269 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001270 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001271
1272 case OADDR:
1273 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001274
1275 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001276 if n.Esc == EscNone {
1277 if n.Type.Type.Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001278 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001279 }
Russ Cox382b44e2015-02-23 16:07:24 -05001280 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001281 r = Nod(OAS, r, nil) // zero temp
1282 typecheck(&r, Etop)
1283 *init = list(*init, r)
1284 r = Nod(OADDR, r.Left, nil)
1285 typecheck(&r, Erv)
1286 n = r
1287 } else {
1288 n = callnew(n.Type.Type)
1289 }
1290
Russ Cox8c195bd2015-02-13 14:40:36 -05001291 // If one argument to the comparison is an empty string,
1292 // comparing the lengths instead will yield the same result
1293 // without the function call.
1294 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001295 if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001296 // TODO(marvin): Fix Node.EType type union.
1297 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001298 typecheck(&r, Erv)
1299 walkexpr(&r, init)
1300 r.Type = n.Type
1301 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001302 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001303 }
1304
1305 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001306 if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && count(n.Left.List) == 2 && Isconst(n.Left.List.Next.N, CTSTR) && strlit(n.Right) == strlit(n.Left.List.Next.N) {
1307 // TODO(marvin): Fix Node.EType type union.
1308 r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001309 typecheck(&r, Erv)
1310 walkexpr(&r, init)
1311 r.Type = n.Type
1312 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001313 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001314 }
1315
Russ Cox382b44e2015-02-23 16:07:24 -05001316 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001317 // TODO(marvin): Fix Node.EType type union.
1318 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001319 // prepare for rewrite below
1320 n.Left = cheapexpr(n.Left, init)
1321
1322 n.Right = cheapexpr(n.Right, init)
1323
1324 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1325
1326 // quick check of len before full compare for == or !=
1327 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001328 // TODO(marvin): Fix Node.EType type union.
1329 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001330 // len(left) == len(right) && eqstring(left, right)
1331 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1332 } else {
1333 // len(left) != len(right) || !eqstring(left, right)
1334 r = Nod(ONOT, r, nil)
1335
1336 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1337 }
1338
1339 typecheck(&r, Erv)
1340 walkexpr(&r, nil)
1341 } else {
1342 // sys_cmpstring(s1, s2) :: 0
1343 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1344
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001345 // TODO(marvin): Fix Node.EType type union.
1346 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001347 }
1348
1349 typecheck(&r, Erv)
1350 if n.Type.Etype != TBOOL {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001351 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001352 }
1353 r.Type = n.Type
1354 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001355
1356 case OADDSTR:
1357 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001358
1359 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001360 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001361 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001362
1363 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001364 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001365
1366 // cannot use chanfn - closechan takes any, not chan any
1367 case OCLOSE:
Russ Cox382b44e2015-02-23 16:07:24 -05001368 fn := syslook("closechan", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001369
Russ Cox13f9c8b2015-03-08 13:33:49 -04001370 substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001371 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001372
1373 case OMAKECHAN:
1374 n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001375
1376 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001377 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001378
Russ Cox382b44e2015-02-23 16:07:24 -05001379 fn := syslook("makemap", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001380
Russ Cox382b44e2015-02-23 16:07:24 -05001381 a := nodnil() // hmap buffer
1382 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001383 if n.Esc == EscNone {
1384 // Allocate hmap buffer on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001385 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001386
1387 a = Nod(OAS, var_, nil) // zero temp
1388 typecheck(&a, Etop)
1389 *init = list(*init, a)
1390 a = Nod(OADDR, var_, nil)
1391
1392 // Allocate one bucket on stack.
1393 // Maximum key/value size is 128 bytes, larger objects
1394 // are stored with an indirection. So max bucket size is 2048+eps.
1395 var_ = temp(mapbucket(t))
1396
1397 r = Nod(OAS, var_, nil) // zero temp
1398 typecheck(&r, Etop)
1399 *init = list(*init, r)
1400 r = Nod(OADDR, var_, nil)
1401 }
1402
Russ Cox13f9c8b2015-03-08 13:33:49 -04001403 substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001404 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001405
1406 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001407 l := n.Left
1408 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001409 if r == nil {
1410 r = safeexpr(l, init)
1411 l = r
1412 }
Russ Cox382b44e2015-02-23 16:07:24 -05001413 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001414 if n.Esc == EscNone {
1415 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001416 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001417 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001418 // var arr [r]T
1419 // n = arr[:l]
1420 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001421 var_ := temp(t)
1422 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001423 typecheck(&a, Etop)
1424 *init = list(*init, a)
Russ Cox382b44e2015-02-23 16:07:24 -05001425 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001426 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001427 typecheck(&r, Erv)
1428 walkexpr(&r, init)
1429 n = r
1430 } else {
1431 // makeslice(t *Type, nel int64, max int64) (ary []any)
Russ Cox382b44e2015-02-23 16:07:24 -05001432 fn := syslook("makeslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001433
Russ Cox13f9c8b2015-03-08 13:33:49 -04001434 substArgTypes(fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001435 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1436 }
1437
Russ Cox8c195bd2015-02-13 14:40:36 -05001438 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001439 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001440 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001441 t := aindex(Nodintconst(4), Types[TUINT8])
1442 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001443 a = Nod(OADDR, var_, nil)
1444 }
1445
1446 // intstring(*[4]byte, rune)
1447 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1448
Russ Cox8c195bd2015-02-13 14:40:36 -05001449 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001450 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001451 if n.Esc == EscNone {
1452 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001453 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001454
1455 a = Nod(OADDR, temp(t), nil)
1456 }
1457
1458 // slicebytetostring(*[32]byte, []byte) string;
1459 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1460
Russ Cox8c195bd2015-02-13 14:40:36 -05001461 // slicebytetostringtmp([]byte) string;
1462 case OARRAYBYTESTRTMP:
1463 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1464
Russ Cox8c195bd2015-02-13 14:40:36 -05001465 // slicerunetostring(*[32]byte, []rune) string;
1466 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001467 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001468
1469 if n.Esc == EscNone {
1470 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001471 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001472
1473 a = Nod(OADDR, temp(t), nil)
1474 }
1475
1476 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001477
1478 // stringtoslicebyte(*32[byte], string) []byte;
1479 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001480 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001481
1482 if n.Esc == EscNone {
1483 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001484 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001485
1486 a = Nod(OADDR, temp(t), nil)
1487 }
1488
1489 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001490
1491 // stringtoslicebytetmp(string) []byte;
1492 case OSTRARRAYBYTETMP:
1493 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1494
Russ Cox8c195bd2015-02-13 14:40:36 -05001495 // stringtoslicerune(*[32]rune, string) []rune
1496 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001497 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001498
1499 if n.Esc == EscNone {
1500 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001501 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001502
1503 a = Nod(OADDR, temp(t), nil)
1504 }
1505
1506 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001507
1508 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1509 case OCMPIFACE:
1510 if !Eqtype(n.Left.Type, n.Right.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001511 Fatalf("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001512 }
Russ Cox382b44e2015-02-23 16:07:24 -05001513 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001514 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001515 fn = syslook("efaceeq", 1)
1516 } else {
1517 fn = syslook("ifaceeq", 1)
1518 }
1519
1520 n.Right = cheapexpr(n.Right, init)
1521 n.Left = cheapexpr(n.Left, init)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001522 substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001523 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001524 // TODO(marvin): Fix Node.EType type union.
1525 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001526 r = Nod(ONOT, r, nil)
1527 }
1528
1529 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001530 // TODO(marvin): Fix Node.EType type union.
1531 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001532 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1533 } else {
1534 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1535 }
1536 typecheck(&r, Erv)
1537 walkexpr(&r, init)
1538 r.Type = n.Type
1539 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001540
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001541 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001542 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001543 anylit(0, n, var_, init)
1544 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001545
1546 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001547 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001548 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1549 walkexpr(&n1, init)
1550 n1 = Nod(OADDR, n1, nil)
1551 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001552
1553 case OCLOSURE:
1554 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001555
1556 case OCALLPART:
1557 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001558 }
1559
Russ Cox8c195bd2015-02-13 14:40:36 -05001560 // Expressions that are constant at run time but not
1561 // considered const by the language spec are not turned into
1562 // constants until walk. For example, if n is y%1 == 0, the
1563 // walk of y%1 may have replaced it by 0.
1564 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001565 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001566
1567 evconst(n)
1568 n.Type = t
1569 if n.Op == OLITERAL {
1570 typecheck(&n, Erv)
1571 }
1572
1573 ullmancalc(n)
1574
1575 if Debug['w'] != 0 && n != nil {
1576 Dump("walk", n)
1577 }
1578
1579 lineno = lno
1580 *np = n
1581}
1582
Russ Coxd4472792015-05-06 12:35:53 -04001583func reduceSlice(n *Node) *Node {
1584 r := n.Right.Right
1585 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1586 // Reduce x[i:len(x)] to x[i:].
1587 n.Right.Right = nil
1588 }
1589 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1590 // Reduce x[:] to x.
1591 if Debug_slice > 0 {
1592 Warn("slice: omit slice operation")
1593 }
1594 return n.Left
1595 }
1596 return n
1597}
1598
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001599func ascompatee1(op Op, l *Node, r *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001600 // convas will turn map assigns into function calls,
1601 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001602 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001603
1604 if l.Op == OINDEXMAP {
1605 return n
1606 }
1607
1608 return convas(n, init)
1609}
1610
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001611func ascompatee(op Op, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001612 // check assign expression list to
1613 // a expression list. called in
1614 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001615
1616 // ensure order of evaluation for function calls
Russ Coxc8198342015-03-12 18:45:30 -04001617 for ll := nl; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001618 ll.N = safeexpr(ll.N, init)
1619 }
Russ Coxc8198342015-03-12 18:45:30 -04001620 for lr := nr; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001621 lr.N = safeexpr(lr.N, init)
1622 }
1623
Russ Cox175929b2015-03-02 14:22:05 -05001624 var nn *NodeList
Russ Coxc8198342015-03-12 18:45:30 -04001625 ll := nl
1626 lr := nr
Russ Coxd7f6d462015-03-09 00:31:13 -04001627 for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001628 // Do not generate 'x = x' during return. See issue 4014.
1629 if op == ORETURN && ll.N == lr.N {
1630 continue
1631 }
1632 nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
1633 }
1634
1635 // cannot happen: caller checked that lists had same length
1636 if ll != nil || lr != nil {
Russ Coxbd4fff62015-05-27 10:42:55 -04001637 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 -05001638 }
1639 return nn
1640}
1641
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001642// l is an lv and rt is the type of an rv
1643// return 1 if this implies a function call
1644// evaluating the lv or a function call
1645// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001646func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001647 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001648 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001649 }
Russ Cox175929b2015-03-02 14:22:05 -05001650 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001651 if needwritebarrier(l, &r) {
1652 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001653 }
1654 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001655 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001656 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001657 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001658}
1659
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001660func ascompatet(op Op, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001661 var l *Node
1662 var tmp *Node
1663 var a *Node
1664 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001665 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001666
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001667 // check assign type list to
1668 // a expression list. called in
1669 // expr-list = func()
Russ Cox382b44e2015-02-23 16:07:24 -05001670 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001671
Russ Cox175929b2015-03-02 14:22:05 -05001672 var nn *NodeList
1673 var mm *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001674 ucount := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001675 for ll = nl; ll != nil; ll = ll.Next {
1676 if r == nil {
1677 break
1678 }
1679 l = ll.N
1680 if isblank(l) {
1681 r = structnext(&saver)
1682 continue
1683 }
1684
1685 // any lv that causes a fn call must be
1686 // deferred until all the return arguments
1687 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001688 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001689 tmp = temp(r.Type)
1690 typecheck(&tmp, Erv)
1691 a = Nod(OAS, l, tmp)
1692 a = convas(a, init)
1693 mm = list(mm, a)
1694 l = tmp
1695 }
1696
1697 a = Nod(OAS, l, nodarg(r, fp))
1698 a = convas(a, init)
1699 ullmancalc(a)
1700 if a.Ullman >= UINF {
1701 Dump("ascompatet ucount", a)
1702 ucount++
1703 }
1704
1705 nn = list(nn, a)
1706 r = structnext(&saver)
1707 }
1708
1709 if ll != nil || r != nil {
1710 Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
1711 }
1712
1713 if ucount != 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001714 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001715 }
1716 return concat(nn, mm)
1717}
1718
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001719// package all the arguments that match a ... T parameter into a []T.
Russ Cox8c195bd2015-02-13 14:40:36 -05001720func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
David Chase7fbb1b32015-03-26 16:36:15 -04001721 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001722 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001723 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001724 }
1725
Russ Cox382b44e2015-02-23 16:07:24 -05001726 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001727 tslice.Type = l.Type.Type
1728 tslice.Bound = -1
1729
Russ Cox382b44e2015-02-23 16:07:24 -05001730 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001731 if count(lr0) == 0 {
1732 n = nodnil()
1733 n.Type = tslice
1734 } else {
1735 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001736 if ddd != nil && prealloc[ddd] != nil {
1737 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001738 }
1739 n.List = lr0
Dave Cheneye4981812015-03-10 09:58:01 +11001740 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001741 typecheck(&n, Erv)
1742 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001743 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001744 }
1745 walkexpr(&n, init)
1746 }
1747
Russ Cox382b44e2015-02-23 16:07:24 -05001748 a := Nod(OAS, nodarg(l, fp), n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001749 nn = list(nn, convas(a, init))
1750 return nn
1751}
1752
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001753// helpers for shape errors
Russ Cox8c195bd2015-02-13 14:40:36 -05001754func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001755 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001756
Russ Cox382b44e2015-02-23 16:07:24 -05001757 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001758 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001759 first := 1
1760 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001761 if first != 0 {
1762 first = 0
1763 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001764 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001765 }
Russ Coxc8198342015-03-12 18:45:30 -04001766 fmt_ += Tconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001767 }
1768
1769 if first != 0 {
1770 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1771 }
1772 return fmt_
1773}
1774
1775func dumpnodetypes(l *NodeList, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001776 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001777
Russ Cox382b44e2015-02-23 16:07:24 -05001778 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001779 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001780 first := 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001781 for ; l != nil; l = l.Next {
1782 r = l.N
1783 if first != 0 {
1784 first = 0
1785 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001786 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001787 }
Russ Coxc8198342015-03-12 18:45:30 -04001788 fmt_ += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 }
1790
1791 if first != 0 {
1792 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1793 }
1794 return fmt_
1795}
1796
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001797// check assign expression list to
1798// a type list. called in
1799// return expr-list
1800// func(expr-list)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001801func ascompatte(op Op, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001802 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001803
Russ Cox382b44e2015-02-23 16:07:24 -05001804 lr0 := lr
1805 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001806 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001807 if lr != nil {
1808 r = lr.N
1809 }
Russ Cox175929b2015-03-02 14:22:05 -05001810 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001811
1812 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001813 var a *Node
1814 var l2 string
1815 var ll *Type
1816 var l1 string
Marvin Stenger9ac0fff2015-09-08 03:51:30 +02001817 if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg {
Russ Cox8c195bd2015-02-13 14:40:36 -05001818 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001819 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001820 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001821 r = Nod(OCONVNOP, r, nil)
1822 r.Type = a.Type
1823 nn = list1(convas(Nod(OAS, a, r), init))
1824 goto ret
1825 }
1826
1827 // conversions involved.
1828 // copy into temporaries.
Russ Cox175929b2015-03-02 14:22:05 -05001829 var alist *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001830
Russ Cox382b44e2015-02-23 16:07:24 -05001831 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 a = temp(l.Type)
1833 alist = list(alist, a)
1834 }
1835
1836 a = Nod(OAS2, nil, nil)
1837 a.List = alist
1838 a.Rlist = lr
1839 typecheck(&a, Etop)
1840 walkstmt(&a)
1841 *init = list(*init, a)
1842 lr = alist
1843 r = lr.N
1844 l = Structfirst(&savel, nl)
1845 }
1846
1847loop:
Dave Cheneyd3287562015-03-09 16:24:07 +11001848 if l != nil && l.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001849 // the ddd parameter must be last
1850 ll = structnext(&savel)
1851
1852 if ll != nil {
1853 Yyerror("... must be last argument")
1854 }
1855
1856 // special case --
1857 // only if we are assigning a single ddd
1858 // argument to a ddd parameter then it is
1859 // passed thru unencapsulated
Dave Cheneyd3287562015-03-09 16:24:07 +11001860 if r != nil && lr.Next == nil && isddd && Eqtype(l.Type, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001861 a = Nod(OAS, nodarg(l, fp), r)
1862 a = convas(a, init)
1863 nn = list(nn, a)
1864 goto ret
1865 }
1866
1867 // normal case -- make a slice of all
1868 // remaining arguments and pass it to
1869 // the ddd parameter.
1870 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1871
1872 goto ret
1873 }
1874
1875 if l == nil || r == nil {
1876 if l != nil || r != nil {
1877 l1 = dumptypes(nl, "expected")
1878 l2 = dumpnodetypes(lr0, "given")
1879 if l != nil {
1880 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1881 } else {
1882 Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1883 }
1884 }
1885
1886 goto ret
1887 }
1888
1889 a = Nod(OAS, nodarg(l, fp), r)
1890 a = convas(a, init)
1891 nn = list(nn, a)
1892
1893 l = structnext(&savel)
1894 r = nil
1895 lr = lr.Next
1896 if lr != nil {
1897 r = lr.N
1898 }
1899 goto loop
1900
1901ret:
1902 for lr = nn; lr != nil; lr = lr.Next {
1903 lr.N.Typecheck = 1
1904 }
1905 return nn
1906}
1907
1908// generate code for print
1909func walkprint(nn *Node, init **NodeList) *Node {
1910 var r *Node
1911 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001912 var on *Node
1913 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001914 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001915
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001916 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001917 all := nn.List
Russ Cox175929b2015-03-02 14:22:05 -05001918 var calls *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001919 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001920
1921 // Hoist all the argument evaluation up before the lock.
1922 walkexprlistcheap(all, init)
1923
1924 calls = list(calls, mkcall("printlock", nil, init))
1925
Russ Cox382b44e2015-02-23 16:07:24 -05001926 for l := all; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001927 if notfirst {
Russ Cox8c195bd2015-02-13 14:40:36 -05001928 calls = list(calls, mkcall("printsp", nil, init))
1929 }
1930
Russ Coxdc7b54b2015-02-17 22:13:49 -05001931 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001932
1933 n = l.N
1934 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04001935 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001936 case CTRUNE:
1937 defaultlit(&n, runetype)
1938
1939 case CTINT:
1940 defaultlit(&n, Types[TINT64])
1941
1942 case CTFLT:
1943 defaultlit(&n, Types[TFLOAT64])
1944 }
1945 }
1946
1947 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
1948 defaultlit(&n, Types[TINT64])
1949 }
1950 defaultlit(&n, nil)
1951 l.N = n
1952 if n.Type == nil || n.Type.Etype == TFORW {
1953 continue
1954 }
1955
1956 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001957 et = n.Type.Etype
Russ Coxdc7b54b2015-02-17 22:13:49 -05001958 if Isinter(n.Type) {
1959 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001960 on = syslook("printeface", 1)
1961 } else {
1962 on = syslook("printiface", 1)
1963 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04001964 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001965 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Russ Cox8c195bd2015-02-13 14:40:36 -05001966 on = syslook("printpointer", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001967 substArgTypes(on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05001968 } else if Isslice(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001969 on = syslook("printslice", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001970 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001971 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001972 if et == TUINT64 {
1973 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
1974 on = syslook("printhex", 0)
1975 } else {
1976 on = syslook("printuint", 0)
1977 }
1978 } else {
1979 on = syslook("printint", 0)
1980 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001981 } else if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001982 on = syslook("printfloat", 0)
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001983 } else if Iscomplex[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001984 on = syslook("printcomplex", 0)
1985 } else if et == TBOOL {
1986 on = syslook("printbool", 0)
1987 } else if et == TSTRING {
1988 on = syslook("printstring", 0)
1989 } else {
1990 badtype(OPRINT, n.Type, nil)
1991 continue
1992 }
1993
1994 t = *getinarg(on.Type)
1995 if t != nil {
1996 t = t.Type
1997 }
1998 if t != nil {
1999 t = t.Type
2000 }
2001
2002 if !Eqtype(t, n.Type) {
2003 n = Nod(OCONV, n, nil)
2004 n.Type = t
2005 }
2006
2007 r = Nod(OCALL, on, nil)
2008 r.List = list1(n)
2009 calls = list(calls, r)
2010 }
2011
2012 if op == OPRINTN {
2013 calls = list(calls, mkcall("printnl", nil, nil))
2014 }
2015
2016 calls = list(calls, mkcall("printunlock", nil, init))
2017
2018 typechecklist(calls, Etop)
2019 walkexprlist(calls, init)
2020
2021 r = Nod(OEMPTY, nil, nil)
2022 typecheck(&r, Etop)
2023 walkexpr(&r, init)
2024 r.Ninit = calls
2025 return r
2026}
2027
2028func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002029 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -05002030 fn := syslook("newobject", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002031 substArgTypes(fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002032 return mkcall1(fn, Ptrto(t), nil, typename(t))
2033}
2034
Russ Cox3b6e86f2015-06-29 15:17:14 -04002035func iscallret(n *Node) bool {
2036 n = outervalue(n)
2037 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2038}
2039
Russ Coxdc7b54b2015-02-17 22:13:49 -05002040func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002041 n = outervalue(n)
2042
2043 // If n is *autotmp and autotmp = &foo, replace n with foo.
2044 // We introduce such temps when initializing struct literals.
2045 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002046 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002047 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2048 n = defn.Right.Left
2049 }
2050 }
2051
2052 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002053 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002054 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002055
2056 case ONAME:
2057 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002058 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002059 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002060 }
2061 }
2062
Russ Coxdc7b54b2015-02-17 22:13:49 -05002063 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002064}
2065
Russ Coxdc7b54b2015-02-17 22:13:49 -05002066func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002067 n = outervalue(n)
2068
2069 switch n.Op {
2070 case ONAME:
2071 switch n.Class {
2072 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002073 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002074 }
2075 }
2076
Russ Coxdc7b54b2015-02-17 22:13:49 -05002077 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002078}
2079
2080// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002081func needwritebarrier(l *Node, r *Node) bool {
2082 if use_writebarrier == 0 {
2083 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002084 }
2085
2086 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002087 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002088 }
2089
2090 // No write barrier for write of non-pointers.
2091 dowidth(l.Type)
2092
2093 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002094 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002095 }
2096
2097 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002098 if isstack(l) {
2099 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002100 }
2101
Russ Cox9f90f312015-06-29 12:49:25 -04002102 // No write barrier for implicit zeroing.
2103 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002105 }
2106
Russ Cox9f90f312015-06-29 12:49:25 -04002107 // Ignore no-op conversions when making decision.
2108 // Ensures that xp = unsafe.Pointer(&x) is treated
2109 // the same as xp = &x.
2110 for r.Op == OCONVNOP {
2111 r = r.Left
2112 }
2113
2114 // No write barrier for zeroing or initialization to constant.
2115 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002116 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002117 }
2118
2119 // No write barrier for storing static (read-only) data.
2120 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002121 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002122 }
2123
2124 // No write barrier for storing address of stack values,
2125 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002126 if r.Op == OADDR && isstack(r.Left) {
2127 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002128 }
2129
2130 // No write barrier for storing address of global, which
2131 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002132 if r.Op == OADDR && isglobal(r.Left) {
2133 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002134 }
2135
Russ Cox8c195bd2015-02-13 14:40:36 -05002136 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002137 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002138}
2139
2140// TODO(rsc): Perhaps componentgen should run before this.
2141
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002142func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002143 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002144 if Debug_wb > 1 {
2145 Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002146 }
Russ Cox972a4782015-05-21 15:00:06 -04002147 n.Op = OASWB
2148 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002149 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002150 return n
2151}
2152
2153func convas(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002154 if n.Op != OAS {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002155 Fatalf("convas: not OAS %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 }
2157
2158 n.Typecheck = 1
2159
Russ Cox382b44e2015-02-23 16:07:24 -05002160 var lt *Type
2161 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002162 if n.Left == nil || n.Right == nil {
2163 goto out
2164 }
2165
2166 lt = n.Left.Type
2167 rt = n.Right.Type
2168 if lt == nil || rt == nil {
2169 goto out
2170 }
2171
2172 if isblank(n.Left) {
2173 defaultlit(&n.Right, nil)
2174 goto out
2175 }
2176
2177 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002178 map_ := n.Left.Left
2179 key := n.Left.Right
2180 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002181 walkexpr(&map_, init)
2182 walkexpr(&key, init)
2183 walkexpr(&val, init)
2184
2185 // orderexpr made sure key and val are addressable.
2186 key = Nod(OADDR, key, nil)
2187
2188 val = Nod(OADDR, val, nil)
2189 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2190 goto out
2191 }
2192
2193 if !Eqtype(lt, rt) {
2194 n.Right = assignconv(n.Right, lt, "assignment")
2195 walkexpr(&n.Right, init)
2196 }
2197
2198out:
2199 ullmancalc(n)
2200 return n
2201}
2202
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002203// from ascompat[te]
2204// evaluating actual function arguments.
2205// f(a,b)
2206// if there is exactly one function expr,
2207// then it is done first. otherwise must
2208// make temp variables
Russ Cox8c195bd2015-02-13 14:40:36 -05002209func reorder1(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002210 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002211
Russ Cox382b44e2015-02-23 16:07:24 -05002212 c := 0 // function calls
2213 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002214
Russ Cox382b44e2015-02-23 16:07:24 -05002215 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002216 n = l.N
2217 t++
2218 ullmancalc(n)
2219 if n.Ullman >= UINF {
2220 c++
2221 }
2222 }
2223
2224 if c == 0 || t == 1 {
2225 return all
2226 }
2227
Russ Cox175929b2015-03-02 14:22:05 -05002228 var g *NodeList // fncalls assigned to tempnames
2229 var f *Node // last fncall assigned to stack
2230 var r *NodeList // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002231 d := 0
2232 var a *Node
2233 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 n = l.N
2235 if n.Ullman < UINF {
2236 r = list(r, n)
2237 continue
2238 }
2239
2240 d++
2241 if d == c {
2242 f = n
2243 continue
2244 }
2245
2246 // make assignment of fncall to tempname
2247 a = temp(n.Right.Type)
2248
2249 a = Nod(OAS, a, n.Right)
2250 g = list(g, a)
2251
2252 // put normal arg assignment on list
2253 // with fncall replaced by tempname
2254 n.Right = a.Left
2255
2256 r = list(r, n)
2257 }
2258
2259 if f != nil {
2260 g = list(g, f)
2261 }
2262 return concat(g, r)
2263}
2264
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002265// from ascompat[ee]
2266// a,b = c,d
2267// simultaneous assignment. there cannot
2268// be later use of an earlier lvalue.
2269//
2270// function calls have been removed.
Russ Cox8c195bd2015-02-13 14:40:36 -05002271func reorder3(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002272 var l *Node
2273
2274 // If a needed expression may be affected by an
2275 // earlier assignment, make an early copy of that
2276 // expression and use the copy instead.
Russ Cox175929b2015-03-02 14:22:05 -05002277 var early *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002278
Russ Cox175929b2015-03-02 14:22:05 -05002279 var mapinit *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002280 for list := all; list != nil; list = list.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002281 l = list.N.Left
2282
2283 // Save subexpressions needed on left side.
2284 // Drill through non-dereferences.
2285 for {
2286 if l.Op == ODOT || l.Op == OPAREN {
2287 l = l.Left
2288 continue
2289 }
2290
Russ Coxdc7b54b2015-02-17 22:13:49 -05002291 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002292 reorder3save(&l.Right, all, list, &early)
2293 l = l.Left
2294 continue
2295 }
2296
2297 break
2298 }
2299
2300 switch l.Op {
2301 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002302 Fatalf("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002303
2304 case ONAME:
2305 break
2306
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002307 case OINDEX, OINDEXMAP:
Russ Cox8c195bd2015-02-13 14:40:36 -05002308 reorder3save(&l.Left, all, list, &early)
2309 reorder3save(&l.Right, all, list, &early)
2310 if l.Op == OINDEXMAP {
2311 list.N = convas(list.N, &mapinit)
2312 }
2313
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002314 case OIND, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05002315 reorder3save(&l.Left, all, list, &early)
2316 }
2317
2318 // Save expression on right side.
2319 reorder3save(&list.N.Right, all, list, &early)
2320 }
2321
2322 early = concat(mapinit, early)
2323 return concat(early, all)
2324}
2325
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002326// if the evaluation of *np would be affected by the
2327// assignments in all up to but not including stop,
2328// copy into a temporary during *early and
2329// replace *np with that temp.
Russ Cox8c195bd2015-02-13 14:40:36 -05002330func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05002331 n := *np
Russ Coxdc7b54b2015-02-17 22:13:49 -05002332 if !aliased(n, all, stop) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002333 return
2334 }
2335
Russ Cox382b44e2015-02-23 16:07:24 -05002336 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002337 q = Nod(OAS, q, n)
2338 typecheck(&q, Etop)
2339 *early = list(*early, q)
2340 *np = q.Left
2341}
2342
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002343// what's the outer value that a write to n affects?
2344// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002345func outervalue(n *Node) *Node {
2346 for {
2347 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002348 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002349 }
2350 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2351 n = n.Left
2352 continue
2353 }
2354
Russ Coxdc7b54b2015-02-17 22:13:49 -05002355 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002356 n = n.Left
2357 continue
2358 }
2359
2360 break
2361 }
2362
2363 return n
2364}
2365
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002366// Is it possible that the computation of n might be
2367// affected by writes in as up to but not including stop?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002368func aliased(n *Node, all *NodeList, stop *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002369 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002370 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002371 }
2372
2373 // Look for obvious aliasing: a variable being assigned
2374 // during the all list and appearing in n.
2375 // Also record whether there are any writes to main memory.
2376 // Also record whether there are any writes to variables
2377 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002378 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002379
Russ Cox382b44e2015-02-23 16:07:24 -05002380 varwrite := 0
2381 var a *Node
2382 for l := all; l != stop; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002383 a = outervalue(l.N.Left)
2384 if a.Op != ONAME {
2385 memwrite = 1
2386 continue
2387 }
2388
2389 switch n.Class {
2390 default:
2391 varwrite = 1
2392 continue
2393
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002394 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002395 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002396 varwrite = 1
2397 continue
2398 }
2399
Russ Coxdc7b54b2015-02-17 22:13:49 -05002400 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002401 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002402 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002403 }
2404 }
2405 }
2406
2407 // The variables being written do not appear in n.
2408 // However, n might refer to computed addresses
2409 // that are being written.
2410
2411 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002412 if memwrite == 0 && varwrite == 0 {
2413 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002414 }
2415
2416 // If n does not refer to computed addresses
2417 // (that is, if n only refers to variables whose addresses
2418 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002419 if varexpr(n) {
2420 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002421 }
2422
2423 // Otherwise, both the writes and n refer to computed memory addresses.
2424 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002425 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002426}
2427
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002428// does the evaluation of n only refer to variables
2429// whose addresses have not been taken?
2430// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002431func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002432 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002433 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002434 }
2435
2436 switch n.Op {
2437 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002438 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002439
2440 case ONAME:
2441 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002442 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002443 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002444 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002445 }
2446 }
2447
Russ Coxdc7b54b2015-02-17 22:13:49 -05002448 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002449
2450 case OADD,
2451 OSUB,
2452 OOR,
2453 OXOR,
2454 OMUL,
2455 ODIV,
2456 OMOD,
2457 OLSH,
2458 ORSH,
2459 OAND,
2460 OANDNOT,
2461 OPLUS,
2462 OMINUS,
2463 OCOM,
2464 OPAREN,
2465 OANDAND,
2466 OOROR,
2467 ODOT, // but not ODOTPTR
2468 OCONV,
2469 OCONVNOP,
2470 OCONVIFACE,
2471 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002472 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002473 }
2474
2475 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002476 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002477}
2478
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002479// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002480func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002481 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002482 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002483 }
2484 switch r.Op {
2485 // match each right given left
2486 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002487 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002488
2489 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002490 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002491 }
2492
Russ Coxdc7b54b2015-02-17 22:13:49 -05002493 if vmatch2(l, r.Left) {
2494 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002495 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002496 if vmatch2(l, r.Right) {
2497 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002498 }
Russ Cox382b44e2015-02-23 16:07:24 -05002499 for ll := r.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002500 if vmatch2(l, ll.N) {
2501 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002502 }
2503 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002504 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002505}
2506
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002507// is any name mentioned in l also mentioned in r?
2508// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002509func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002510 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002511 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002512 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002513 }
2514 switch l.Op {
2515 case ONAME:
2516 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002517 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002518 break
2519
2520 // assignment to non-stack variable
2521 // must be delayed if right has function calls.
2522 default:
2523 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002524 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002525 }
2526 }
2527
2528 return vmatch2(l, r)
2529
2530 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002531 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002532 }
2533
Russ Coxdc7b54b2015-02-17 22:13:49 -05002534 if vmatch1(l.Left, r) {
2535 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002536 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002537 if vmatch1(l.Right, r) {
2538 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002539 }
Russ Cox382b44e2015-02-23 16:07:24 -05002540 for ll := l.List; ll != nil; ll = ll.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002541 if vmatch1(ll.N, r) {
2542 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002543 }
2544 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002545 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002546}
2547
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002548// walk through argin parameters.
2549// generate and return code to allocate
2550// copies of escaped parameters to the heap.
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002551func paramstoheap(argin **Type, out int) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002552 var savet Iter
2553 var v *Node
2554 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002555
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002556 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002557 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002558 v = t.Nname
2559 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2560 v = nil
2561 }
2562
2563 // For precise stacks, the garbage collector assumes results
2564 // are always live, so zero them always.
2565 if out != 0 {
2566 // Defer might stop a panic and show the
2567 // return values as they exist at the time of panic.
2568 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002569 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002570 }
2571
Russ Coxdc7b54b2015-02-17 22:13:49 -05002572 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002573 continue
2574 }
2575
2576 // generate allocation & copying code
2577 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002578 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002579 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002580 if prealloc[v] == nil {
2581 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002582 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002583 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 if v.Class&^PHEAP != PPARAMOUT {
Russ Coxbd4fff62015-05-27 10:42:55 -04002585 as = Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002586 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002587 typecheck(&as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002588 as = applywritebarrier(as)
2589 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002590 }
2591 }
2592
2593 return nn
2594}
2595
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002596// walk through argout parameters copying back to stack
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002597func returnsfromheap(argin **Type) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002598 var savet Iter
2599 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002600
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002601 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002602 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002603 v = t.Nname
2604 if v == nil || v.Class != PHEAP|PPARAMOUT {
2605 continue
2606 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002607 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002608 }
2609
2610 return nn
2611}
2612
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002613// take care of migrating any function in/out args
2614// between the stack and the heap. adds code to
2615// curfn's before and after lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002616func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002617 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002618 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002619 nn := paramstoheap(getthis(Curfn.Type), 0)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002620 nn = append(nn, paramstoheap(getinarg(Curfn.Type), 0)...)
2621 nn = append(nn, paramstoheap(Getoutarg(Curfn.Type), 1)...)
2622 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002623 lineno = Curfn.Func.Endlineno
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002624 Curfn.Func.Exit.Append(returnsfromheap(Getoutarg(Curfn.Type))...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002625 lineno = lno
2626}
2627
2628func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002629 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002630 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002631 }
2632
Russ Cox175929b2015-03-02 14:22:05 -05002633 var args *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002634 n := fn.Type.Intuple
2635 for i := 0; i < n; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05002636 args = list(args, va[i])
2637 }
2638
Russ Cox382b44e2015-02-23 16:07:24 -05002639 r := Nod(OCALL, fn, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002640 r.List = args
2641 if fn.Type.Outtuple > 0 {
2642 typecheck(&r, Erv|Efnstruct)
2643 } else {
2644 typecheck(&r, Etop)
2645 }
2646 walkexpr(&r, init)
2647 r.Type = t
2648 return r
2649}
2650
2651func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
2652 return vmkcall(syslook(name, 0), t, init, args)
2653}
2654
2655func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
2656 return vmkcall(fn, t, init, args)
2657}
2658
2659func conv(n *Node, t *Type) *Node {
2660 if Eqtype(n.Type, t) {
2661 return n
2662 }
2663 n = Nod(OCONV, n, nil)
2664 n.Type = t
2665 typecheck(&n, Erv)
2666 return n
2667}
2668
2669func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002670 if t.Etype != TCHAN {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002671 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002672 }
Russ Cox382b44e2015-02-23 16:07:24 -05002673 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002674 switch n {
2675 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002676 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002677 case 1:
2678 substArgTypes(fn, t.Type)
2679 case 2:
2680 substArgTypes(fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002681 }
2682 return fn
2683}
2684
2685func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002686 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002687 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002688 }
Russ Cox382b44e2015-02-23 16:07:24 -05002689 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002690 substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002691 return fn
2692}
2693
2694func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002695 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002696 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002697 }
Russ Cox382b44e2015-02-23 16:07:24 -05002698 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002699 substArgTypes(fn, t.Down, t.Type, t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05002700 return fn
2701}
2702
2703func writebarrierfn(name string, l *Type, r *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002704 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002705 substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002706 return fn
2707}
2708
2709func addstr(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002710 // orderexpr rewrote OADDSTR to have a list of strings.
Russ Cox382b44e2015-02-23 16:07:24 -05002711 c := count(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002712
2713 if c < 2 {
2714 Yyerror("addstr count %d too small", c)
2715 }
2716
Russ Cox382b44e2015-02-23 16:07:24 -05002717 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002718 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002719 sz := int64(0)
2720 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002721 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002722 sz += int64(len(n.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002723 }
2724 }
2725
2726 // Don't allocate the buffer if the result won't fit.
2727 if sz < tmpstringbufsize {
2728 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002729 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002730
2731 buf = Nod(OADDR, temp(t), nil)
2732 }
2733 }
2734
2735 // build list of string arguments
Russ Cox382b44e2015-02-23 16:07:24 -05002736 args := list1(buf)
Russ Cox8c195bd2015-02-13 14:40:36 -05002737
Russ Cox382b44e2015-02-23 16:07:24 -05002738 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002739 args = list(args, conv(l.N, Types[TSTRING]))
2740 }
2741
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002742 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002743 if c <= 5 {
2744 // small numbers of strings use direct runtime helpers.
2745 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002746 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002747 } else {
2748 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002749 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002750
Russ Cox382b44e2015-02-23 16:07:24 -05002751 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002752 t.Type = Types[TSTRING]
2753 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002754 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002755 if prealloc[n] != nil {
2756 prealloc[slice] = prealloc[n]
2757 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002758 slice.List = args.Next // skip buf arg
2759 args = list1(buf)
2760 args = list(args, slice)
2761 slice.Esc = EscNone
2762 }
2763
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002764 cat := syslook(fn, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05002765 r := Nod(OCALL, cat, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002766 r.List = args
2767 typecheck(&r, Erv)
2768 walkexpr(&r, init)
2769 r.Type = n.Type
2770
2771 return r
2772}
2773
2774// expand append(l1, l2...) to
2775// init {
2776// s := l1
2777// if n := len(l1) + len(l2) - cap(s); n > 0 {
Russ Cox32fddad2015-06-25 19:27:20 -04002778// s = growslice_n(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002779// }
2780// s = s[:len(l1)+len(l2)]
2781// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2782// }
2783// s
2784//
2785// l2 is allowed to be a string.
2786func appendslice(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002787 walkexprlistsafe(n.List, init)
2788
2789 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2790 // and n are name or literal, but those may index the slice we're
2791 // modifying here. Fix explicitly.
Russ Cox382b44e2015-02-23 16:07:24 -05002792 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002793 l.N = cheapexpr(l.N, init)
2794 }
2795
Russ Cox382b44e2015-02-23 16:07:24 -05002796 l1 := n.List.N
2797 l2 := n.List.Next.N
Russ Cox8c195bd2015-02-13 14:40:36 -05002798
Russ Cox382b44e2015-02-23 16:07:24 -05002799 s := temp(l1.Type) // var s []T
Russ Cox175929b2015-03-02 14:22:05 -05002800 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002801 l = list(l, Nod(OAS, s, l1)) // s = l1
2802
Russ Cox382b44e2015-02-23 16:07:24 -05002803 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002804
Russ Cox382b44e2015-02-23 16:07:24 -05002805 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002806
2807 // n := len(s) + len(l2) - cap(s)
2808 nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
2809
Russ Cox66be1482015-05-26 21:30:20 -04002810 nif.Left = Nod(OGT, nt, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002811
Russ Cox32fddad2015-06-25 19:27:20 -04002812 // instantiate growslice_n(Type*, []any, int) []any
2813 fn := syslook("growslice_n", 1) // growslice_n(<type>, old []T, n int64) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002814 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002815
Russ Cox32fddad2015-06-25 19:27:20 -04002816 // s = growslice_n(T, s, n)
Matthew Dempsky81d40722015-02-27 15:13:05 +09002817 nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002818
2819 l = list(l, nif)
2820
2821 if haspointers(l1.Type.Type) {
2822 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002823 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 -05002824
2825 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002826 nptr2 := l2
2827 fn := syslook("typedslicecopy", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002828 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002829 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
Russ Cox8c195bd2015-02-13 14:40:36 -05002830 l = list(l, nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002831 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002832 // rely on runtime to instrument copy.
2833 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002834 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 -05002835
2836 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002837 nptr2 := l2
2838 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002839 if l2.Type.Etype == TSTRING {
2840 fn = syslook("slicestringcopy", 1)
2841 } else {
2842 fn = syslook("slicecopy", 1)
2843 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002844 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002845 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05002846 l = list(l, nt)
2847 } else {
2848 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002849 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002850
Russ Coxdc7b54b2015-02-17 22:13:49 -05002851 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002852 nptr1 = Nod(OADDR, nptr1, nil)
2853
Russ Cox382b44e2015-02-23 16:07:24 -05002854 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002855
Russ Cox382b44e2015-02-23 16:07:24 -05002856 fn := syslook("memmove", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002857 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002858
Russ Cox382b44e2015-02-23 16:07:24 -05002859 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
Russ Cox8c195bd2015-02-13 14:40:36 -05002860
2861 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Russ Cox382b44e2015-02-23 16:07:24 -05002862 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
Russ Cox8c195bd2015-02-13 14:40:36 -05002863 l = list(l, nt)
2864 }
2865
2866 // s = s[:len(l1)+len(l2)]
2867 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
2868
2869 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
2870 nt.Etype = 1
2871 l = list(l, Nod(OAS, s, nt))
2872
2873 typechecklist(l, Etop)
2874 walkstmtlist(l)
2875 *init = concat(*init, l)
2876 return s
2877}
2878
Russ Cox85520472015-05-06 12:34:30 -04002879// Rewrite append(src, x, y, z) so that any side effects in
2880// x, y, z (including runtime panics) are evaluated in
2881// initialization statements before the append.
2882// For normal code generation, stop there and leave the
2883// rest to cgen_append.
2884//
2885// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002886//
2887// init {
2888// s := src
2889// const argc = len(args) - 1
2890// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002891// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002892// }
2893// n := len(s)
2894// s = s[:n+argc]
2895// s[n] = a
2896// s[n+1] = b
2897// ...
2898// }
2899// s
Russ Cox85520472015-05-06 12:34:30 -04002900func walkappend(n *Node, init **NodeList, dst *Node) *Node {
2901 if !samesafeexpr(dst, n.List.N) {
2902 l := n.List
2903 l.N = safeexpr(l.N, init)
2904 walkexpr(&l.N, init)
2905 }
2906 walkexprlistsafe(n.List.Next, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002907
2908 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2909 // and n are name or literal, but those may index the slice we're
2910 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002911 // Using cheapexpr also makes sure that the evaluation
2912 // of all arguments (and especially any panics) happen
2913 // before we begin to modify the slice in a visible way.
2914 for l := n.List.Next; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002915 l.N = cheapexpr(l.N, init)
2916 }
2917
Russ Cox382b44e2015-02-23 16:07:24 -05002918 nsrc := n.List.N
Russ Cox8c195bd2015-02-13 14:40:36 -05002919
2920 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002921 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002922 nsrc.Type = nsrc.Type.Type.Type
2923 }
Russ Cox382b44e2015-02-23 16:07:24 -05002924 argc := count(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002925 if argc < 1 {
2926 return nsrc
2927 }
2928
Russ Cox85520472015-05-06 12:34:30 -04002929 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002930 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002931 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002932 return n
2933 }
2934
Russ Cox175929b2015-03-02 14:22:05 -05002935 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002936
Russ Cox382b44e2015-02-23 16:07:24 -05002937 ns := temp(nsrc.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002938 l = list(l, Nod(OAS, ns, nsrc)) // s = src
2939
Russ Cox382b44e2015-02-23 16:07:24 -05002940 na := Nodintconst(int64(argc)) // const argc
2941 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002942 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002943
Russ Cox32fddad2015-06-25 19:27:20 -04002944 fn := syslook("growslice", 1) // growslice(<type>, old []T, mincap int) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002945 substArgTypes(fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002946
Russ Cox32fddad2015-06-25 19:27:20 -04002947 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 -05002948
2949 l = list(l, nx)
2950
Russ Cox382b44e2015-02-23 16:07:24 -05002951 nn := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002952 l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
2953
2954 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
2955 nx.Etype = 1
2956 l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
2957
Russ Cox382b44e2015-02-23 16:07:24 -05002958 for a := n.List.Next; a != nil; a = a.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002959 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05002960 nx.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002961 l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg
2962 if a.Next != nil {
2963 l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
2964 }
2965 }
2966
2967 typechecklist(l, Etop)
2968 walkstmtlist(l)
2969 *init = concat(*init, l)
2970 return ns
2971}
2972
2973// Lower copy(a, b) to a memmove call or a runtime call.
2974//
2975// init {
2976// n := len(a)
2977// if n > len(b) { n = len(b) }
2978// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
2979// }
2980// n;
2981//
2982// Also works if b is a string.
2983//
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002984func copyany(n *Node, init **NodeList, runtimecall bool) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002985 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05002986 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002987 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
2988 }
2989
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002990 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05002991 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002992 if n.Right.Type.Etype == TSTRING {
2993 fn = syslook("slicestringcopy", 1)
2994 } else {
2995 fn = syslook("slicecopy", 1)
2996 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002997 substArgTypes(fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002998 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
2999 }
3000
3001 walkexpr(&n.Left, init)
3002 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003003 nl := temp(n.Left.Type)
3004 nr := temp(n.Right.Type)
Russ Cox175929b2015-03-02 14:22:05 -05003005 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003006 l = list(l, Nod(OAS, nl, n.Left))
3007 l = list(l, Nod(OAS, nr, n.Right))
3008
Russ Cox382b44e2015-02-23 16:07:24 -05003009 nfrm := Nod(OSPTR, nr, nil)
3010 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003011
Russ Cox382b44e2015-02-23 16:07:24 -05003012 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003013
3014 // n = len(to)
3015 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
3016
3017 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003018 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003019
Russ Cox66be1482015-05-26 21:30:20 -04003020 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003021 nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
3022 l = list(l, nif)
3023
3024 // Call memmove.
Russ Cox382b44e2015-02-23 16:07:24 -05003025 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003026
Russ Cox13f9c8b2015-03-08 13:33:49 -04003027 substArgTypes(fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003028 nwid := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -05003029 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
3030 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
3031 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
3032
3033 typechecklist(l, Etop)
3034 walkstmtlist(l)
3035 *init = concat(*init, l)
3036 return nlen
3037}
3038
Russ Cox8c195bd2015-02-13 14:40:36 -05003039func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003040 // Should only arrive here with large memory or
3041 // a struct/array containing a non-memory field/element.
3042 // Small memory is handled inline, and single non-memory
3043 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003044 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003045
3046 if a != AMEM && a != -1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003047 Fatalf("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003048 }
3049
3050 if a == AMEM {
Russ Cox382b44e2015-02-23 16:07:24 -05003051 n := syslook("memequal", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003052 substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003053 *needsize = 1
3054 return n
3055 }
3056
Russ Cox382b44e2015-02-23 16:07:24 -05003057 sym := typesymprefix(".eq", t)
3058 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003059 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003060 ntype := Nod(OTFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003061 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3062 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3063 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3064 typecheck(&ntype, Etype)
3065 n.Type = ntype.Type
3066 *needsize = 0
3067 return n
3068}
3069
3070func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003071 n := 0
3072 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003073 n++
3074 }
3075 return n
3076}
3077
3078func walkcompare(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003079 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003080
3081 // Given interface value l and concrete value r, rewrite
3082 // l == r
3083 // to
3084 // x, ok := l.(type(r)); ok && x == r
3085 // Handle != similarly.
3086 // This avoids the allocation that would be required
3087 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003088 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003089
Russ Cox175929b2015-03-02 14:22:05 -05003090 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003091 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003092 l = n.Left
3093 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003094 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003095 l = n.Right
3096 r = n.Left
3097 }
3098
3099 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003100 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003101 if haspointers(r.Type) {
3102 a := Nod(OAS, x, nil)
3103 typecheck(&a, Etop)
3104 *init = list(*init, a)
3105 }
Russ Cox382b44e2015-02-23 16:07:24 -05003106 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003107
3108 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003109 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003110
3111 a.Type = r.Type
3112
3113 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003114 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003115
3116 expr.List = list1(x)
3117 expr.List = list(expr.List, ok)
3118 expr.Rlist = list1(a)
3119 typecheck(&expr, Etop)
3120 walkexpr(&expr, init)
3121
3122 if n.Op == OEQ {
3123 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3124 } else {
3125 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3126 }
3127 *init = list(*init, expr)
Russ Cox44928112015-03-02 20:34:22 -05003128 finishcompare(np, n, r, init)
3129 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003130 }
3131
3132 // Must be comparison of array or struct.
3133 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003134 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003135
3136 switch t.Etype {
3137 default:
3138 return
3139
3140 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003141 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003142 return
3143 }
3144
3145 case TSTRUCT:
3146 break
3147 }
3148
Russ Cox44928112015-03-02 20:34:22 -05003149 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003150 for cmpl != nil && cmpl.Op == OCONVNOP {
3151 cmpl = cmpl.Left
3152 }
Russ Cox44928112015-03-02 20:34:22 -05003153 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003154 for cmpr != nil && cmpr.Op == OCONVNOP {
3155 cmpr = cmpr.Left
3156 }
3157
Russ Coxdc7b54b2015-02-17 22:13:49 -05003158 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003159 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003160 }
3161
3162 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003163 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003164 a.Right.Etype = 1 // addr does not escape
3165 typecheck(&a, Etop)
3166 *init = list(*init, a)
3167
3168 r = temp(Ptrto(t))
3169 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3170 a.Right.Etype = 1 // addr does not escape
3171 typecheck(&a, Etop)
3172 *init = list(*init, a)
3173
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003174 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003175 if n.Op == ONE {
3176 andor = OOROR
3177 }
3178
Russ Cox44928112015-03-02 20:34:22 -05003179 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003180 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003181 // Four or fewer elements of a basic type.
3182 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003183 var li *Node
3184 var ri *Node
3185 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003186 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3187 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003188 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003189 if expr == nil {
3190 expr = a
3191 } else {
3192 expr = Nod(andor, expr, a)
3193 }
3194 }
3195
3196 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003197 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003198 }
Russ Cox44928112015-03-02 20:34:22 -05003199 finishcompare(np, n, expr, init)
3200 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 }
3202
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003203 if t.Etype == TARRAY {
3204 // Zero- or single-element array, of any type.
3205 switch t.Bound {
3206 case 0:
3207 finishcompare(np, n, Nodbool(n.Op == OEQ), init)
3208 return
3209 case 1:
3210 l0 := Nod(OINDEX, l, Nodintconst(0))
3211 r0 := Nod(OINDEX, r, Nodintconst(0))
3212 a := Nod(n.Op, l0, r0)
3213 finishcompare(np, n, a, init)
3214 return
3215 }
3216 }
3217
Russ Cox8c195bd2015-02-13 14:40:36 -05003218 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3219 // Struct of four or fewer fields.
3220 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003221 var li *Node
3222 var ri *Node
3223 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003224 if isblanksym(t1.Sym) {
3225 continue
3226 }
3227 li = Nod(OXDOT, l, newname(t1.Sym))
3228 ri = Nod(OXDOT, r, newname(t1.Sym))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003229 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003230 if expr == nil {
3231 expr = a
3232 } else {
3233 expr = Nod(andor, expr, a)
3234 }
3235 }
3236
3237 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003238 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003239 }
Russ Cox44928112015-03-02 20:34:22 -05003240 finishcompare(np, n, expr, init)
3241 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003242 }
3243
3244 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003245 var needsize int
3246 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003247
3248 call.List = list(call.List, l)
3249 call.List = list(call.List, r)
3250 if needsize != 0 {
3251 call.List = list(call.List, Nodintconst(t.Width))
3252 }
3253 r = call
3254 if n.Op != OEQ {
3255 r = Nod(ONOT, r, nil)
3256 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003257
Russ Cox44928112015-03-02 20:34:22 -05003258 finishcompare(np, n, r, init)
3259 return
3260}
3261
3262func finishcompare(np **Node, n, r *Node, init **NodeList) {
3263 // Using np here to avoid passing &r to typecheck.
3264 *np = r
3265 typecheck(np, Erv)
3266 walkexpr(np, init)
3267 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003268 if r.Type != n.Type {
3269 r = Nod(OCONVNOP, r, nil)
3270 r.Type = n.Type
3271 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003272 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003273 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003274}
3275
Russ Coxdc7b54b2015-02-17 22:13:49 -05003276func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003277 var ar *Node
3278 var br *Node
3279 for a != nil && b != nil && a.Op == b.Op {
3280 switch a.Op {
3281 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003282 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003283
3284 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003285 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003286
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003287 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003288 ar = a.Right
3289 br = b.Right
3290 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003291 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003292 }
3293
3294 case OINDEX:
3295 ar = a.Right
3296 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003297 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003298 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003299 }
3300 }
3301
3302 a = a.Left
3303 b = b.Left
3304 }
3305
Russ Coxdc7b54b2015-02-17 22:13:49 -05003306 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003307}
3308
3309func walkrotate(np **Node) {
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003310 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003311 return
3312 }
3313
Russ Cox382b44e2015-02-23 16:07:24 -05003314 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003315
3316 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003317 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003318
Russ Cox382b44e2015-02-23 16:07:24 -05003319 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003320 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 -05003321 return
3322 }
3323
3324 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003325 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003326 return
3327 }
3328
3329 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003330 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003331
Russ Coxdc7b54b2015-02-17 22:13:49 -05003332 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003333 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003334 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003335 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003336 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003337 // Rewrite left shift half to left rotate.
3338 if l.Op == OLSH {
3339 n = l
3340 } else {
3341 n = r
3342 }
3343 n.Op = OLROT
3344
3345 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003346 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003347
3348 if s == 0 || s == w {
3349 n = n.Left
3350 }
3351
3352 *np = n
3353 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003354 }
3355 }
3356 return
3357 }
3358
3359 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3360 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003361}
3362
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003363// walkmul rewrites integer multiplication by powers of two as shifts.
Russ Cox8c195bd2015-02-13 14:40:36 -05003364func walkmul(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003365 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003366 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003367 return
3368 }
3369
Russ Cox382b44e2015-02-23 16:07:24 -05003370 var nr *Node
3371 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003372 if n.Right.Op == OLITERAL {
3373 nl = n.Left
3374 nr = n.Right
3375 } else if n.Left.Op == OLITERAL {
3376 nl = n.Right
3377 nr = n.Left
3378 } else {
3379 return
3380 }
3381
Russ Cox382b44e2015-02-23 16:07:24 -05003382 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003383
3384 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003385 var pow int
3386 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003387 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003388 cheapexpr(nl, init)
3389 Nodconst(n, n.Type, 0)
3390 goto ret
3391 }
3392
3393 // nr is a constant.
3394 pow = powtwo(nr)
3395
3396 if pow < 0 {
3397 return
3398 }
3399 if pow >= 1000 {
3400 // negative power of 2, like -16
3401 neg = 1
3402
3403 pow -= 1000
3404 }
3405
3406 w = int(nl.Type.Width * 8)
3407 if pow+1 >= w { // too big, shouldn't happen
3408 return
3409 }
3410
3411 nl = cheapexpr(nl, init)
3412
3413 if pow == 0 {
3414 // x*1 is x
3415 n = nl
3416
3417 goto ret
3418 }
3419
3420 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3421
3422ret:
3423 if neg != 0 {
3424 n = Nod(OMINUS, n, nil)
3425 }
3426
3427 typecheck(&n, Erv)
3428 walkexpr(&n, init)
3429 *np = n
3430}
3431
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003432// walkdiv rewrites division by a constant as less expensive
3433// operations.
Russ Cox8c195bd2015-02-13 14:40:36 -05003434func walkdiv(np **Node, init **NodeList) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003435 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003436
3437 // TODO(minux)
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003438 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003439 return
3440 }
3441
Russ Cox382b44e2015-02-23 16:07:24 -05003442 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003443 if n.Right.Op != OLITERAL {
3444 return
3445 }
3446
3447 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003448 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003449
Russ Cox382b44e2015-02-23 16:07:24 -05003450 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003451
3452 // special cases of mod/div
3453 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003454 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003455
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003456 s := 0 // 1 if nr is negative.
3457 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003458 if pow >= 1000 {
3459 // negative power of 2
3460 s = 1
3461
3462 pow -= 1000
3463 }
3464
3465 if pow+1 >= w {
3466 // divisor too large.
3467 return
3468 }
3469
3470 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003471 // try to do division by multiply by (2^w)/d
3472 // see hacker's delight chapter 10
3473 // TODO: support 64-bit magic multiply here.
3474 var m Magic
3475 m.W = w
3476
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003477 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003478 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003479 Smagic(&m)
3480 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003481 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003482 Umagic(&m)
3483 }
3484
3485 if m.Bad != 0 {
3486 return
3487 }
3488
3489 // We have a quick division method so use it
3490 // for modulo too.
3491 if n.Op == OMOD {
3492 // rewrite as A%B = A - (A/B*B).
3493 n1 := Nod(ODIV, nl, nr)
3494
3495 n2 := Nod(OMUL, n1, nr)
3496 n = Nod(OSUB, nl, n2)
3497 goto ret
3498 }
3499
3500 switch Simtype[nl.Type.Etype] {
3501 default:
3502 return
3503
3504 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003505 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003506 nc := Nod(OXXX, nil, nil)
3507
3508 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003509 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003510 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003511 if m.Ua != 0 {
3512 // Select a Go type with (at least) twice the width.
3513 var twide *Type
3514 switch Simtype[nl.Type.Etype] {
3515 default:
3516 return
3517
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003518 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003519 twide = Types[TUINT32]
3520
3521 case TUINT32:
3522 twide = Types[TUINT64]
3523
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003524 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003525 twide = Types[TINT32]
3526
3527 case TINT32:
3528 twide = Types[TINT64]
3529 }
3530
3531 // add numerator (might overflow).
3532 // n2 = (n1 + nl)
3533 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3534
3535 // shift by m.s
3536 nc := Nod(OXXX, nil, nil)
3537
3538 Nodconst(nc, Types[TUINT], int64(m.S))
3539 n = conv(Nod(ORSH, n2, nc), nl.Type)
3540 } else {
3541 // n = n1 >> m.s
3542 nc := Nod(OXXX, nil, nil)
3543
3544 Nodconst(nc, Types[TUINT], int64(m.S))
3545 n = Nod(ORSH, n1, nc)
3546 }
3547
3548 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003549 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003550 nc := Nod(OXXX, nil, nil)
3551
3552 Nodconst(nc, nl.Type, m.Sm)
Todd Neal765c0f32015-06-23 18:59:52 -05003553 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003554 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003555 if m.Sm < 0 {
3556 // add the numerator.
3557 n1 = Nod(OADD, n1, nl)
3558 }
3559
3560 // shift by m.s
3561 nc = Nod(OXXX, nil, nil)
3562
3563 Nodconst(nc, Types[TUINT], int64(m.S))
3564 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3565
3566 // add 1 iff n1 is negative.
3567 nc = Nod(OXXX, nil, nil)
3568
3569 Nodconst(nc, Types[TUINT], int64(w)-1)
3570 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3571 n = Nod(OSUB, n2, n3)
3572
3573 // apply sign.
3574 if m.Sd < 0 {
3575 n = Nod(OMINUS, n, nil)
3576 }
3577 }
3578
3579 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003580 }
3581
3582 switch pow {
3583 case 0:
3584 if n.Op == OMOD {
3585 // nl % 1 is zero.
3586 Nodconst(n, n.Type, 0)
3587 } else if s != 0 {
3588 // divide by -1
3589 n.Op = OMINUS
3590
3591 n.Right = nil
3592 } else {
3593 // divide by 1
3594 n = nl
3595 }
3596
3597 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003598 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003599 if n.Op == OMOD {
3600 // signed modulo 2^pow is like ANDing
3601 // with the last pow bits, but if nl < 0,
3602 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003603 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003604
3605 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003606 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003607 if pow == 1 {
3608 typecheck(&n1, Erv)
3609 n1 = cheapexpr(n1, init)
3610
3611 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003612 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003613
Russ Cox382b44e2015-02-23 16:07:24 -05003614 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003615 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003616 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003617 n = Nod(OADD, n3, n1)
3618 } else {
3619 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003620 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003621
3622 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003623 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003624 typecheck(&n2, Erv)
3625 n2 = cheapexpr(n2, init)
3626
Russ Cox382b44e2015-02-23 16:07:24 -05003627 n3 := Nod(OADD, nl, n2)
3628 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003629 n = Nod(OSUB, n4, n2)
3630 }
3631
3632 break
3633 } else {
3634 // arithmetic right shift does not give the correct rounding.
3635 // if nl >= 0, nl >> n == nl / nr
3636 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003637 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003638
3639 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003640 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003641 if pow == 1 {
3642 // nl+1 is nl-(-1)
3643 n.Left = Nod(OSUB, nl, n1)
3644 } else {
3645 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003646 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003647
3648 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003649 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003650 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3651 }
3652
3653 // n = (nl + 2^pow-1) >> pow
3654 n.Op = ORSH
3655
3656 nc = Nod(OXXX, nil, nil)
3657 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3658 n.Right = nc
3659 n.Typecheck = 0
3660 }
3661
3662 if s != 0 {
3663 n = Nod(OMINUS, n, nil)
3664 }
3665 break
3666 }
3667
Russ Cox382b44e2015-02-23 16:07:24 -05003668 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003669 if n.Op == OMOD {
3670 // n = nl & (nr-1)
3671 n.Op = OAND
3672
Russ Cox81d58102015-05-27 00:47:05 -04003673 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003674 } else {
3675 // n = nl >> pow
3676 n.Op = ORSH
3677
3678 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3679 }
3680
3681 n.Typecheck = 0
3682 n.Right = nc
3683 }
3684
3685 goto ret
3686
Russ Cox8c195bd2015-02-13 14:40:36 -05003687ret:
3688 typecheck(&n, Erv)
3689 walkexpr(&n, init)
3690 *np = n
3691}
3692
3693// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003694func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003695 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003696 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003697 }
3698
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003699 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003700 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003701
Russ Coxdc7b54b2015-02-17 22:13:49 -05003702 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003703 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003704 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003705 }
3706
3707 switch n.Op {
3708 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003709 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003710 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003711 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003712 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003713 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003714 }
3715
3716 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003717 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003718 }
3719
3720 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003721 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003722 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003723 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003724 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003725 }
3726 }
3727
3728 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003729 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003730 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003731 for bits > 0 && v >= 2 {
3732 bits--
3733 v >>= 1
3734 }
3735 }
3736
3737 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003738 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003739 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003740 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003741 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003742 }
3743 bits -= int32(v)
3744 }
3745 }
3746
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003747 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003748 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003749 }
3750
Russ Coxdc7b54b2015-02-17 22:13:49 -05003751 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003752}
3753
3754func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003755 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003756 return
3757 }
3758
3759 switch n.Op {
3760 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003761 Fatalf("usefield %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003762
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003763 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003764 break
3765 }
3766
Russ Cox496ad0a2015-05-26 21:49:31 -04003767 t := n.Left.Type
3768 if Isptr[t.Etype] {
3769 t = t.Type
3770 }
Russ Coxf68d1df2015-08-17 21:38:46 -04003771 field := dotField[typeSym{t.Orig, n.Right.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003772 if field == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003773 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003774 }
Russ Coxbed1f902015-03-02 16:03:26 -05003775 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003776 return
3777 }
3778
3779 // dedup on list
3780 if field.Lastfn == Curfn {
3781 return
3782 }
3783 field.Lastfn = Curfn
3784 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003785 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003786 field.Outer = field.Outer.Type
3787 }
3788 if field.Outer.Sym == nil {
3789 Yyerror("tracked field must be in named struct type")
3790 }
3791 if !exportname(field.Sym.Name) {
3792 Yyerror("tracked field must be exported (upper case)")
3793 }
3794
Russ Cox496ad0a2015-05-26 21:49:31 -04003795 Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
Russ Cox8c195bd2015-02-13 14:40:36 -05003796}
3797
Russ Coxdc7b54b2015-02-17 22:13:49 -05003798func candiscardlist(l *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003799 for ; l != nil; l = l.Next {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003800 if !candiscard(l.N) {
3801 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003802 }
3803 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003804 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003805}
3806
Russ Coxdc7b54b2015-02-17 22:13:49 -05003807func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003808 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003809 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003810 }
3811
3812 switch n.Op {
3813 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003814 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003815
3816 // Discardable as long as the subpieces are.
3817 case ONAME,
3818 ONONAME,
3819 OTYPE,
3820 OPACK,
3821 OLITERAL,
3822 OADD,
3823 OSUB,
3824 OOR,
3825 OXOR,
3826 OADDSTR,
3827 OADDR,
3828 OANDAND,
3829 OARRAYBYTESTR,
3830 OARRAYRUNESTR,
3831 OSTRARRAYBYTE,
3832 OSTRARRAYRUNE,
3833 OCAP,
3834 OCMPIFACE,
3835 OCMPSTR,
3836 OCOMPLIT,
3837 OMAPLIT,
3838 OSTRUCTLIT,
3839 OARRAYLIT,
3840 OPTRLIT,
3841 OCONV,
3842 OCONVIFACE,
3843 OCONVNOP,
3844 ODOT,
3845 OEQ,
3846 ONE,
3847 OLT,
3848 OLE,
3849 OGT,
3850 OGE,
3851 OKEY,
3852 OLEN,
3853 OMUL,
3854 OLSH,
3855 ORSH,
3856 OAND,
3857 OANDNOT,
3858 ONEW,
3859 ONOT,
3860 OCOM,
3861 OPLUS,
3862 OMINUS,
3863 OOROR,
3864 OPAREN,
3865 ORUNESTR,
3866 OREAL,
3867 OIMAG,
3868 OCOMPLEX:
3869 break
3870
3871 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003872 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003873 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003874 break
3875 }
Russ Cox81d58102015-05-27 00:47:05 -04003876 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003877 break
3878 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003879 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003880
3881 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003882 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003883 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003884 break
3885 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003886 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003887
3888 // Difficult to tell what sizes are okay.
3889 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003890 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003891 }
3892
Russ Cox66be1482015-05-26 21:30:20 -04003893 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 -05003894 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
3900// rewrite
3901// print(x, y, z)
3902// into
3903// func(a1, a2, a3) {
3904// print(a1, a2, a3)
3905// }(x, y, z)
3906// and same for println.
3907
3908var walkprintfunc_prgen int
3909
3910func walkprintfunc(np **Node, init **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05003911 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003912
3913 if n.Ninit != nil {
3914 walkstmtlist(n.Ninit)
3915 *init = concat(*init, n.Ninit)
3916 n.Ninit = nil
3917 }
3918
Russ Cox382b44e2015-02-23 16:07:24 -05003919 t := Nod(OTFUNC, nil, nil)
3920 num := 0
Russ Cox175929b2015-03-02 14:22:05 -05003921 var printargs *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05003922 var a *Node
3923 var buf string
3924 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05003925 buf = fmt.Sprintf("a%d", num)
3926 num++
3927 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
3928 t.List = list(t.List, a)
3929 printargs = list(printargs, a.Left)
3930 }
3931
Russ Cox382b44e2015-02-23 16:07:24 -05003932 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003933 walkprintfunc_prgen++
3934 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003935 fn.Func.Nname = newname(Lookup(buf))
3936 fn.Func.Nname.Name.Defn = fn
3937 fn.Func.Nname.Name.Param.Ntype = t
3938 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003939
Russ Cox382b44e2015-02-23 16:07:24 -05003940 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05003941 Curfn = nil
3942 funchdr(fn)
3943
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003944 a = Nod(n.Op, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003945 a.List = printargs
3946 typecheck(&a, Etop)
3947 walkstmt(&a)
3948
3949 fn.Nbody = list1(a)
3950
3951 funcbody(fn)
3952
3953 typecheck(&fn, Etop)
3954 typechecklist(fn.Nbody, Etop)
3955 xtop = list(xtop, fn)
3956 Curfn = oldfn
3957
3958 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04003959 a.Left = fn.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -05003960 a.List = n.List
3961 typecheck(&a, Etop)
3962 walkexpr(&a, init)
3963 *np = a
3964}