blob: ca77fc9fbfc193e1e482834afed52d333d5223c4 [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)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080025 dumplist(s, Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050026 }
27
Robert Griesemerc41608f2016-03-02 17:34:42 -080028 lno := 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
Robert Griesemerc41608f2016-03-02 17:34:42 -080063 lineno = lno
Russ Cox8c195bd2015-02-13 14:40:36 -050064 if nerrors != 0 {
65 return
66 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -080067 walkstmtlist(Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050068 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040069 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080070 dumplist(s, Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050071 }
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 Taylor55c65d42016-03-04 13:16:48 -080076 dumplist(s, Curfn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050077 }
78}
79
Ian Lance Taylor132ebea2016-03-03 20:48:00 -080080func walkstmtlist(l nodesOrNodeList) {
81 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
82 walkstmt(it.P())
Russ Cox8c195bd2015-02-13 14:40:36 -050083 }
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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800125 for argsit := nodeSeqIterate(callfunc.List); !argsit.Done(); argsit.Next() {
126 arg = argsit.N()
Russ Cox8c195bd2015-02-13 14:40:36 -0500127 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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800195 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500196 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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800209 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500210
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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800261 setNodeSeq(&n.Left.Ninit, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400262 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)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800267 walkstmtlist(n.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -0500268
269 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400270 walkexpr(&n.Left, &n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800271 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)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800291 if nodeSeqLen(n.List) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500292 break
293 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800294 if (Curfn.Type.Outnamed && nodeSeqLen(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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800310 if got, want := nodeSeqLen(n.List), nodeSeqLen(rl); got != want {
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800311 // 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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800318 setNodeSeq(&n.List, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500319
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)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800327 setNodeSeq(&n.List, reorder3(ll))
328 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
329 *it.P() = applywritebarrier(it.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)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800335 setNodeSeq(&n.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500336
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
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800380func walkexprlist(l nodesOrNodeList, init nodesOrNodeListPtr) {
381 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
382 walkexpr(it.P(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500383 }
384}
385
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800386func walkexprlistsafe(l nodesOrNodeList, init nodesOrNodeListPtr) {
387 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
388 *it.P() = safeexpr(it.N(), init)
389 walkexpr(it.P(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500390 }
391}
392
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800393func walkexprlistcheap(l nodesOrNodeList, init nodesOrNodeListPtr) {
394 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
395 *it.P() = cheapexpr(it.N(), init)
396 walkexpr(it.P(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500397 }
398}
399
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000400// Build name of function: convI2E etc.
401// Not all names are possible
402// (e.g., we'll never generate convE2E or convE2I).
403func convFuncName(from, to *Type) string {
404 tkind := to.iet()
405 switch from.iet() {
406 case 'I':
407 switch tkind {
408 case 'E':
409 return "convI2E"
410 case 'I':
411 return "convI2I"
412 }
413 case 'T':
414 switch tkind {
415 case 'E':
416 return "convT2E"
417 case 'I':
418 return "convT2I"
419 }
420 }
421 Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
422 panic("unreachable")
423}
424
425// Build name of function: assertI2E etc.
426// If with2suffix is true, the form ending in "2" is returned".
427func assertFuncName(from, to *Type, with2suffix bool) string {
428 l := len("assertX2X2")
429 if !with2suffix {
430 l--
431 }
432 tkind := to.iet()
433 switch from.iet() {
434 case 'E':
435 switch tkind {
436 case 'I':
437 return "assertE2I2"[:l]
438 case 'E':
439 return "assertE2E2"[:l]
440 case 'T':
441 return "assertE2T2"[:l]
442 }
443 case 'I':
444 switch tkind {
445 case 'I':
446 return "assertI2I2"[:l]
447 case 'E':
448 return "assertI2E2"[:l]
449 case 'T':
450 return "assertI2T2"[:l]
451 }
452 }
453 Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
454 panic("unreachable")
455}
456
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800457func walkexpr(np **Node, init nodesOrNodeListPtr) {
Russ Cox382b44e2015-02-23 16:07:24 -0500458 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500459
460 if n == nil {
461 return
462 }
463
464 if init == &n.Ninit {
465 // not okay to use n->ninit when walking n,
466 // because we might replace n with some other node
467 // and would lose the init list.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200468 Fatalf("walkexpr init == &n->ninit")
Russ Cox8c195bd2015-02-13 14:40:36 -0500469 }
470
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800471 if nodeSeqLen(n.Ninit) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500472 walkstmtlist(n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800473 appendNodeSeq(init, n.Ninit)
474 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500475 }
476
477 // annoying case - not typechecked
478 if n.Op == OKEY {
479 walkexpr(&n.Left, init)
480 walkexpr(&n.Right, init)
481 return
482 }
483
Russ Cox382b44e2015-02-23 16:07:24 -0500484 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500485
486 if Debug['w'] > 1 {
487 Dump("walk-before", n)
488 }
489
490 if n.Typecheck != 1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200491 Fatalf("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500492 }
493
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200494opswitch:
Russ Cox8c195bd2015-02-13 14:40:36 -0500495 switch n.Op {
496 default:
497 Dump("walk", n)
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200498 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500499
500 case OTYPE,
501 ONONAME,
502 OINDREG,
503 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400504 OPARAM,
505 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500506
507 case ONOT,
508 OMINUS,
509 OPLUS,
510 OCOM,
511 OREAL,
512 OIMAG,
513 ODOTMETH,
514 ODOTINTER:
515 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500516
517 case OIND:
518 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500519
520 case ODOT:
521 usefield(n)
522 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500523
524 case ODOTPTR:
525 usefield(n)
526 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
527 // No actual copy will be generated, so emit an explicit nil check.
528 n.Left = cheapexpr(n.Left, init)
529
530 checknil(n.Left, init)
531 }
532
533 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500534
535 case OEFACE:
536 walkexpr(&n.Left, init)
537 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500538
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700539 case OSPTR, OITAB:
Russ Cox8c195bd2015-02-13 14:40:36 -0500540 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500541
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700542 case OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500543 walkexpr(&n.Left, init)
544
545 // replace len(*[10]int) with 10.
546 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500547 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500548
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000549 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500550 t = t.Type
551 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500552 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500553 safeexpr(n.Left, init)
554 Nodconst(n, n.Type, t.Bound)
555 n.Typecheck = 1
556 }
557
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700558 case OLSH, ORSH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500559 walkexpr(&n.Left, init)
560 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500561 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500562 n.Bounded = bounded(n.Right, 8*t.Width)
563 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500564 Warn("shift bounds check elided")
565 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500566
567 // Use results from call expression as arguments for complex.
568 case OAND,
569 OSUB,
570 OHMUL,
571 OLT,
572 OLE,
573 OGE,
574 OGT,
575 OADD,
576 OCOMPLEX,
577 OLROT:
578 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800579 n.Left = nodeSeqFirst(n.List)
580 n.Right = nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500581 }
582
583 walkexpr(&n.Left, init)
584 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500585
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700586 case OOR, OXOR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500587 walkexpr(&n.Left, init)
588 walkexpr(&n.Right, init)
589 walkrotate(&n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500590
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700591 case OEQ, ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500592 walkexpr(&n.Left, init)
593 walkexpr(&n.Right, init)
594
595 // Disable safemode while compiling this code: the code we
596 // generate internally can refer to unsafe.Pointer.
597 // In this case it can happen if we need to generate an ==
598 // for a struct containing a reflect.Value, which itself has
599 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500600 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500601
602 safemode = 0
603 walkcompare(&n, init)
604 safemode = old_safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500605
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700606 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500607 walkexpr(&n.Left, init)
608
David Chaseffe7fbf2015-03-27 12:34:45 -0400609 // cannot put side effects from n.Right on init,
610 // because they cannot run before n.Left is checked.
611 // save elsewhere and store on the eventual n.Right.
Russ Cox175929b2015-03-02 14:22:05 -0500612 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500613
614 walkexpr(&n.Right, &ll)
615 addinit(&n.Right, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500616
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700617 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500618 walkexprlist(n.List, init)
619 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500620
621 case OPANIC:
622 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500623
624 case ORECOVER:
625 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500626
627 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700628 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500629
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700630 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700631 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500632
633 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500634 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700635 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500636 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500637
638 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500639 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800640 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).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, n.Isddd, getinarg(t), n.List, 0, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800646 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500647
648 case OCALLFUNC:
649 if n.Left.Op == OCLOSURE {
650 // Transform direct call of a closure to call of a normal function.
651 // transformclosure already did all preparation work.
652
David Chase731dcda2015-07-23 14:17:07 -0400653 // Prepend captured variables to argument list.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800654 setNodeSeq(&n.List, concat(n.Left.Func.Enter.NodeList(), n.List))
Russ Cox8c195bd2015-02-13 14:40:36 -0500655
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800656 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500657
658 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400659 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500660
661 // Update type of OCALLFUNC node.
662 // Output arguments had not changed, but their offsets could.
663 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500664 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500665 if t.Etype == TFIELD {
666 t = t.Type
667 }
668 n.Type = t
669 } else {
670 n.Type = getoutargx(n.Left.Type)
671 }
672 }
673
Russ Cox382b44e2015-02-23 16:07:24 -0500674 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800675 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200676 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500677 }
678
679 walkexpr(&n.Left, init)
680 walkexprlist(n.List, init)
681
Russ Cox92dba0d2015-04-01 16:02:34 -0400682 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
683 switch Thearch.Thechar {
Shenghou Ma764c7512015-04-03 18:15:26 -0400684 case '5', '6', '7':
Russ Cox92dba0d2015-04-01 16:02:34 -0400685 n.Op = OSQRT
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800686 n.Left = nodeSeqFirst(n.List)
687 setNodeSeq(&n.List, nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200688 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400689 }
690 }
691
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200692 ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800693 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500694
695 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500696 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800697 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200698 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500699 }
700 walkexpr(&n.Left, init)
701 walkexprlist(n.List, init)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200702 ll := ascompatte(n.Op, n, false, getthis(t), list1(n.Left.Left), 0, init)
703 lr := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500704 ll = concat(ll, lr)
705 n.Left.Left = nil
706 ullmancalc(n.Left)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800707 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500708
709 case OAS:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800710 appendNodeSeq(init, n.Ninit)
711 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500712
713 walkexpr(&n.Left, init)
714 n.Left = safeexpr(n.Left, init)
715
Russ Coxdc7b54b2015-02-17 22:13:49 -0500716 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200717 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500718 }
719
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700720 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200721 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500722 }
723
724 switch n.Right.Op {
725 default:
726 walkexpr(&n.Right, init)
727
Russ Cox8c195bd2015-02-13 14:40:36 -0500728 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400729 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
730 // It needs to be removed in all three places.
731 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700732 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400733 // handled directly during cgen
734 walkexpr(&n.Right, init)
735 break
736 }
737
David Chaseffe7fbf2015-03-27 12:34:45 -0400738 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400739 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500740 walkexpr(&n.Right.Left, init)
741
Russ Cox382b44e2015-02-23 16:07:24 -0500742 n1 := Nod(OADDR, n.Left, nil)
743 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500744
Russ Cox4224d812015-03-20 00:06:10 -0400745 if Debug_typeassert > 0 {
746 Warn("type assertion not inlined")
747 }
748
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000749 fn := syslook(assertFuncName(r.Left.Type, r.Type, false), 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400750 substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500751
752 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
753 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200754 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500755
Russ Cox8c195bd2015-02-13 14:40:36 -0500756 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400757 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400758 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500759 walkexpr(&n.Right.Left, init)
760
Russ Cox382b44e2015-02-23 16:07:24 -0500761 n1 := Nod(OADDR, n.Left, nil)
762 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500763 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
764 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200765 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400766
767 case OAPPEND:
768 // x = append(...)
769 r := n.Right
770 if r.Isddd {
771 r = appendslice(r, init) // also works for append(slice, string).
772 } else {
773 r = walkappend(r, init, n)
774 }
775 n.Right = r
776 if r.Op == OAPPEND {
777 // Left in place for back end.
778 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200779 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400780 }
781 // Otherwise, lowered for race detector.
782 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500783 }
784
785 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500786 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500787 r.Dodata = n.Dodata
788 n = r
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800789 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500790 }
791
Russ Cox8c195bd2015-02-13 14:40:36 -0500792 case OAS2:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800793 appendNodeSeq(init, n.Ninit)
794 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 walkexprlistsafe(n.List, init)
796 walkexprlistsafe(n.Rlist, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500797 ll := ascompatee(OAS, n.List, n.Rlist, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500798 ll = reorder3(ll)
Russ Cox382b44e2015-02-23 16:07:24 -0500799 for lr := ll; lr != nil; lr = lr.Next {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800800 lr.N = applywritebarrier(lr.N)
Russ Cox8c195bd2015-02-13 14:40:36 -0500801 }
802 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500803
804 // a,b,... = fn()
805 case OAS2FUNC:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800806 appendNodeSeq(init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500807
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800808 setNodeSeq(&n.Ninit, nil)
809 r := nodeSeqFirst(n.Rlist)
Russ Cox8c195bd2015-02-13 14:40:36 -0500810 walkexprlistsafe(n.List, init)
811 walkexpr(&r, init)
812
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200813 ll := ascompatet(n.Op, n.List, &r.Type, 0, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500814 for lr := ll; lr != nil; lr = lr.Next {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800815 lr.N = applywritebarrier(lr.N)
Russ Cox8c195bd2015-02-13 14:40:36 -0500816 }
817 n = liststmt(concat(list1(r), ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500818
819 // x, y = <-c
820 // orderstmt made sure x is addressable.
821 case OAS2RECV:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800822 appendNodeSeq(init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500823
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800824 setNodeSeq(&n.Ninit, nil)
825 r := nodeSeqFirst(n.Rlist)
Russ Cox8c195bd2015-02-13 14:40:36 -0500826 walkexprlistsafe(n.List, init)
827 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500828 var n1 *Node
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800829 if isblank(nodeSeqFirst(n.List)) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500830 n1 = nodnil()
831 } else {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800832 n1 = Nod(OADDR, nodeSeqFirst(n.List), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500833 }
834 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500835 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800836 r = mkcall1(fn, nodeSeqSecond(n.List).Type, init, typename(r.Left.Type), r.Left, n1)
837 n = Nod(OAS, nodeSeqSecond(n.List), r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500838 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500839
840 // a,b = m[i];
841 case OAS2MAPR:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800842 appendNodeSeq(init, n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500843
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800844 setNodeSeq(&n.Ninit, nil)
845 r := nodeSeqFirst(n.Rlist)
Russ Cox8c195bd2015-02-13 14:40:36 -0500846 walkexprlistsafe(n.List, init)
847 walkexpr(&r.Left, init)
848 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500849 t := r.Left.Type
850 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500851 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800852 switch algtype(t.Down) {
853 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500854 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800855 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500856 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800857 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500858 p = "mapaccess2_faststr"
859 }
860 }
861
Russ Cox382b44e2015-02-23 16:07:24 -0500862 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500863 if p != "" {
864 // fast versions take key by value
865 key = r.Right
866 } else {
867 // standard version takes key by reference
868 // orderexpr made sure key is addressable.
869 key = Nod(OADDR, r.Right, nil)
870
871 p = "mapaccess2"
872 }
873
874 // from:
875 // a,b = m[i]
876 // to:
877 // var,b = mapaccess2*(t, m, i)
878 // a = *var
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800879 a := nodeSeqFirst(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500880
Russ Cox382b44e2015-02-23 16:07:24 -0500881 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500882 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
883
884 // mapaccess2* returns a typed bool, but due to spec changes,
885 // the boolean result of i.(T) is now untyped so we make it the
886 // same type as the variable on the lhs.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800887 if !isblank(nodeSeqSecond(n.List)) {
888 r.Type.Type.Down.Type = nodeSeqSecond(n.List).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500889 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800890 setNodeSeq(&n.Rlist, list1(r))
Russ Cox8c195bd2015-02-13 14:40:36 -0500891 n.Op = OAS2FUNC
892
893 // don't generate a = *var if a is _
894 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500895 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500896 var_.Typecheck = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800897 it := nodeSeqIterate(n.List)
898 *it.P() = var_
Russ Cox8c195bd2015-02-13 14:40:36 -0500899 walkexpr(&n, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800900 appendNodeSeqNode(init, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500901 n = Nod(OAS, a, Nod(OIND, var_, nil))
902 }
903
904 typecheck(&n, Etop)
905 walkexpr(&n, init)
906
Russ Cox8c195bd2015-02-13 14:40:36 -0500907 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
Russ Cox8c195bd2015-02-13 14:40:36 -0500908
909 case ODELETE:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800910 appendNodeSeq(init, n.Ninit)
911 setNodeSeq(&n.Ninit, nil)
912 map_ := nodeSeqFirst(n.List)
913 key := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500914 walkexpr(&map_, init)
915 walkexpr(&key, init)
916
917 // orderstmt made sure key is addressable.
918 key = Nod(OADDR, key, nil)
919
Russ Cox382b44e2015-02-23 16:07:24 -0500920 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500921 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500922
Russ Cox8c195bd2015-02-13 14:40:36 -0500923 case OAS2DOTTYPE:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800924 e := nodeSeqFirst(n.Rlist) // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400925 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
926 // It needs to be removed in all three places.
927 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700928 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400929 // handled directly during gen.
930 walkexprlistsafe(n.List, init)
931 walkexpr(&e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200932 break
Russ Cox4224d812015-03-20 00:06:10 -0400933 }
934
935 // res, ok = i.(T)
936 // orderstmt made sure a is addressable.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800937 appendNodeSeq(init, n.Ninit)
938 setNodeSeq(&n.Ninit, nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700939
Russ Cox8c195bd2015-02-13 14:40:36 -0500940 walkexprlistsafe(n.List, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700941 walkexpr(&e.Left, init)
942 t := e.Type // T
943 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500944
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700945 oktype := Types[TBOOL]
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800946 ok := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500947 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700948 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500949 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700950
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000951 fromKind := from.Type.iet()
952 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700953
954 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
955 // This is faster and shorter and allows the corresponding assertX2X2
956 // routines to skip nil checks on their last argument.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800957 if isblank(nodeSeqFirst(n.List)) {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700958 var fast *Node
959 switch {
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000960 case fromKind == 'E' && toKind == 'T':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700961 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
962 typ := Nod(OCONVNOP, typename(t), nil)
963 typ.Type = Ptrto(Types[TUINTPTR])
964 fast = Nod(OEQ, tab, typ)
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000965 case fromKind == 'I' && toKind == 'E',
966 fromKind == 'E' && toKind == 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700967 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700968 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700969 }
970 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400971 if Debug_typeassert > 0 {
972 Warn("type assertion (ok only) inlined")
973 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700974 n = Nod(OAS, ok, fast)
975 typecheck(&n, Etop)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200976 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700977 }
978 }
979
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700980 var resptr *Node // &res
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800981 if isblank(nodeSeqFirst(n.List)) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700982 resptr = nodnil()
983 } else {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800984 resptr = Nod(OADDR, nodeSeqFirst(n.List), nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700985 }
986 resptr.Etype = 1 // addr does not escape
987
Russ Cox4224d812015-03-20 00:06:10 -0400988 if Debug_typeassert > 0 {
989 Warn("type assertion not inlined")
990 }
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000991 fn := syslook(assertFuncName(from.Type, t, true), 1)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700992 substArgTypes(fn, from.Type, t)
993 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
994 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500995 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500996
Russ Cox4224d812015-03-20 00:06:10 -0400997 case ODOTTYPE, ODOTTYPE2:
998 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200999 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -04001000 }
1001 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001002
1003 case OCONVIFACE:
1004 walkexpr(&n.Left, init)
1005
1006 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001007 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05001008 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001009 l.Type = n.Type
1010 l.Typecheck = n.Typecheck
1011 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001012 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001013 }
1014
Russ Cox175929b2015-03-02 14:22:05 -05001015 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -05001016 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001017 ll = list(ll, typename(n.Left.Type))
1018 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001019 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001020 ll = list(ll, typename(n.Type))
1021 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001022 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Coxc8198342015-03-12 18:45:30 -04001023 sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -05001024 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -05001025 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001026 l.Sym = sym
1027 l.Type = Ptrto(Types[TUINT8])
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001028 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001029 l.Class = PEXTERN
1030 l.Xoffset = 0
1031 sym.Def = l
1032 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
1033 }
1034
Russ Cox382b44e2015-02-23 16:07:24 -05001035 l := Nod(OADDR, sym.Def, nil)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001036 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001037 ll = list(ll, l)
1038
Russ Coxdc7b54b2015-02-17 22:13:49 -05001039 if isdirectiface(n.Left.Type) {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001040 // For pointer types, we can make a special form of optimization
1041 //
1042 // These statements are put onto the expression init list:
1043 // Itab *tab = atomicloadtype(&cache);
1044 // if(tab == nil)
1045 // tab = typ2Itab(type, itype, &cache);
1046 //
1047 // The CONVIFACE expression is replaced with this:
1048 // OEFACE{tab, ptr};
Russ Cox382b44e2015-02-23 16:07:24 -05001049 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001050
Russ Cox382b44e2015-02-23 16:07:24 -05001051 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001052 typecheck(&n1, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001053 appendNodeSeqNode(init, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001054
Matthew Dempsky7f13fbf2016-03-04 07:55:39 -08001055 fn := syslook("typ2Itab", 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001056 n1 = Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001057 setNodeSeq(&n1.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001058 typecheck(&n1, Erv)
1059 walkexpr(&n1, init)
1060
Russ Cox382b44e2015-02-23 16:07:24 -05001061 n2 := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -04001062 n2.Left = Nod(OEQ, l, nodnil())
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08001063 n2.Nbody.Set([]*Node{Nod(OAS, l, n1)})
Russ Cox8c195bd2015-02-13 14:40:36 -05001064 n2.Likely = -1
1065 typecheck(&n2, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001066 appendNodeSeqNode(init, n2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001067
1068 l = Nod(OEFACE, l, n.Left)
1069 l.Typecheck = n.Typecheck
1070 l.Type = n.Type
1071 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001072 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001073 }
1074 }
1075
Russ Coxdc7b54b2015-02-17 22:13:49 -05001076 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001077 ll = list(ll, n.Left)
1078 } else {
1079 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001080 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001081 // the conversions it could see. comparison of an interface
1082 // with a non-interface, especially in a switch on interface value
1083 // with non-interface cases, is not visible to orderstmt, so we
1084 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001085 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001086 ll = list(ll, Nod(OADDR, n.Left, nil))
1087 } else {
1088 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1089 }
David Chase22701332015-03-27 11:21:14 -04001090 dowidth(n.Left.Type)
1091 r := nodnil()
1092 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1093 // Allocate stack buffer for value stored in interface.
1094 r = temp(n.Left.Type)
1095 r = Nod(OAS, r, nil) // zero temp
1096 typecheck(&r, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001097 appendNodeSeqNode(init, r)
David Chase22701332015-03-27 11:21:14 -04001098 r = Nod(OADDR, r.Left, nil)
1099 typecheck(&r, Erv)
1100 }
1101 ll = list(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001102 }
1103
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +00001104 fn := syslook(convFuncName(n.Left.Type, n.Type), 1)
David Chase22701332015-03-27 11:21:14 -04001105 if !Isinter(n.Left.Type) {
1106 substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
1107 } else {
1108 substArgTypes(fn, n.Left.Type, n.Type)
1109 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001110 dowidth(fn.Type)
1111 n = Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001112 setNodeSeq(&n.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001113 typecheck(&n, Erv)
1114 walkexpr(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001115
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001116 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001117 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001118 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001119 if n.Type.Etype == TINT64 {
1120 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001121 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001122 }
1123
1124 if n.Type.Etype == TUINT64 {
1125 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001126 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001127 }
1128 }
1129
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001130 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001131 if n.Left.Type.Etype == TINT64 {
1132 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001133 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001134 }
1135
1136 if n.Left.Type.Etype == TUINT64 {
1137 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001138 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001139 }
1140 }
1141 }
1142
1143 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001144
1145 case OANDNOT:
1146 walkexpr(&n.Left, init)
1147 n.Op = OAND
1148 n.Right = Nod(OCOM, n.Right, nil)
1149 typecheck(&n.Right, Erv)
1150 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001151
1152 case OMUL:
1153 walkexpr(&n.Left, init)
1154 walkexpr(&n.Right, init)
1155 walkmul(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001156
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001157 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001158 walkexpr(&n.Left, init)
1159 walkexpr(&n.Right, init)
1160
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001161 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001162 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001163
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001164 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001165 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001166 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1167 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001168 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001169 }
1170
1171 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001172 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001173 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001174 }
1175
1176 // Try rewriting as shifts or magic multiplies.
1177 walkdiv(&n, init)
1178
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001179 // rewrite 64-bit div and mod into function calls
1180 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001181 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001182 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001183 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001184 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001185 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001186 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001187 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001188 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001189 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001190 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001191 }
1192 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001193 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001194 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001195 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001196 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001197 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001198 }
1199
Russ Cox8c195bd2015-02-13 14:40:36 -05001200 case OINDEX:
1201 walkexpr(&n.Left, init)
1202
1203 // save the original node for bounds checking elision.
1204 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001205 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001206
1207 walkexpr(&n.Right, init)
1208
1209 // if range of type cannot exceed static array bound,
1210 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001211 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001212 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001213 }
Russ Cox382b44e2015-02-23 16:07:24 -05001214 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001215 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001216 t = t.Type
1217 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001218 if Isfixedarray(t) {
1219 n.Bounded = bounded(r, t.Bound)
1220 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001221 Warn("index bounds check elided")
1222 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001223 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001224 Yyerror("index out of bounds")
1225 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001226 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001227 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001228 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001229 Warn("index bounds check elided")
1230 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001231 if Smallintconst(n.Right) {
1232 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001233 Yyerror("index out of bounds")
1234 } else {
1235 // replace "abc"[1] with 'b'.
1236 // delayed until now because "abc"[1] is not
1237 // an ideal constant.
Russ Cox81d58102015-05-27 00:47:05 -04001238 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05001239
Russ Cox81d58102015-05-27 00:47:05 -04001240 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001241 n.Typecheck = 1
1242 }
1243 }
1244 }
1245
Russ Coxdc7b54b2015-02-17 22:13:49 -05001246 if Isconst(n.Right, CTINT) {
Russ Cox81d58102015-05-27 00:47:05 -04001247 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 -05001248 Yyerror("index out of bounds")
1249 }
1250 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001251
1252 case OINDEXMAP:
1253 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001254 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001255 }
1256 walkexpr(&n.Left, init)
1257 walkexpr(&n.Right, init)
1258
Russ Cox382b44e2015-02-23 16:07:24 -05001259 t := n.Left.Type
1260 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001261 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001262 switch algtype(t.Down) {
1263 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001264 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001265 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001266 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001267 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001268 p = "mapaccess1_faststr"
1269 }
1270 }
1271
Russ Cox382b44e2015-02-23 16:07:24 -05001272 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001273 if p != "" {
1274 // fast versions take key by value
1275 key = n.Right
1276 } else {
1277 // standard version takes key by reference.
1278 // orderexpr made sure key is addressable.
1279 key = Nod(OADDR, n.Right, nil)
1280
1281 p = "mapaccess1"
1282 }
1283
1284 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1285 n = Nod(OIND, n, nil)
1286 n.Type = t.Type
1287 n.Typecheck = 1
1288
Russ Cox8c195bd2015-02-13 14:40:36 -05001289 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001290 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001291
Russ Coxd4472792015-05-06 12:35:53 -04001292 case OSLICE, OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001293 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001294 walkexpr(&n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001295 if n.Right.Left != nil && iszero(n.Right.Left) {
1296 // Reduce x[0:j] to x[:j].
1297 n.Right.Left = nil
1298 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001299 walkexpr(&n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001300 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001301
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001302 case OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -04001303 walkexpr(&n.Left, init)
1304 walkexpr(&n.Right.Left, init)
1305 if n.Right.Left != nil && iszero(n.Right.Left) {
1306 // Reduce x[0:j:k] to x[:j:k].
1307 n.Right.Left = nil
1308 }
1309 walkexpr(&n.Right.Right.Left, init)
1310 walkexpr(&n.Right.Right.Right, init)
1311
1312 r := n.Right.Right.Right
1313 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1314 // Reduce x[i:j:cap(x)] to x[i:j].
1315 n.Right.Right = n.Right.Right.Left
1316 if n.Op == OSLICE3 {
1317 n.Op = OSLICE
1318 } else {
1319 n.Op = OSLICEARR
1320 }
1321 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001322 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001323
1324 case OADDR:
1325 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001326
1327 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001328 if n.Esc == EscNone {
1329 if n.Type.Type.Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001330 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001331 }
Russ Cox382b44e2015-02-23 16:07:24 -05001332 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001333 r = Nod(OAS, r, nil) // zero temp
1334 typecheck(&r, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001335 appendNodeSeqNode(init, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001336 r = Nod(OADDR, r.Left, nil)
1337 typecheck(&r, Erv)
1338 n = r
1339 } else {
1340 n = callnew(n.Type.Type)
1341 }
1342
Russ Cox8c195bd2015-02-13 14:40:36 -05001343 // If one argument to the comparison is an empty string,
1344 // comparing the lengths instead will yield the same result
1345 // without the function call.
1346 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001347 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 +02001348 // TODO(marvin): Fix Node.EType type union.
1349 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001350 typecheck(&r, Erv)
1351 walkexpr(&r, init)
1352 r.Type = n.Type
1353 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001354 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001355 }
1356
1357 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001358 if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && nodeSeqLen(n.Left.List) == 2 && Isconst(nodeSeqSecond(n.Left.List), CTSTR) && strlit(n.Right) == strlit(nodeSeqSecond(n.Left.List)) {
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001359 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001360 r := Nod(Op(n.Etype), Nod(OLEN, nodeSeqFirst(n.Left.List), nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001361 typecheck(&r, Erv)
1362 walkexpr(&r, init)
1363 r.Type = n.Type
1364 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001365 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001366 }
1367
Russ Cox382b44e2015-02-23 16:07:24 -05001368 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001369 // TODO(marvin): Fix Node.EType type union.
1370 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001371 // prepare for rewrite below
1372 n.Left = cheapexpr(n.Left, init)
1373
1374 n.Right = cheapexpr(n.Right, init)
1375
1376 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1377
1378 // quick check of len before full compare for == or !=
1379 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001380 // TODO(marvin): Fix Node.EType type union.
1381 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001382 // len(left) == len(right) && eqstring(left, right)
1383 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1384 } else {
1385 // len(left) != len(right) || !eqstring(left, right)
1386 r = Nod(ONOT, r, nil)
1387
1388 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1389 }
1390
1391 typecheck(&r, Erv)
1392 walkexpr(&r, nil)
1393 } else {
1394 // sys_cmpstring(s1, s2) :: 0
1395 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1396
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001397 // TODO(marvin): Fix Node.EType type union.
1398 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001399 }
1400
1401 typecheck(&r, Erv)
1402 if n.Type.Etype != TBOOL {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001403 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001404 }
1405 r.Type = n.Type
1406 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001407
1408 case OADDSTR:
1409 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001410
1411 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001412 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001413 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001414
1415 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001416 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001417
1418 // cannot use chanfn - closechan takes any, not chan any
1419 case OCLOSE:
Russ Cox382b44e2015-02-23 16:07:24 -05001420 fn := syslook("closechan", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001421
Russ Cox13f9c8b2015-03-08 13:33:49 -04001422 substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001423 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001424
1425 case OMAKECHAN:
1426 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 -05001427
1428 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001429 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001430
Russ Cox382b44e2015-02-23 16:07:24 -05001431 a := nodnil() // hmap buffer
1432 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001433 if n.Esc == EscNone {
1434 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001435 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001436
1437 a = Nod(OAS, var_, nil) // zero temp
1438 typecheck(&a, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001439 appendNodeSeqNode(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001440 a = Nod(OADDR, var_, nil)
1441
1442 // Allocate one bucket on stack.
1443 // Maximum key/value size is 128 bytes, larger objects
1444 // are stored with an indirection. So max bucket size is 2048+eps.
1445 var_ = temp(mapbucket(t))
1446
1447 r = Nod(OAS, var_, nil) // zero temp
1448 typecheck(&r, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001449 appendNodeSeqNode(init, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001450 r = Nod(OADDR, var_, nil)
1451 }
1452
Matthew Dempsky7f13fbf2016-03-04 07:55:39 -08001453 fn := syslook("makemap", 1)
Matthew Dempsky98779002016-02-23 07:46:01 +00001454 substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001455 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001456
1457 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001458 l := n.Left
1459 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001460 if r == nil {
1461 r = safeexpr(l, init)
1462 l = r
1463 }
Russ Cox382b44e2015-02-23 16:07:24 -05001464 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001465 if n.Esc == EscNone {
1466 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001467 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001468 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001469 // var arr [r]T
1470 // n = arr[:l]
1471 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001472 var_ := temp(t)
1473 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001474 typecheck(&a, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001475 appendNodeSeqNode(init, a)
Russ Cox382b44e2015-02-23 16:07:24 -05001476 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001477 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001478 typecheck(&r, Erv)
1479 walkexpr(&r, init)
1480 n = r
1481 } else {
1482 // makeslice(t *Type, nel int64, max int64) (ary []any)
Russ Cox382b44e2015-02-23 16:07:24 -05001483 fn := syslook("makeslice", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001484
Russ Cox13f9c8b2015-03-08 13:33:49 -04001485 substArgTypes(fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001486 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1487 }
1488
Russ Cox8c195bd2015-02-13 14:40:36 -05001489 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001490 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001491 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001492 t := aindex(Nodintconst(4), Types[TUINT8])
1493 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001494 a = Nod(OADDR, var_, nil)
1495 }
1496
1497 // intstring(*[4]byte, rune)
1498 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1499
Russ Cox8c195bd2015-02-13 14:40:36 -05001500 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001501 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001502 if n.Esc == EscNone {
1503 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001504 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001505
1506 a = Nod(OADDR, temp(t), nil)
1507 }
1508
1509 // slicebytetostring(*[32]byte, []byte) string;
1510 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1511
Russ Cox8c195bd2015-02-13 14:40:36 -05001512 // slicebytetostringtmp([]byte) string;
1513 case OARRAYBYTESTRTMP:
1514 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1515
Russ Cox8c195bd2015-02-13 14:40:36 -05001516 // slicerunetostring(*[32]byte, []rune) string;
1517 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001518 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001519
1520 if n.Esc == EscNone {
1521 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001522 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001523
1524 a = Nod(OADDR, temp(t), nil)
1525 }
1526
1527 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001528
1529 // stringtoslicebyte(*32[byte], string) []byte;
1530 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001531 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001532
1533 if n.Esc == EscNone {
1534 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001535 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001536
1537 a = Nod(OADDR, temp(t), nil)
1538 }
1539
1540 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001541
1542 // stringtoslicebytetmp(string) []byte;
1543 case OSTRARRAYBYTETMP:
1544 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1545
Russ Cox8c195bd2015-02-13 14:40:36 -05001546 // stringtoslicerune(*[32]rune, string) []rune
1547 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001548 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001549
1550 if n.Esc == EscNone {
1551 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001552 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001553
1554 a = Nod(OADDR, temp(t), nil)
1555 }
1556
1557 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001558
1559 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1560 case OCMPIFACE:
1561 if !Eqtype(n.Left.Type, n.Right.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001562 Fatalf("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001563 }
Russ Cox382b44e2015-02-23 16:07:24 -05001564 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001565 if isnilinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001566 fn = syslook("efaceeq", 1)
1567 } else {
1568 fn = syslook("ifaceeq", 1)
1569 }
1570
1571 n.Right = cheapexpr(n.Right, init)
1572 n.Left = cheapexpr(n.Left, init)
Russ Cox13f9c8b2015-03-08 13:33:49 -04001573 substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001574 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001575 // TODO(marvin): Fix Node.EType type union.
1576 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001577 r = Nod(ONOT, r, nil)
1578 }
1579
1580 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001581 // TODO(marvin): Fix Node.EType type union.
1582 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001583 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1584 } else {
1585 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1586 }
1587 typecheck(&r, Erv)
1588 walkexpr(&r, init)
1589 r.Type = n.Type
1590 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001591
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001592 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001593 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001594 anylit(0, n, var_, init)
1595 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001596
1597 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001598 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001599 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1600 walkexpr(&n1, init)
1601 n1 = Nod(OADDR, n1, nil)
1602 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001603
1604 case OCLOSURE:
1605 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001606
1607 case OCALLPART:
1608 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001609 }
1610
Russ Cox8c195bd2015-02-13 14:40:36 -05001611 // Expressions that are constant at run time but not
1612 // considered const by the language spec are not turned into
1613 // constants until walk. For example, if n is y%1 == 0, the
1614 // walk of y%1 may have replaced it by 0.
1615 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001616 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001617
1618 evconst(n)
1619 n.Type = t
1620 if n.Op == OLITERAL {
1621 typecheck(&n, Erv)
1622 }
1623
1624 ullmancalc(n)
1625
1626 if Debug['w'] != 0 && n != nil {
1627 Dump("walk", n)
1628 }
1629
1630 lineno = lno
1631 *np = n
1632}
1633
Russ Coxd4472792015-05-06 12:35:53 -04001634func reduceSlice(n *Node) *Node {
1635 r := n.Right.Right
1636 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1637 // Reduce x[i:len(x)] to x[i:].
1638 n.Right.Right = nil
1639 }
1640 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1641 // Reduce x[:] to x.
1642 if Debug_slice > 0 {
1643 Warn("slice: omit slice operation")
1644 }
1645 return n.Left
1646 }
1647 return n
1648}
1649
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001650func ascompatee1(op Op, l *Node, r *Node, init nodesOrNodeListPtr) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001651 // convas will turn map assigns into function calls,
1652 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001653 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001654
1655 if l.Op == OINDEXMAP {
1656 return n
1657 }
1658
1659 return convas(n, init)
1660}
1661
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001662func ascompatee(op Op, nl *NodeList, nr *NodeList, init nodesOrNodeListPtr) *NodeList {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001663 // check assign expression list to
1664 // a expression list. called in
1665 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001666
1667 // ensure order of evaluation for function calls
Russ Coxc8198342015-03-12 18:45:30 -04001668 for ll := nl; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001669 ll.N = safeexpr(ll.N, init)
1670 }
Russ Coxc8198342015-03-12 18:45:30 -04001671 for lr := nr; lr != nil; lr = lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001672 lr.N = safeexpr(lr.N, init)
1673 }
1674
Russ Cox175929b2015-03-02 14:22:05 -05001675 var nn *NodeList
Russ Coxc8198342015-03-12 18:45:30 -04001676 ll := nl
1677 lr := nr
Russ Coxd7f6d462015-03-09 00:31:13 -04001678 for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001679 // Do not generate 'x = x' during return. See issue 4014.
1680 if op == ORETURN && ll.N == lr.N {
1681 continue
1682 }
1683 nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
1684 }
1685
1686 // cannot happen: caller checked that lists had same length
1687 if ll != nil || lr != nil {
Russ Coxbd4fff62015-05-27 10:42:55 -04001688 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 -05001689 }
1690 return nn
1691}
1692
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001693// l is an lv and rt is the type of an rv
1694// return 1 if this implies a function call
1695// evaluating the lv or a function call
1696// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001697func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001698 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001699 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001700 }
Russ Cox175929b2015-03-02 14:22:05 -05001701 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001702 if needwritebarrier(l, &r) {
1703 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001704 }
1705 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001706 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001707 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001708 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001709}
1710
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001711func ascompatet(op Op, nl *NodeList, nr **Type, fp int, init nodesOrNodeListPtr) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001712 var l *Node
1713 var tmp *Node
1714 var a *Node
1715 var ll *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001716 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001717
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001718 // check assign type list to
1719 // a expression list. called in
1720 // expr-list = func()
Russ Cox382b44e2015-02-23 16:07:24 -05001721 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001722
Russ Cox175929b2015-03-02 14:22:05 -05001723 var nn *NodeList
1724 var mm *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001725 ucount := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001726 for ll = nl; ll != nil; ll = ll.Next {
1727 if r == nil {
1728 break
1729 }
1730 l = ll.N
1731 if isblank(l) {
1732 r = structnext(&saver)
1733 continue
1734 }
1735
1736 // any lv that causes a fn call must be
1737 // deferred until all the return arguments
1738 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001739 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001740 tmp = temp(r.Type)
1741 typecheck(&tmp, Erv)
1742 a = Nod(OAS, l, tmp)
1743 a = convas(a, init)
1744 mm = list(mm, a)
1745 l = tmp
1746 }
1747
1748 a = Nod(OAS, l, nodarg(r, fp))
1749 a = convas(a, init)
1750 ullmancalc(a)
1751 if a.Ullman >= UINF {
1752 Dump("ascompatet ucount", a)
1753 ucount++
1754 }
1755
1756 nn = list(nn, a)
1757 r = structnext(&saver)
1758 }
1759
1760 if ll != nil || r != nil {
1761 Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
1762 }
1763
1764 if ucount != 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001765 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001766 }
1767 return concat(nn, mm)
1768}
1769
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001770// package all the arguments that match a ... T parameter into a []T.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001771func mkdotargslice(lr0 nodesOrNodeList, nn *NodeList, l *Type, fp int, init nodesOrNodeListPtr, ddd *Node) *NodeList {
David Chase7fbb1b32015-03-26 16:36:15 -04001772 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001773 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001774 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001775 }
1776
Russ Cox382b44e2015-02-23 16:07:24 -05001777 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001778 tslice.Type = l.Type.Type
1779 tslice.Bound = -1
1780
Russ Cox382b44e2015-02-23 16:07:24 -05001781 var n *Node
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001782 if nodeSeqLen(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001783 n = nodnil()
1784 n.Type = tslice
1785 } else {
1786 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001787 if ddd != nil && prealloc[ddd] != nil {
1788 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 }
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001790 setNodeSeq(&n.List, lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001791 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001792 typecheck(&n, Erv)
1793 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001794 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001795 }
1796 walkexpr(&n, init)
1797 }
1798
Russ Cox382b44e2015-02-23 16:07:24 -05001799 a := Nod(OAS, nodarg(l, fp), n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001800 nn = list(nn, convas(a, init))
1801 return nn
1802}
1803
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001804// helpers for shape errors
Russ Cox8c195bd2015-02-13 14:40:36 -05001805func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001807
Russ Cox382b44e2015-02-23 16:07:24 -05001808 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001809 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001810 first := 1
1811 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001812 if first != 0 {
1813 first = 0
1814 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001815 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001816 }
Russ Coxc8198342015-03-12 18:45:30 -04001817 fmt_ += Tconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001818 }
1819
1820 if first != 0 {
1821 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1822 }
1823 return fmt_
1824}
1825
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001826func dumpnodetypes(l nodesOrNodeList, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001827 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001828
Russ Cox382b44e2015-02-23 16:07:24 -05001829 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001830 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001831 first := 1
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001832 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
1833 r = it.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001834 if first != 0 {
1835 first = 0
1836 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001837 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001838 }
Russ Coxc8198342015-03-12 18:45:30 -04001839 fmt_ += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001840 }
1841
1842 if first != 0 {
1843 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1844 }
1845 return fmt_
1846}
1847
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001848// check assign expression list to
1849// a type list. called in
1850// return expr-list
1851// func(expr-list)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001852func ascompatte(op Op, call *Node, isddd bool, nl **Type, lr nodesOrNodeList, fp int, init nodesOrNodeListPtr) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05001853 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001854
Russ Cox382b44e2015-02-23 16:07:24 -05001855 lr0 := lr
1856 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001857 var r *Node
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001858 if nodeSeqLen(lr) > 0 {
1859 r = nodeSeqFirst(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001860 }
Russ Cox175929b2015-03-02 14:22:05 -05001861 var nn *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001862
1863 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001864 var a *Node
1865 var l2 string
1866 var ll *Type
1867 var l1 string
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001868 var lrit nodeSeqIterator
1869 if r != nil && nodeSeqLen(lr) <= 1 && r.Type.Etype == TSTRUCT && r.Type.Funarg {
Russ Cox8c195bd2015-02-13 14:40:36 -05001870 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001871 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001872 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001873 r = Nod(OCONVNOP, r, nil)
1874 r.Type = a.Type
1875 nn = list1(convas(Nod(OAS, a, r), init))
1876 goto ret
1877 }
1878
1879 // conversions involved.
1880 // copy into temporaries.
Russ Cox175929b2015-03-02 14:22:05 -05001881 var alist *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05001882
Russ Cox382b44e2015-02-23 16:07:24 -05001883 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001884 a = temp(l.Type)
1885 alist = list(alist, a)
1886 }
1887
1888 a = Nod(OAS2, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001889 setNodeSeq(&a.List, alist)
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001890 setNodeSeq(&a.Rlist, lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001891 typecheck(&a, Etop)
1892 walkstmt(&a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001893 appendNodeSeqNode(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001894 lr = alist
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001895 r = nodeSeqFirst(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001896 l = Structfirst(&savel, nl)
1897 }
1898
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001899 lrit = nodeSeqIterate(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001900loop:
Dave Cheneyd3287562015-03-09 16:24:07 +11001901 if l != nil && l.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001902 // the ddd parameter must be last
1903 ll = structnext(&savel)
1904
1905 if ll != nil {
1906 Yyerror("... must be last argument")
1907 }
1908
1909 // special case --
1910 // only if we are assigning a single ddd
1911 // argument to a ddd parameter then it is
1912 // passed thru unencapsulated
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001913 if r != nil && lrit.Len() <= 1 && isddd && Eqtype(l.Type, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001914 a = Nod(OAS, nodarg(l, fp), r)
1915 a = convas(a, init)
1916 nn = list(nn, a)
1917 goto ret
1918 }
1919
1920 // normal case -- make a slice of all
1921 // remaining arguments and pass it to
1922 // the ddd parameter.
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001923 nn = mkdotargslice(lrit.Seq(), nn, l, fp, init, call.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05001924
1925 goto ret
1926 }
1927
1928 if l == nil || r == nil {
1929 if l != nil || r != nil {
1930 l1 = dumptypes(nl, "expected")
1931 l2 = dumpnodetypes(lr0, "given")
1932 if l != nil {
1933 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1934 } else {
1935 Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
1936 }
1937 }
1938
1939 goto ret
1940 }
1941
1942 a = Nod(OAS, nodarg(l, fp), r)
1943 a = convas(a, init)
1944 nn = list(nn, a)
1945
1946 l = structnext(&savel)
1947 r = nil
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001948 lrit.Next()
1949 if !lrit.Done() {
1950 r = lrit.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001951 }
1952 goto loop
1953
1954ret:
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001955 for lrit = nodeSeqIterate(nn); !lrit.Done(); lrit.Next() {
1956 lrit.N().Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001957 }
1958 return nn
1959}
1960
1961// generate code for print
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001962func walkprint(nn *Node, init nodesOrNodeListPtr) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001963 var r *Node
1964 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001965 var on *Node
1966 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001967 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001968
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001969 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001970 all := nn.List
Russ Cox175929b2015-03-02 14:22:05 -05001971 var calls *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05001972 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001973
1974 // Hoist all the argument evaluation up before the lock.
1975 walkexprlistcheap(all, init)
1976
1977 calls = list(calls, mkcall("printlock", nil, init))
1978
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001979 for it := nodeSeqIterate(all); !it.Done(); it.Next() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001980 if notfirst {
Russ Cox8c195bd2015-02-13 14:40:36 -05001981 calls = list(calls, mkcall("printsp", nil, init))
1982 }
1983
Russ Coxdc7b54b2015-02-17 22:13:49 -05001984 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001985
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001986 n = it.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001987 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04001988 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001989 case CTRUNE:
1990 defaultlit(&n, runetype)
1991
1992 case CTINT:
1993 defaultlit(&n, Types[TINT64])
1994
1995 case CTFLT:
1996 defaultlit(&n, Types[TFLOAT64])
1997 }
1998 }
1999
2000 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
2001 defaultlit(&n, Types[TINT64])
2002 }
2003 defaultlit(&n, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002004 *it.P() = n
Russ Cox8c195bd2015-02-13 14:40:36 -05002005 if n.Type == nil || n.Type.Etype == TFORW {
2006 continue
2007 }
2008
2009 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002010 et = n.Type.Etype
Russ Coxdc7b54b2015-02-17 22:13:49 -05002011 if Isinter(n.Type) {
2012 if isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002013 on = syslook("printeface", 1)
2014 } else {
2015 on = syslook("printiface", 1)
2016 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002017 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002018 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Russ Cox8c195bd2015-02-13 14:40:36 -05002019 on = syslook("printpointer", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002020 substArgTypes(on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05002021 } else if Isslice(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002022 on = syslook("printslice", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002023 substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002024 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002025 if et == TUINT64 {
2026 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
2027 on = syslook("printhex", 0)
2028 } else {
2029 on = syslook("printuint", 0)
2030 }
2031 } else {
2032 on = syslook("printint", 0)
2033 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002034 } else if Isfloat[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002035 on = syslook("printfloat", 0)
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002036 } else if Iscomplex[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002037 on = syslook("printcomplex", 0)
2038 } else if et == TBOOL {
2039 on = syslook("printbool", 0)
2040 } else if et == TSTRING {
2041 on = syslook("printstring", 0)
2042 } else {
2043 badtype(OPRINT, n.Type, nil)
2044 continue
2045 }
2046
2047 t = *getinarg(on.Type)
2048 if t != nil {
2049 t = t.Type
2050 }
2051 if t != nil {
2052 t = t.Type
2053 }
2054
2055 if !Eqtype(t, n.Type) {
2056 n = Nod(OCONV, n, nil)
2057 n.Type = t
2058 }
2059
2060 r = Nod(OCALL, on, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002061 appendNodeSeqNode(&r.List, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002062 calls = list(calls, r)
2063 }
2064
2065 if op == OPRINTN {
2066 calls = list(calls, mkcall("printnl", nil, nil))
2067 }
2068
2069 calls = list(calls, mkcall("printunlock", nil, init))
2070
2071 typechecklist(calls, Etop)
2072 walkexprlist(calls, init)
2073
2074 r = Nod(OEMPTY, nil, nil)
2075 typecheck(&r, Etop)
2076 walkexpr(&r, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002077 setNodeSeq(&r.Ninit, calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002078 return r
2079}
2080
2081func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002082 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -05002083 fn := syslook("newobject", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002084 substArgTypes(fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002085 return mkcall1(fn, Ptrto(t), nil, typename(t))
2086}
2087
Russ Cox3b6e86f2015-06-29 15:17:14 -04002088func iscallret(n *Node) bool {
2089 n = outervalue(n)
2090 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2091}
2092
Russ Coxdc7b54b2015-02-17 22:13:49 -05002093func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002094 n = outervalue(n)
2095
2096 // If n is *autotmp and autotmp = &foo, replace n with foo.
2097 // We introduce such temps when initializing struct literals.
2098 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002099 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002100 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2101 n = defn.Right.Left
2102 }
2103 }
2104
2105 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002106 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002107 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002108
2109 case ONAME:
2110 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002111 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002112 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002113 }
2114 }
2115
Russ Coxdc7b54b2015-02-17 22:13:49 -05002116 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002117}
2118
Russ Coxdc7b54b2015-02-17 22:13:49 -05002119func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002120 n = outervalue(n)
2121
2122 switch n.Op {
2123 case ONAME:
2124 switch n.Class {
2125 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002126 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002127 }
2128 }
2129
Russ Coxdc7b54b2015-02-17 22:13:49 -05002130 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002131}
2132
2133// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002134func needwritebarrier(l *Node, r *Node) bool {
2135 if use_writebarrier == 0 {
2136 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002137 }
2138
2139 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002140 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002141 }
2142
2143 // No write barrier for write of non-pointers.
2144 dowidth(l.Type)
2145
2146 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002147 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002148 }
2149
2150 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002151 if isstack(l) {
2152 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002153 }
2154
Russ Cox9f90f312015-06-29 12:49:25 -04002155 // No write barrier for implicit zeroing.
2156 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002157 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002158 }
2159
Russ Cox9f90f312015-06-29 12:49:25 -04002160 // Ignore no-op conversions when making decision.
2161 // Ensures that xp = unsafe.Pointer(&x) is treated
2162 // the same as xp = &x.
2163 for r.Op == OCONVNOP {
2164 r = r.Left
2165 }
2166
2167 // No write barrier for zeroing or initialization to constant.
2168 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002169 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002170 }
2171
2172 // No write barrier for storing static (read-only) data.
2173 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002174 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002175 }
2176
2177 // No write barrier for storing address of stack values,
2178 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002179 if r.Op == OADDR && isstack(r.Left) {
2180 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002181 }
2182
2183 // No write barrier for storing address of global, which
2184 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002185 if r.Op == OADDR && isglobal(r.Left) {
2186 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002187 }
2188
Russ Cox8c195bd2015-02-13 14:40:36 -05002189 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002190 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002191}
2192
2193// TODO(rsc): Perhaps componentgen should run before this.
2194
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002195func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002196 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002197 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002198 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002199 }
Russ Cox972a4782015-05-21 15:00:06 -04002200 n.Op = OASWB
2201 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002202 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002203 return n
2204}
2205
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002206func convas(n *Node, init nodesOrNodeListPtr) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002207 if n.Op != OAS {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002208 Fatalf("convas: not OAS %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002209 }
2210
2211 n.Typecheck = 1
2212
Russ Cox382b44e2015-02-23 16:07:24 -05002213 var lt *Type
2214 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002215 if n.Left == nil || n.Right == nil {
2216 goto out
2217 }
2218
2219 lt = n.Left.Type
2220 rt = n.Right.Type
2221 if lt == nil || rt == nil {
2222 goto out
2223 }
2224
2225 if isblank(n.Left) {
2226 defaultlit(&n.Right, nil)
2227 goto out
2228 }
2229
2230 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002231 map_ := n.Left.Left
2232 key := n.Left.Right
2233 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 walkexpr(&map_, init)
2235 walkexpr(&key, init)
2236 walkexpr(&val, init)
2237
2238 // orderexpr made sure key and val are addressable.
2239 key = Nod(OADDR, key, nil)
2240
2241 val = Nod(OADDR, val, nil)
2242 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2243 goto out
2244 }
2245
2246 if !Eqtype(lt, rt) {
2247 n.Right = assignconv(n.Right, lt, "assignment")
2248 walkexpr(&n.Right, init)
2249 }
2250
2251out:
2252 ullmancalc(n)
2253 return n
2254}
2255
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002256// from ascompat[te]
2257// evaluating actual function arguments.
2258// f(a,b)
2259// if there is exactly one function expr,
2260// then it is done first. otherwise must
2261// make temp variables
Russ Cox8c195bd2015-02-13 14:40:36 -05002262func reorder1(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002263 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002264
Russ Cox382b44e2015-02-23 16:07:24 -05002265 c := 0 // function calls
2266 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002267
Russ Cox382b44e2015-02-23 16:07:24 -05002268 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002269 n = l.N
2270 t++
2271 ullmancalc(n)
2272 if n.Ullman >= UINF {
2273 c++
2274 }
2275 }
2276
2277 if c == 0 || t == 1 {
2278 return all
2279 }
2280
Russ Cox175929b2015-03-02 14:22:05 -05002281 var g *NodeList // fncalls assigned to tempnames
2282 var f *Node // last fncall assigned to stack
2283 var r *NodeList // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002284 d := 0
2285 var a *Node
2286 for l := all; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002287 n = l.N
2288 if n.Ullman < UINF {
2289 r = list(r, n)
2290 continue
2291 }
2292
2293 d++
2294 if d == c {
2295 f = n
2296 continue
2297 }
2298
2299 // make assignment of fncall to tempname
2300 a = temp(n.Right.Type)
2301
2302 a = Nod(OAS, a, n.Right)
2303 g = list(g, a)
2304
2305 // put normal arg assignment on list
2306 // with fncall replaced by tempname
2307 n.Right = a.Left
2308
2309 r = list(r, n)
2310 }
2311
2312 if f != nil {
2313 g = list(g, f)
2314 }
2315 return concat(g, r)
2316}
2317
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002318// from ascompat[ee]
2319// a,b = c,d
2320// simultaneous assignment. there cannot
2321// be later use of an earlier lvalue.
2322//
2323// function calls have been removed.
Russ Cox8c195bd2015-02-13 14:40:36 -05002324func reorder3(all *NodeList) *NodeList {
Russ Cox8c195bd2015-02-13 14:40:36 -05002325 var l *Node
2326
2327 // If a needed expression may be affected by an
2328 // earlier assignment, make an early copy of that
2329 // expression and use the copy instead.
Russ Cox175929b2015-03-02 14:22:05 -05002330 var early *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05002331
Russ Cox175929b2015-03-02 14:22:05 -05002332 var mapinit *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -05002333 for list := all; list != nil; list = list.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002334 l = list.N.Left
2335
2336 // Save subexpressions needed on left side.
2337 // Drill through non-dereferences.
2338 for {
2339 if l.Op == ODOT || l.Op == OPAREN {
2340 l = l.Left
2341 continue
2342 }
2343
Russ Coxdc7b54b2015-02-17 22:13:49 -05002344 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002345 reorder3save(&l.Right, all, list, &early)
2346 l = l.Left
2347 continue
2348 }
2349
2350 break
2351 }
2352
2353 switch l.Op {
2354 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002355 Fatalf("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002356
2357 case ONAME:
2358 break
2359
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002360 case OINDEX, OINDEXMAP:
Russ Cox8c195bd2015-02-13 14:40:36 -05002361 reorder3save(&l.Left, all, list, &early)
2362 reorder3save(&l.Right, all, list, &early)
2363 if l.Op == OINDEXMAP {
2364 list.N = convas(list.N, &mapinit)
2365 }
2366
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002367 case OIND, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05002368 reorder3save(&l.Left, all, list, &early)
2369 }
2370
2371 // Save expression on right side.
2372 reorder3save(&list.N.Right, all, list, &early)
2373 }
2374
2375 early = concat(mapinit, early)
2376 return concat(early, all)
2377}
2378
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002379// if the evaluation of *np would be affected by the
2380// assignments in all up to but not including stop,
2381// copy into a temporary during *early and
2382// replace *np with that temp.
Russ Cox8c195bd2015-02-13 14:40:36 -05002383func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
Russ Cox382b44e2015-02-23 16:07:24 -05002384 n := *np
Russ Coxdc7b54b2015-02-17 22:13:49 -05002385 if !aliased(n, all, stop) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002386 return
2387 }
2388
Russ Cox382b44e2015-02-23 16:07:24 -05002389 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002390 q = Nod(OAS, q, n)
2391 typecheck(&q, Etop)
2392 *early = list(*early, q)
2393 *np = q.Left
2394}
2395
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002396// what's the outer value that a write to n affects?
2397// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002398func outervalue(n *Node) *Node {
2399 for {
2400 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002401 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002402 }
2403 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2404 n = n.Left
2405 continue
2406 }
2407
Russ Coxdc7b54b2015-02-17 22:13:49 -05002408 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002409 n = n.Left
2410 continue
2411 }
2412
2413 break
2414 }
2415
2416 return n
2417}
2418
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002419// Is it possible that the computation of n might be
2420// affected by writes in as up to but not including stop?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002421func aliased(n *Node, all *NodeList, stop *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002422 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002423 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002424 }
2425
2426 // Look for obvious aliasing: a variable being assigned
2427 // during the all list and appearing in n.
2428 // Also record whether there are any writes to main memory.
2429 // Also record whether there are any writes to variables
2430 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002431 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002432
Russ Cox382b44e2015-02-23 16:07:24 -05002433 varwrite := 0
2434 var a *Node
2435 for l := all; l != stop; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05002436 a = outervalue(l.N.Left)
2437 if a.Op != ONAME {
2438 memwrite = 1
2439 continue
2440 }
2441
2442 switch n.Class {
2443 default:
2444 varwrite = 1
2445 continue
2446
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002447 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002448 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002449 varwrite = 1
2450 continue
2451 }
2452
Russ Coxdc7b54b2015-02-17 22:13:49 -05002453 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002454 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002455 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002456 }
2457 }
2458 }
2459
2460 // The variables being written do not appear in n.
2461 // However, n might refer to computed addresses
2462 // that are being written.
2463
2464 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002465 if memwrite == 0 && varwrite == 0 {
2466 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002467 }
2468
2469 // If n does not refer to computed addresses
2470 // (that is, if n only refers to variables whose addresses
2471 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002472 if varexpr(n) {
2473 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002474 }
2475
2476 // Otherwise, both the writes and n refer to computed memory addresses.
2477 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002478 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002479}
2480
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002481// does the evaluation of n only refer to variables
2482// whose addresses have not been taken?
2483// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002484func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002485 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002486 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002487 }
2488
2489 switch n.Op {
2490 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002491 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002492
2493 case ONAME:
2494 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002495 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002496 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002497 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002498 }
2499 }
2500
Russ Coxdc7b54b2015-02-17 22:13:49 -05002501 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002502
2503 case OADD,
2504 OSUB,
2505 OOR,
2506 OXOR,
2507 OMUL,
2508 ODIV,
2509 OMOD,
2510 OLSH,
2511 ORSH,
2512 OAND,
2513 OANDNOT,
2514 OPLUS,
2515 OMINUS,
2516 OCOM,
2517 OPAREN,
2518 OANDAND,
2519 OOROR,
2520 ODOT, // but not ODOTPTR
2521 OCONV,
2522 OCONVNOP,
2523 OCONVIFACE,
2524 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002525 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002526 }
2527
2528 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002529 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002530}
2531
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002532// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002533func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002534 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002535 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002536 }
2537 switch r.Op {
2538 // match each right given left
2539 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002540 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002541
2542 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002543 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002544 }
2545
Russ Coxdc7b54b2015-02-17 22:13:49 -05002546 if vmatch2(l, r.Left) {
2547 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002548 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002549 if vmatch2(l, r.Right) {
2550 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002551 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002552 for it := nodeSeqIterate(r.List); !it.Done(); it.Next() {
2553 if vmatch2(l, it.N()) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002554 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002555 }
2556 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002557 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002558}
2559
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002560// is any name mentioned in l also mentioned in r?
2561// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002562func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002563 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002564 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002565 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002566 }
2567 switch l.Op {
2568 case ONAME:
2569 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002570 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002571 break
2572
2573 // assignment to non-stack variable
2574 // must be delayed if right has function calls.
2575 default:
2576 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002577 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002578 }
2579 }
2580
2581 return vmatch2(l, r)
2582
2583 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002584 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002585 }
2586
Russ Coxdc7b54b2015-02-17 22:13:49 -05002587 if vmatch1(l.Left, r) {
2588 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002589 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002590 if vmatch1(l.Right, r) {
2591 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002592 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002593 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
2594 if vmatch1(it.N(), r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002595 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002596 }
2597 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002598 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002599}
2600
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002601// walk through argin parameters.
2602// generate and return code to allocate
2603// copies of escaped parameters to the heap.
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002604func paramstoheap(argin **Type, out int) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002605 var savet Iter
2606 var v *Node
2607 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002608
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002609 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002610 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002611 v = t.Nname
2612 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2613 v = nil
2614 }
2615
2616 // For precise stacks, the garbage collector assumes results
2617 // are always live, so zero them always.
2618 if out != 0 {
2619 // Defer might stop a panic and show the
2620 // return values as they exist at the time of panic.
2621 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002622 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002623 }
2624
Russ Coxdc7b54b2015-02-17 22:13:49 -05002625 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002626 continue
2627 }
2628
2629 // generate allocation & copying code
2630 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002631 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002632 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002633 if prealloc[v] == nil {
2634 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002635 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002636 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002637 if v.Class&^PHEAP != PPARAMOUT {
Russ Coxbd4fff62015-05-27 10:42:55 -04002638 as = Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002639 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002640 typecheck(&as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002641 as = applywritebarrier(as)
2642 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002643 }
2644 }
2645
2646 return nn
2647}
2648
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002649// walk through argout parameters copying back to stack
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002650func returnsfromheap(argin **Type) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002651 var savet Iter
2652 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002653
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002654 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002655 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002656 v = t.Nname
2657 if v == nil || v.Class != PHEAP|PPARAMOUT {
2658 continue
2659 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002660 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002661 }
2662
2663 return nn
2664}
2665
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002666// take care of migrating any function in/out args
2667// between the stack and the heap. adds code to
2668// curfn's before and after lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002669func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002670 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002671 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002672 nn := paramstoheap(getthis(Curfn.Type), 0)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002673 nn = append(nn, paramstoheap(getinarg(Curfn.Type), 0)...)
2674 nn = append(nn, paramstoheap(Getoutarg(Curfn.Type), 1)...)
2675 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002676 lineno = Curfn.Func.Endlineno
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002677 Curfn.Func.Exit.Append(returnsfromheap(Getoutarg(Curfn.Type))...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002678 lineno = lno
2679}
2680
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002681func vmkcall(fn *Node, t *Type, init nodesOrNodeListPtr, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002682 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002683 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002684 }
2685
Russ Cox382b44e2015-02-23 16:07:24 -05002686 n := fn.Type.Intuple
Russ Cox8c195bd2015-02-13 14:40:36 -05002687
Russ Cox382b44e2015-02-23 16:07:24 -05002688 r := Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002689 setNodeSeq(&r.List, va[:n])
Russ Cox8c195bd2015-02-13 14:40:36 -05002690 if fn.Type.Outtuple > 0 {
2691 typecheck(&r, Erv|Efnstruct)
2692 } else {
2693 typecheck(&r, Etop)
2694 }
2695 walkexpr(&r, init)
2696 r.Type = t
2697 return r
2698}
2699
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002700func mkcall(name string, t *Type, init nodesOrNodeListPtr, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002701 return vmkcall(syslook(name, 0), t, init, args)
2702}
2703
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002704func mkcall1(fn *Node, t *Type, init nodesOrNodeListPtr, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002705 return vmkcall(fn, t, init, args)
2706}
2707
2708func conv(n *Node, t *Type) *Node {
2709 if Eqtype(n.Type, t) {
2710 return n
2711 }
2712 n = Nod(OCONV, n, nil)
2713 n.Type = t
2714 typecheck(&n, Erv)
2715 return n
2716}
2717
2718func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002719 if t.Etype != TCHAN {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002720 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002721 }
Russ Cox382b44e2015-02-23 16:07:24 -05002722 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002723 switch n {
2724 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002725 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002726 case 1:
2727 substArgTypes(fn, t.Type)
2728 case 2:
2729 substArgTypes(fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002730 }
2731 return fn
2732}
2733
2734func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002735 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002736 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002737 }
Russ Cox382b44e2015-02-23 16:07:24 -05002738 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002739 substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002740 return fn
2741}
2742
2743func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002744 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002745 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002746 }
Russ Cox382b44e2015-02-23 16:07:24 -05002747 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002748 substArgTypes(fn, t.Down, t.Type, t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05002749 return fn
2750}
2751
2752func writebarrierfn(name string, l *Type, r *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002753 fn := syslook(name, 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002754 substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002755 return fn
2756}
2757
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002758func addstr(n *Node, init nodesOrNodeListPtr) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002759 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002760 c := nodeSeqLen(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002761
2762 if c < 2 {
2763 Yyerror("addstr count %d too small", c)
2764 }
2765
Russ Cox382b44e2015-02-23 16:07:24 -05002766 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002767 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002768 sz := int64(0)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002769 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2770 if it.N().Op == OLITERAL {
2771 sz += int64(len(it.N().Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002772 }
2773 }
2774
2775 // Don't allocate the buffer if the result won't fit.
2776 if sz < tmpstringbufsize {
2777 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002778 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002779
2780 buf = Nod(OADDR, temp(t), nil)
2781 }
2782 }
2783
2784 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002785 args := []*Node{buf}
Russ Cox8c195bd2015-02-13 14:40:36 -05002786
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002787 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2788 args = append(args, conv(it.N(), Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002789 }
2790
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002791 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002792 if c <= 5 {
2793 // small numbers of strings use direct runtime helpers.
2794 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002795 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002796 } else {
2797 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002798 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002799
Russ Cox382b44e2015-02-23 16:07:24 -05002800 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002801 t.Type = Types[TSTRING]
2802 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002803 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002804 if prealloc[n] != nil {
2805 prealloc[slice] = prealloc[n]
2806 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002807 setNodeSeq(&slice.List, args[1:]) // skip buf arg
2808 args = []*Node{buf}
2809 args = append(args, slice)
Russ Cox8c195bd2015-02-13 14:40:36 -05002810 slice.Esc = EscNone
2811 }
2812
Matthew Dempsky7f13fbf2016-03-04 07:55:39 -08002813 cat := syslook(fn, 0)
Russ Cox382b44e2015-02-23 16:07:24 -05002814 r := Nod(OCALL, cat, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002815 setNodeSeq(&r.List, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002816 typecheck(&r, Erv)
2817 walkexpr(&r, init)
2818 r.Type = n.Type
2819
2820 return r
2821}
2822
2823// expand append(l1, l2...) to
2824// init {
2825// s := l1
2826// if n := len(l1) + len(l2) - cap(s); n > 0 {
Russ Cox32fddad2015-06-25 19:27:20 -04002827// s = growslice_n(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002828// }
2829// s = s[:len(l1)+len(l2)]
2830// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2831// }
2832// s
2833//
2834// l2 is allowed to be a string.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002835func appendslice(n *Node, init nodesOrNodeListPtr) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002836 walkexprlistsafe(n.List, init)
2837
2838 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2839 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002840 // modifying here. Fix explicitly.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002841 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2842 *it.P() = cheapexpr(it.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002843 }
2844
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002845 l1 := nodeSeqFirst(n.List)
2846 l2 := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002847
Russ Cox382b44e2015-02-23 16:07:24 -05002848 s := temp(l1.Type) // var s []T
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002849 var l []*Node
2850 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002851
Russ Cox382b44e2015-02-23 16:07:24 -05002852 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002853
Russ Cox382b44e2015-02-23 16:07:24 -05002854 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002855
2856 // n := len(s) + len(l2) - cap(s)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002857 setNodeSeq(&nif.Ninit, list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil)))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002858
Russ Cox66be1482015-05-26 21:30:20 -04002859 nif.Left = Nod(OGT, nt, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002860
Russ Cox32fddad2015-06-25 19:27:20 -04002861 // instantiate growslice_n(Type*, []any, int) []any
2862 fn := syslook("growslice_n", 1) // growslice_n(<type>, old []T, n int64) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002863 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002864
Russ Cox32fddad2015-06-25 19:27:20 -04002865 // s = growslice_n(T, s, n)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08002866 nif.Nbody.Set([]*Node{Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt))})
Russ Cox8c195bd2015-02-13 14:40:36 -05002867
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002868 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002869
2870 if haspointers(l1.Type.Type) {
2871 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002872 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 -05002873
2874 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002875 nptr2 := l2
2876 fn := syslook("typedslicecopy", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002877 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002878 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002879 l = append(l, nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002880 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002881 // rely on runtime to instrument copy.
2882 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002883 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 -05002884
2885 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002886 nptr2 := l2
2887 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002888 if l2.Type.Etype == TSTRING {
2889 fn = syslook("slicestringcopy", 1)
2890 } else {
2891 fn = syslook("slicecopy", 1)
2892 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04002893 substArgTypes(fn, l1.Type, l2.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05002894 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002895 l = append(l, nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002896 } else {
2897 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002898 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002899
Russ Coxdc7b54b2015-02-17 22:13:49 -05002900 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002901 nptr1 = Nod(OADDR, nptr1, nil)
2902
Russ Cox382b44e2015-02-23 16:07:24 -05002903 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002904
Russ Cox382b44e2015-02-23 16:07:24 -05002905 fn := syslook("memmove", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002906 substArgTypes(fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002907
Russ Cox382b44e2015-02-23 16:07:24 -05002908 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
Russ Cox8c195bd2015-02-13 14:40:36 -05002909
2910 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Russ Cox382b44e2015-02-23 16:07:24 -05002911 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002912 l = append(l, nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002913 }
2914
2915 // s = s[:len(l1)+len(l2)]
2916 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
2917
2918 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
2919 nt.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002920 l = append(l, Nod(OAS, s, nt))
Russ Cox8c195bd2015-02-13 14:40:36 -05002921
2922 typechecklist(l, Etop)
2923 walkstmtlist(l)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002924 appendNodeSeq(init, l)
Russ Cox8c195bd2015-02-13 14:40:36 -05002925 return s
2926}
2927
Russ Cox85520472015-05-06 12:34:30 -04002928// Rewrite append(src, x, y, z) so that any side effects in
2929// x, y, z (including runtime panics) are evaluated in
2930// initialization statements before the append.
2931// For normal code generation, stop there and leave the
2932// rest to cgen_append.
2933//
2934// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002935//
2936// init {
2937// s := src
2938// const argc = len(args) - 1
2939// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002940// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002941// }
2942// n := len(s)
2943// s = s[:n+argc]
2944// s[n] = a
2945// s[n+1] = b
2946// ...
2947// }
2948// s
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002949func walkappend(n *Node, init nodesOrNodeListPtr, dst *Node) *Node {
Russ Cox85520472015-05-06 12:34:30 -04002950 if !samesafeexpr(dst, n.List.N) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002951 it := nodeSeqIterate(n.List)
2952 *it.P() = safeexpr(it.N(), init)
2953 walkexpr(it.P(), init)
Russ Cox85520472015-05-06 12:34:30 -04002954 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002955 it := nodeSeqIterate(n.List)
2956 it.Next()
2957 walkexprlistsafe(it.Seq(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002958
2959 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2960 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002961 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002962 // Using cheapexpr also makes sure that the evaluation
2963 // of all arguments (and especially any panics) happen
2964 // before we begin to modify the slice in a visible way.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002965 it = nodeSeqIterate(n.List)
2966 it.Next()
2967 for ; !it.Done(); it.Next() {
2968 *it.P() = cheapexpr(it.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002969 }
2970
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002971 nsrc := nodeSeqFirst(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002972
2973 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002974 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002975 nsrc.Type = nsrc.Type.Type.Type
2976 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002977 argc := nodeSeqLen(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002978 if argc < 1 {
2979 return nsrc
2980 }
2981
Russ Cox85520472015-05-06 12:34:30 -04002982 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002983 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002984 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002985 return n
2986 }
2987
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002988 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002989
Russ Cox382b44e2015-02-23 16:07:24 -05002990 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002991 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002992
Russ Cox382b44e2015-02-23 16:07:24 -05002993 na := Nodintconst(int64(argc)) // const argc
2994 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002995 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002996
Russ Cox32fddad2015-06-25 19:27:20 -04002997 fn := syslook("growslice", 1) // growslice(<type>, old []T, mincap int) (ret []T)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002998 substArgTypes(fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002999
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003000 nx.Nbody.Set([]*Node{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 -05003001
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003002 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05003003
Russ Cox382b44e2015-02-23 16:07:24 -05003004 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003005 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05003006
3007 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
3008 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003009 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05003010
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003011 it = nodeSeqIterate(n.List)
3012 it.Next()
3013 for ; !it.Done(); it.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003014 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003015 nx.Bounded = true
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003016 l = append(l, Nod(OAS, nx, it.N())) // s[n] = arg
Ian Lance Taylor55c65d42016-03-04 13:16:48 -08003017 if it.Len() > 1 {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003018 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003019 }
3020 }
3021
3022 typechecklist(l, Etop)
3023 walkstmtlist(l)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003024 appendNodeSeq(init, l)
Russ Cox8c195bd2015-02-13 14:40:36 -05003025 return ns
3026}
3027
3028// Lower copy(a, b) to a memmove call or a runtime call.
3029//
3030// init {
3031// n := len(a)
3032// if n > len(b) { n = len(b) }
3033// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3034// }
3035// n;
3036//
3037// Also works if b is a string.
3038//
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003039func copyany(n *Node, init nodesOrNodeListPtr, runtimecall bool) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003040 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05003041 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003042 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
3043 }
3044
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003045 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003046 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003047 if n.Right.Type.Etype == TSTRING {
3048 fn = syslook("slicestringcopy", 1)
3049 } else {
3050 fn = syslook("slicecopy", 1)
3051 }
Russ Cox13f9c8b2015-03-08 13:33:49 -04003052 substArgTypes(fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003053 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3054 }
3055
3056 walkexpr(&n.Left, init)
3057 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003058 nl := temp(n.Left.Type)
3059 nr := temp(n.Right.Type)
Russ Cox175929b2015-03-02 14:22:05 -05003060 var l *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -05003061 l = list(l, Nod(OAS, nl, n.Left))
3062 l = list(l, Nod(OAS, nr, n.Right))
3063
Russ Cox382b44e2015-02-23 16:07:24 -05003064 nfrm := Nod(OSPTR, nr, nil)
3065 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003066
Russ Cox382b44e2015-02-23 16:07:24 -05003067 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003068
3069 // n = len(to)
3070 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
3071
3072 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003073 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003074
Russ Cox66be1482015-05-26 21:30:20 -04003075 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003076 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003077 l = list(l, nif)
3078
3079 // Call memmove.
Russ Cox382b44e2015-02-23 16:07:24 -05003080 fn := syslook("memmove", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003081
Russ Cox13f9c8b2015-03-08 13:33:49 -04003082 substArgTypes(fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003083 nwid := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -05003084 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
3085 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
3086 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
3087
3088 typechecklist(l, Etop)
3089 walkstmtlist(l)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003090 appendNodeSeq(init, l)
Russ Cox8c195bd2015-02-13 14:40:36 -05003091 return nlen
3092}
3093
Russ Cox8c195bd2015-02-13 14:40:36 -05003094func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003095 // Should only arrive here with large memory or
3096 // a struct/array containing a non-memory field/element.
3097 // Small memory is handled inline, and single non-memory
3098 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003099 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003100
3101 if a != AMEM && a != -1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003102 Fatalf("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003103 }
3104
3105 if a == AMEM {
Russ Cox382b44e2015-02-23 16:07:24 -05003106 n := syslook("memequal", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -04003107 substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003108 *needsize = 1
3109 return n
3110 }
3111
Russ Cox382b44e2015-02-23 16:07:24 -05003112 sym := typesymprefix(".eq", t)
3113 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003114 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003115 ntype := Nod(OTFUNC, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003116 appendNodeSeqNode(&ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3117 appendNodeSeqNode(&ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3118 appendNodeSeqNode(&ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003119 typecheck(&ntype, Etype)
3120 n.Type = ntype.Type
3121 *needsize = 0
3122 return n
3123}
3124
3125func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003126 n := 0
3127 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003128 n++
3129 }
3130 return n
3131}
3132
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003133func walkcompare(np **Node, init nodesOrNodeListPtr) {
Russ Cox382b44e2015-02-23 16:07:24 -05003134 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003135
3136 // Given interface value l and concrete value r, rewrite
3137 // l == r
3138 // to
3139 // x, ok := l.(type(r)); ok && x == r
3140 // Handle != similarly.
3141 // This avoids the allocation that would be required
3142 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003143 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003144
Russ Cox175929b2015-03-02 14:22:05 -05003145 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003146 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003147 l = n.Left
3148 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003149 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003150 l = n.Right
3151 r = n.Left
3152 }
3153
3154 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003155 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003156 if haspointers(r.Type) {
3157 a := Nod(OAS, x, nil)
3158 typecheck(&a, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003159 appendNodeSeqNode(init, a)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003160 }
Russ Cox382b44e2015-02-23 16:07:24 -05003161 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003162
3163 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003164 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003165
3166 a.Type = r.Type
3167
3168 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003169 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003170
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003171 appendNodeSeqNode(&expr.List, x)
3172 appendNodeSeqNode(&expr.List, ok)
3173 appendNodeSeqNode(&expr.Rlist, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003174 typecheck(&expr, Etop)
3175 walkexpr(&expr, init)
3176
3177 if n.Op == OEQ {
3178 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3179 } else {
3180 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3181 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003182 appendNodeSeqNode(init, expr)
Russ Cox44928112015-03-02 20:34:22 -05003183 finishcompare(np, n, r, init)
3184 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003185 }
3186
3187 // Must be comparison of array or struct.
3188 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003189 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003190
3191 switch t.Etype {
3192 default:
3193 return
3194
3195 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003196 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003197 return
3198 }
3199
3200 case TSTRUCT:
3201 break
3202 }
3203
Russ Cox44928112015-03-02 20:34:22 -05003204 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003205 for cmpl != nil && cmpl.Op == OCONVNOP {
3206 cmpl = cmpl.Left
3207 }
Russ Cox44928112015-03-02 20:34:22 -05003208 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003209 for cmpr != nil && cmpr.Op == OCONVNOP {
3210 cmpr = cmpr.Left
3211 }
3212
Russ Coxdc7b54b2015-02-17 22:13:49 -05003213 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003214 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003215 }
3216
3217 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003218 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003219 a.Right.Etype = 1 // addr does not escape
3220 typecheck(&a, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003221 appendNodeSeqNode(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003222
3223 r = temp(Ptrto(t))
3224 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3225 a.Right.Etype = 1 // addr does not escape
3226 typecheck(&a, Etop)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003227 appendNodeSeqNode(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003228
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003229 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003230 if n.Op == ONE {
3231 andor = OOROR
3232 }
3233
Russ Cox44928112015-03-02 20:34:22 -05003234 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003235 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003236 // Four or fewer elements of a basic type.
3237 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003238 var li *Node
3239 var ri *Node
3240 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003241 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3242 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003243 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003244 if expr == nil {
3245 expr = a
3246 } else {
3247 expr = Nod(andor, expr, a)
3248 }
3249 }
3250
3251 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003252 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003253 }
Russ Cox44928112015-03-02 20:34:22 -05003254 finishcompare(np, n, expr, init)
3255 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003256 }
3257
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003258 if t.Etype == TARRAY {
3259 // Zero- or single-element array, of any type.
3260 switch t.Bound {
3261 case 0:
3262 finishcompare(np, n, Nodbool(n.Op == OEQ), init)
3263 return
3264 case 1:
3265 l0 := Nod(OINDEX, l, Nodintconst(0))
3266 r0 := Nod(OINDEX, r, Nodintconst(0))
3267 a := Nod(n.Op, l0, r0)
3268 finishcompare(np, n, a, init)
3269 return
3270 }
3271 }
3272
Russ Cox8c195bd2015-02-13 14:40:36 -05003273 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3274 // Struct of four or fewer fields.
3275 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003276 var li *Node
3277 var ri *Node
3278 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003279 if isblanksym(t1.Sym) {
3280 continue
3281 }
3282 li = Nod(OXDOT, l, newname(t1.Sym))
3283 ri = Nod(OXDOT, r, newname(t1.Sym))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003284 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003285 if expr == nil {
3286 expr = a
3287 } else {
3288 expr = Nod(andor, expr, a)
3289 }
3290 }
3291
3292 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003293 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003294 }
Russ Cox44928112015-03-02 20:34:22 -05003295 finishcompare(np, n, expr, init)
3296 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003297 }
3298
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003299 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003300 var needsize int
3301 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003302
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003303 appendNodeSeqNode(&call.List, l)
3304 appendNodeSeqNode(&call.List, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003305 if needsize != 0 {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003306 appendNodeSeqNode(&call.List, Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003307 }
3308 r = call
3309 if n.Op != OEQ {
3310 r = Nod(ONOT, r, nil)
3311 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003312
Russ Cox44928112015-03-02 20:34:22 -05003313 finishcompare(np, n, r, init)
3314 return
3315}
3316
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003317func finishcompare(np **Node, n, r *Node, init nodesOrNodeListPtr) {
Russ Cox44928112015-03-02 20:34:22 -05003318 // Using np here to avoid passing &r to typecheck.
3319 *np = r
3320 typecheck(np, Erv)
3321 walkexpr(np, init)
3322 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003323 if r.Type != n.Type {
3324 r = Nod(OCONVNOP, r, nil)
3325 r.Type = n.Type
3326 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003327 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003328 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003329}
3330
Russ Coxdc7b54b2015-02-17 22:13:49 -05003331func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003332 var ar *Node
3333 var br *Node
3334 for a != nil && b != nil && a.Op == b.Op {
3335 switch a.Op {
3336 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003337 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003338
3339 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003340 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003341
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003342 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003343 ar = a.Right
3344 br = b.Right
3345 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003346 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003347 }
3348
3349 case OINDEX:
3350 ar = a.Right
3351 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003352 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003353 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003354 }
3355 }
3356
3357 a = a.Left
3358 b = b.Left
3359 }
3360
Russ Coxdc7b54b2015-02-17 22:13:49 -05003361 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003362}
3363
3364func walkrotate(np **Node) {
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003365 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003366 return
3367 }
3368
Russ Cox382b44e2015-02-23 16:07:24 -05003369 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003370
3371 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003372 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003373
Russ Cox382b44e2015-02-23 16:07:24 -05003374 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003375 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 -05003376 return
3377 }
3378
3379 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003380 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003381 return
3382 }
3383
3384 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003385 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003386
Russ Coxdc7b54b2015-02-17 22:13:49 -05003387 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003388 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003389 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003390 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003391 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003392 // Rewrite left shift half to left rotate.
3393 if l.Op == OLSH {
3394 n = l
3395 } else {
3396 n = r
3397 }
3398 n.Op = OLROT
3399
3400 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003401 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003402
3403 if s == 0 || s == w {
3404 n = n.Left
3405 }
3406
3407 *np = n
3408 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003409 }
3410 }
3411 return
3412 }
3413
3414 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3415 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003416}
3417
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003418// walkmul rewrites integer multiplication by powers of two as shifts.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003419func walkmul(np **Node, init nodesOrNodeListPtr) {
Russ Cox382b44e2015-02-23 16:07:24 -05003420 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003421 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003422 return
3423 }
3424
Russ Cox382b44e2015-02-23 16:07:24 -05003425 var nr *Node
3426 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003427 if n.Right.Op == OLITERAL {
3428 nl = n.Left
3429 nr = n.Right
3430 } else if n.Left.Op == OLITERAL {
3431 nl = n.Right
3432 nr = n.Left
3433 } else {
3434 return
3435 }
3436
Russ Cox382b44e2015-02-23 16:07:24 -05003437 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003438
3439 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003440 var pow int
3441 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003442 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003443 cheapexpr(nl, init)
3444 Nodconst(n, n.Type, 0)
3445 goto ret
3446 }
3447
3448 // nr is a constant.
3449 pow = powtwo(nr)
3450
3451 if pow < 0 {
3452 return
3453 }
3454 if pow >= 1000 {
3455 // negative power of 2, like -16
3456 neg = 1
3457
3458 pow -= 1000
3459 }
3460
3461 w = int(nl.Type.Width * 8)
3462 if pow+1 >= w { // too big, shouldn't happen
3463 return
3464 }
3465
3466 nl = cheapexpr(nl, init)
3467
3468 if pow == 0 {
3469 // x*1 is x
3470 n = nl
3471
3472 goto ret
3473 }
3474
3475 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3476
3477ret:
3478 if neg != 0 {
3479 n = Nod(OMINUS, n, nil)
3480 }
3481
3482 typecheck(&n, Erv)
3483 walkexpr(&n, init)
3484 *np = n
3485}
3486
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003487// walkdiv rewrites division by a constant as less expensive
3488// operations.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003489func walkdiv(np **Node, init nodesOrNodeListPtr) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003490 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003491
3492 // TODO(minux)
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003493 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003494 return
3495 }
3496
Russ Cox382b44e2015-02-23 16:07:24 -05003497 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003498 if n.Right.Op != OLITERAL {
3499 return
3500 }
3501
3502 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003503 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003504
Russ Cox382b44e2015-02-23 16:07:24 -05003505 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003506
3507 // special cases of mod/div
3508 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003509 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003510
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003511 s := 0 // 1 if nr is negative.
3512 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003513 if pow >= 1000 {
3514 // negative power of 2
3515 s = 1
3516
3517 pow -= 1000
3518 }
3519
3520 if pow+1 >= w {
3521 // divisor too large.
3522 return
3523 }
3524
3525 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003526 // try to do division by multiply by (2^w)/d
3527 // see hacker's delight chapter 10
3528 // TODO: support 64-bit magic multiply here.
3529 var m Magic
3530 m.W = w
3531
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003532 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003533 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003534 Smagic(&m)
3535 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003536 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003537 Umagic(&m)
3538 }
3539
3540 if m.Bad != 0 {
3541 return
3542 }
3543
3544 // We have a quick division method so use it
3545 // for modulo too.
3546 if n.Op == OMOD {
3547 // rewrite as A%B = A - (A/B*B).
3548 n1 := Nod(ODIV, nl, nr)
3549
3550 n2 := Nod(OMUL, n1, nr)
3551 n = Nod(OSUB, nl, n2)
3552 goto ret
3553 }
3554
3555 switch Simtype[nl.Type.Etype] {
3556 default:
3557 return
3558
3559 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003560 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003561 nc := Nod(OXXX, nil, nil)
3562
3563 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003564 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003565 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003566 if m.Ua != 0 {
3567 // Select a Go type with (at least) twice the width.
3568 var twide *Type
3569 switch Simtype[nl.Type.Etype] {
3570 default:
3571 return
3572
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003573 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003574 twide = Types[TUINT32]
3575
3576 case TUINT32:
3577 twide = Types[TUINT64]
3578
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003579 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003580 twide = Types[TINT32]
3581
3582 case TINT32:
3583 twide = Types[TINT64]
3584 }
3585
3586 // add numerator (might overflow).
3587 // n2 = (n1 + nl)
3588 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3589
3590 // shift by m.s
3591 nc := Nod(OXXX, nil, nil)
3592
3593 Nodconst(nc, Types[TUINT], int64(m.S))
3594 n = conv(Nod(ORSH, n2, nc), nl.Type)
3595 } else {
3596 // n = n1 >> m.s
3597 nc := Nod(OXXX, nil, nil)
3598
3599 Nodconst(nc, Types[TUINT], int64(m.S))
3600 n = Nod(ORSH, n1, nc)
3601 }
3602
3603 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003604 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003605 nc := Nod(OXXX, nil, nil)
3606
3607 Nodconst(nc, nl.Type, m.Sm)
Todd Neal765c0f32015-06-23 18:59:52 -05003608 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003609 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003610 if m.Sm < 0 {
3611 // add the numerator.
3612 n1 = Nod(OADD, n1, nl)
3613 }
3614
3615 // shift by m.s
3616 nc = Nod(OXXX, nil, nil)
3617
3618 Nodconst(nc, Types[TUINT], int64(m.S))
3619 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3620
3621 // add 1 iff n1 is negative.
3622 nc = Nod(OXXX, nil, nil)
3623
3624 Nodconst(nc, Types[TUINT], int64(w)-1)
3625 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3626 n = Nod(OSUB, n2, n3)
3627
3628 // apply sign.
3629 if m.Sd < 0 {
3630 n = Nod(OMINUS, n, nil)
3631 }
3632 }
3633
3634 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003635 }
3636
3637 switch pow {
3638 case 0:
3639 if n.Op == OMOD {
3640 // nl % 1 is zero.
3641 Nodconst(n, n.Type, 0)
3642 } else if s != 0 {
3643 // divide by -1
3644 n.Op = OMINUS
3645
3646 n.Right = nil
3647 } else {
3648 // divide by 1
3649 n = nl
3650 }
3651
3652 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003653 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003654 if n.Op == OMOD {
3655 // signed modulo 2^pow is like ANDing
3656 // with the last pow bits, but if nl < 0,
3657 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003658 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003659
3660 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003661 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003662 if pow == 1 {
3663 typecheck(&n1, Erv)
3664 n1 = cheapexpr(n1, init)
3665
3666 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003667 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003668
Russ Cox382b44e2015-02-23 16:07:24 -05003669 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003670 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003671 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003672 n = Nod(OADD, n3, n1)
3673 } else {
3674 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003675 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003676
3677 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003678 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003679 typecheck(&n2, Erv)
3680 n2 = cheapexpr(n2, init)
3681
Russ Cox382b44e2015-02-23 16:07:24 -05003682 n3 := Nod(OADD, nl, n2)
3683 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003684 n = Nod(OSUB, n4, n2)
3685 }
3686
3687 break
3688 } else {
3689 // arithmetic right shift does not give the correct rounding.
3690 // if nl >= 0, nl >> n == nl / nr
3691 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003692 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003693
3694 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003695 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003696 if pow == 1 {
3697 // nl+1 is nl-(-1)
3698 n.Left = Nod(OSUB, nl, n1)
3699 } else {
3700 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003701 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003702
3703 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003704 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003705 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3706 }
3707
3708 // n = (nl + 2^pow-1) >> pow
3709 n.Op = ORSH
3710
3711 nc = Nod(OXXX, nil, nil)
3712 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3713 n.Right = nc
3714 n.Typecheck = 0
3715 }
3716
3717 if s != 0 {
3718 n = Nod(OMINUS, n, nil)
3719 }
3720 break
3721 }
3722
Russ Cox382b44e2015-02-23 16:07:24 -05003723 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003724 if n.Op == OMOD {
3725 // n = nl & (nr-1)
3726 n.Op = OAND
3727
Russ Cox81d58102015-05-27 00:47:05 -04003728 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003729 } else {
3730 // n = nl >> pow
3731 n.Op = ORSH
3732
3733 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3734 }
3735
3736 n.Typecheck = 0
3737 n.Right = nc
3738 }
3739
3740 goto ret
3741
Russ Cox8c195bd2015-02-13 14:40:36 -05003742ret:
3743 typecheck(&n, Erv)
3744 walkexpr(&n, init)
3745 *np = n
3746}
3747
3748// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003749func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003750 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003751 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003752 }
3753
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003754 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003755 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003756
Russ Coxdc7b54b2015-02-17 22:13:49 -05003757 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003758 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003759 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003760 }
3761
3762 switch n.Op {
3763 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003764 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003765 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003766 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003767 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003768 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003769 }
3770
3771 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003772 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003773 }
3774
3775 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003776 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003777 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003778 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003779 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003780 }
3781 }
3782
3783 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003784 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003785 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003786 for bits > 0 && v >= 2 {
3787 bits--
3788 v >>= 1
3789 }
3790 }
3791
3792 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003793 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003794 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003795 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003796 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003797 }
3798 bits -= int32(v)
3799 }
3800 }
3801
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003802 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003803 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003804 }
3805
Russ Coxdc7b54b2015-02-17 22:13:49 -05003806 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003807}
3808
3809func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003810 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 return
3812 }
3813
3814 switch n.Op {
3815 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003816 Fatalf("usefield %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003817
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003818 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003819 break
3820 }
Keith Randall71d13a82016-03-02 20:54:41 -08003821 if n.Right == nil {
3822 // No field name. This DOTPTR was built by the compiler for access
3823 // to runtime data structures. Ignore.
3824 return
3825 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003826
Russ Cox496ad0a2015-05-26 21:49:31 -04003827 t := n.Left.Type
3828 if Isptr[t.Etype] {
3829 t = t.Type
3830 }
Russ Coxf68d1df2015-08-17 21:38:46 -04003831 field := dotField[typeSym{t.Orig, n.Right.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003832 if field == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003833 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003834 }
Russ Coxbed1f902015-03-02 16:03:26 -05003835 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003836 return
3837 }
3838
3839 // dedup on list
3840 if field.Lastfn == Curfn {
3841 return
3842 }
3843 field.Lastfn = Curfn
3844 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003845 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003846 field.Outer = field.Outer.Type
3847 }
3848 if field.Outer.Sym == nil {
3849 Yyerror("tracked field must be in named struct type")
3850 }
3851 if !exportname(field.Sym.Name) {
3852 Yyerror("tracked field must be exported (upper case)")
3853 }
3854
Russ Cox496ad0a2015-05-26 21:49:31 -04003855 Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
Russ Cox8c195bd2015-02-13 14:40:36 -05003856}
3857
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003858func candiscardlist(l nodesOrNodeList) bool {
3859 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
3860 if !candiscard(it.N()) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003861 return false
3862 }
3863 }
3864 return true
3865}
3866
Russ Coxdc7b54b2015-02-17 22:13:49 -05003867func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003868 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003869 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003870 }
3871
3872 switch n.Op {
3873 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003874 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003875
3876 // Discardable as long as the subpieces are.
3877 case ONAME,
3878 ONONAME,
3879 OTYPE,
3880 OPACK,
3881 OLITERAL,
3882 OADD,
3883 OSUB,
3884 OOR,
3885 OXOR,
3886 OADDSTR,
3887 OADDR,
3888 OANDAND,
3889 OARRAYBYTESTR,
3890 OARRAYRUNESTR,
3891 OSTRARRAYBYTE,
3892 OSTRARRAYRUNE,
3893 OCAP,
3894 OCMPIFACE,
3895 OCMPSTR,
3896 OCOMPLIT,
3897 OMAPLIT,
3898 OSTRUCTLIT,
3899 OARRAYLIT,
3900 OPTRLIT,
3901 OCONV,
3902 OCONVIFACE,
3903 OCONVNOP,
3904 ODOT,
3905 OEQ,
3906 ONE,
3907 OLT,
3908 OLE,
3909 OGT,
3910 OGE,
3911 OKEY,
3912 OLEN,
3913 OMUL,
3914 OLSH,
3915 ORSH,
3916 OAND,
3917 OANDNOT,
3918 ONEW,
3919 ONOT,
3920 OCOM,
3921 OPLUS,
3922 OMINUS,
3923 OOROR,
3924 OPAREN,
3925 ORUNESTR,
3926 OREAL,
3927 OIMAG,
3928 OCOMPLEX:
3929 break
3930
3931 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003932 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003933 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003934 break
3935 }
Russ Cox81d58102015-05-27 00:47:05 -04003936 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003937 break
3938 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003939 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003940
3941 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003942 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003943 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003944 break
3945 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003946 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003947
3948 // Difficult to tell what sizes are okay.
3949 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003950 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003951 }
3952
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003953 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 -05003954 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003955 }
3956
Russ Coxdc7b54b2015-02-17 22:13:49 -05003957 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003958}
3959
3960// rewrite
3961// print(x, y, z)
3962// into
3963// func(a1, a2, a3) {
3964// print(a1, a2, a3)
3965// }(x, y, z)
3966// and same for println.
3967
3968var walkprintfunc_prgen int
3969
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003970func walkprintfunc(np **Node, init nodesOrNodeListPtr) {
Russ Cox382b44e2015-02-23 16:07:24 -05003971 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003972
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003973 if nodeSeqLen(n.Ninit) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003974 walkstmtlist(n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003975 appendNodeSeq(init, n.Ninit)
3976 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003977 }
3978
Russ Cox382b44e2015-02-23 16:07:24 -05003979 t := Nod(OTFUNC, nil, nil)
3980 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003981 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05003982 var a *Node
3983 var buf string
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003984 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003985 buf = fmt.Sprintf("a%d", num)
3986 num++
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003987 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(it.N().Type))
3988 appendNodeSeqNode(&t.List, a)
3989 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05003990 }
3991
Russ Cox382b44e2015-02-23 16:07:24 -05003992 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003993 walkprintfunc_prgen++
3994 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003995 fn.Func.Nname = newname(Lookup(buf))
3996 fn.Func.Nname.Name.Defn = fn
3997 fn.Func.Nname.Name.Param.Ntype = t
3998 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003999
Russ Cox382b44e2015-02-23 16:07:24 -05004000 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004001 Curfn = nil
4002 funchdr(fn)
4003
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02004004 a = Nod(n.Op, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004005 setNodeSeq(&a.List, printargs)
Russ Cox8c195bd2015-02-13 14:40:36 -05004006 typecheck(&a, Etop)
4007 walkstmt(&a)
4008
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08004009 fn.Nbody.Set([]*Node{a})
Russ Cox8c195bd2015-02-13 14:40:36 -05004010
4011 funcbody(fn)
4012
4013 typecheck(&fn, Etop)
Ian Lance Taylor466c9482016-03-03 11:30:17 -08004014 typechecklist(fn.Nbody, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05004015 xtop = list(xtop, fn)
4016 Curfn = oldfn
4017
4018 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004019 a.Left = fn.Func.Nname
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004020 setNodeSeq(&a.List, n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05004021 typecheck(&a, Etop)
4022 walkexpr(&a, init)
4023 *np = a
4024}