blob: 52d35ceb2b6e17ab7ef46605976423c06fcb3bf5 [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 Taylore28a8902016-03-07 22:54:46 -080067 walkstmtlist(Curfn.Nbody.Slice())
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 Taylore28a8902016-03-07 22:54:46 -080080func walkstmtlist(s []*Node) {
81 for i := range s {
82 walkstmt(&s[i])
Russ Cox8c195bd2015-02-13 14:40:36 -050083 }
84}
85
Ian Lance Taylore28a8902016-03-07 22:54:46 -080086func samelist(a, b []*Node) bool {
87 if len(a) != len(b) {
88 return false
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080089 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080090 for i, n := range a {
91 if n != b[i] {
Russ Coxdc7b54b2015-02-17 22:13:49 -050092 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050093 }
94 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080095 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050096}
97
Dave Cheneyb006d382015-03-06 18:42:58 +110098func paramoutheap(fn *Node) bool {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080099 for _, ln := range fn.Func.Dcl {
100 switch ln.Class {
Russ Cox8c195bd2015-02-13 14:40:36 -0500101 case PPARAMOUT,
102 PPARAMOUT | PHEAP:
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800103 return ln.Addrtaken
Russ Cox8c195bd2015-02-13 14:40:36 -0500104
105 // stop early - parameters are over
106 case PAUTO,
107 PAUTO | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +1100108 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500109 }
110 }
111
Dave Cheneyb006d382015-03-06 18:42:58 +1100112 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500113}
114
115// adds "adjust" to all the argument locations for the call n.
116// n must be a defer or go node that has already been walked.
117func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500118 var arg *Node
119 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500120
Russ Cox382b44e2015-02-23 16:07:24 -0500121 callfunc := n.Left
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800122 for argsit := nodeSeqIterate(callfunc.List); !argsit.Done(); argsit.Next() {
123 arg = argsit.N()
Russ Cox8c195bd2015-02-13 14:40:36 -0500124 if arg.Op != OAS {
125 Yyerror("call arg not assignment")
126 }
127 lhs = arg.Left
128 if lhs.Op == ONAME {
129 // This is a temporary introduced by reorder1.
130 // The real store to the stack appears later in the arg list.
131 continue
132 }
133
134 if lhs.Op != OINDREG {
135 Yyerror("call argument store does not use OINDREG")
136 }
137
138 // can't really check this in machine-indep code.
139 //if(lhs->val.u.reg != D_SP)
140 // yyerror("call arg assign not indreg(SP)");
141 lhs.Xoffset += int64(adjust)
142 }
143}
144
145func walkstmt(np **Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500146 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500147 if n == nil {
148 return
149 }
150 if n.Dodata == 2 { // don't walk, generated by anylit.
151 return
152 }
153
154 setlineno(n)
155
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800156 walkstmtlist(n.Ninit.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500157
158 switch n.Op {
159 default:
160 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400161 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500162 } else {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -0800163 Yyerror("%v is not a top level statement", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500164 }
165 Dump("nottop", n)
166
167 case OAS,
168 OASOP,
169 OAS2,
170 OAS2DOTTYPE,
171 OAS2RECV,
172 OAS2FUNC,
173 OAS2MAPR,
174 OCLOSE,
175 OCOPY,
176 OCALLMETH,
177 OCALLINTER,
178 OCALL,
179 OCALLFUNC,
180 ODELETE,
181 OSEND,
182 OPRINT,
183 OPRINTN,
184 OPANIC,
185 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400186 ORECOVER,
187 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500188 if n.Typecheck == 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200189 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500190 }
Russ Cox382b44e2015-02-23 16:07:24 -0500191 init := n.Ninit
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800192 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500193 walkexpr(&n, &init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800194 addinit(&n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 if (*np).Op == OCOPY && n.Op == OCONVNOP {
196 n.Op = OEMPTY // don't leave plain values as statements.
197 }
198
199 // special case for a receive where we throw away
200 // the value received.
201 case ORECV:
202 if n.Typecheck == 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200203 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500204 }
Russ Cox382b44e2015-02-23 16:07:24 -0500205 init := n.Ninit
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800206 setNodeSeq(&n.Ninit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500207
208 walkexpr(&n.Left, &init)
209 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
210 walkexpr(&n, &init)
211
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800212 addinit(&n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500213
214 case OBREAK,
215 ODCL,
216 OCONTINUE,
217 OFALL,
218 OGOTO,
219 OLABEL,
220 ODCLCONST,
221 ODCLTYPE,
222 OCHECKNIL,
Russ Cox1ac637c2016-01-13 00:46:28 -0500223 OVARKILL,
224 OVARLIVE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500225 break
226
227 case OBLOCK:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800228 walkstmtlist(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500229
230 case OXCASE:
231 Yyerror("case statement out of place")
232 n.Op = OCASE
233 fallthrough
234
235 case OCASE:
236 walkstmt(&n.Right)
237
238 case ODEFER:
HĂ¥vard Haugen25946642015-09-07 22:19:30 +0200239 hasdefer = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500240 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700241 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500242 walkprintfunc(&n.Left, &n.Ninit)
243
244 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700245 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500246
247 default:
248 walkexpr(&n.Left, &n.Ninit)
249 }
250
251 // make room for size & fn arguments.
252 adjustargs(n, 2*Widthptr)
253
254 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400255 if n.Left != nil {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800256 walkstmtlist(n.Left.Ninit.Slice())
Russ Cox66be1482015-05-26 21:30:20 -0400257 init := n.Left.Ninit
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800258 setNodeSeq(&n.Left.Ninit, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400259 walkexpr(&n.Left, &init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800260 addinit(&n.Left, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500261 }
262
Russ Coxffef1802015-05-22 01:16:52 -0400263 walkstmt(&n.Right)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800264 walkstmtlist(n.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500265
266 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400267 walkexpr(&n.Left, &n.Ninit)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800268 walkstmtlist(n.Nbody.Slice())
269 walkstmtlist(n.Rlist.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500270
271 case OPROC:
272 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700273 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500274 walkprintfunc(&n.Left, &n.Ninit)
275
276 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700277 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500278
279 default:
280 walkexpr(&n.Left, &n.Ninit)
281 }
282
283 // make room for size & fn arguments.
284 adjustargs(n, 2*Widthptr)
285
286 case ORETURN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800287 walkexprlist(n.List.Slice(), &n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800288 if nodeSeqLen(n.List) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500289 break
290 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800291 if (Curfn.Type.Outnamed && nodeSeqLen(n.List) > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500292 // assign to the function out parameters,
293 // so that reorder3 can fix up conflicts
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800294 var rl []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500295
Robert Griesemercd7d7382015-10-26 14:57:36 -0700296 var cl Class
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800297 for _, ln := range Curfn.Func.Dcl {
298 cl = ln.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500299 if cl == PAUTO {
300 break
301 }
302 if cl == PPARAMOUT {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800303 rl = append(rl, ln)
Russ Cox8c195bd2015-02-13 14:40:36 -0500304 }
305 }
306
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800307 if got, want := nodeSeqLen(n.List), len(rl); got != want {
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800308 // order should have rewritten multi-value function calls
309 // with explicit OAS2FUNC nodes.
310 Fatalf("expected %v return arguments, have %v", want, got)
311 }
312
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800313 if samelist(rl, n.List.Slice()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500314 // special return in disguise
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800315 setNodeSeq(&n.List, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500316
317 break
318 }
319
Russ Cox8c195bd2015-02-13 14:40:36 -0500320 // move function calls out, to make reorder3's job easier.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800321 walkexprlistsafe(n.List.Slice(), &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500322
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800323 ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800324 setNodeSeq(&n.List, reorder3(ll))
325 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
326 *it.P() = applywritebarrier(it.N())
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800327 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500328 break
329 }
330
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800331 ll := ascompatte(n.Op, nil, false, Getoutarg(Curfn.Type), n.List.Slice(), 1, &n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800332 setNodeSeq(&n.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500333
334 case ORETJMP:
335 break
336
337 case OSELECT:
338 walkselect(n)
339
340 case OSWITCH:
341 walkswitch(n)
342
343 case ORANGE:
344 walkrange(n)
345
346 case OXFALL:
347 Yyerror("fallthrough statement out of place")
348 n.Op = OFALL
349 }
350
351 if n.Op == ONAME {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200352 Fatalf("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500353 }
354
355 *np = n
356}
357
David Chasee5060c72015-05-20 15:16:34 -0400358func isSmallMakeSlice(n *Node) bool {
359 if n.Op != OMAKESLICE {
360 return false
361 }
362 l := n.Left
363 r := n.Right
364 if r == nil {
365 r = l
366 }
367 t := n.Type
368
Russ Cox81d58102015-05-27 00:47:05 -0400369 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 -0400370}
371
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900372// walk the whole tree of the body of an
373// expression or simple statement.
374// the types expressions are calculated.
375// compile-time constants are evaluated.
376// complex side effects like statements are appended to init
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800377func walkexprlist(s []*Node, init *Nodes) {
378 for i := range s {
379 walkexpr(&s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500380 }
381}
382
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800383func walkexprlistsafe(s []*Node, init *Nodes) {
384 for i, n := range s {
385 s[i] = safeexpr(n, init)
386 walkexpr(&s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500387 }
388}
389
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800390func walkexprlistcheap(s []*Node, init *Nodes) {
391 for i, n := range s {
392 s[i] = cheapexpr(n, init)
393 walkexpr(&s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500394 }
395}
396
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000397// Build name of function: convI2E etc.
398// Not all names are possible
399// (e.g., we'll never generate convE2E or convE2I).
400func convFuncName(from, to *Type) string {
401 tkind := to.iet()
402 switch from.iet() {
403 case 'I':
404 switch tkind {
405 case 'E':
406 return "convI2E"
407 case 'I':
408 return "convI2I"
409 }
410 case 'T':
411 switch tkind {
412 case 'E':
413 return "convT2E"
414 case 'I':
415 return "convT2I"
416 }
417 }
418 Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
419 panic("unreachable")
420}
421
422// Build name of function: assertI2E etc.
423// If with2suffix is true, the form ending in "2" is returned".
424func assertFuncName(from, to *Type, with2suffix bool) string {
425 l := len("assertX2X2")
426 if !with2suffix {
427 l--
428 }
429 tkind := to.iet()
430 switch from.iet() {
431 case 'E':
432 switch tkind {
433 case 'I':
434 return "assertE2I2"[:l]
435 case 'E':
436 return "assertE2E2"[:l]
437 case 'T':
438 return "assertE2T2"[:l]
439 }
440 case 'I':
441 switch tkind {
442 case 'I':
443 return "assertI2I2"[:l]
444 case 'E':
445 return "assertI2E2"[:l]
446 case 'T':
447 return "assertI2T2"[:l]
448 }
449 }
450 Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
451 panic("unreachable")
452}
453
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800454func walkexpr(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -0500455 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500456
457 if n == nil {
458 return
459 }
460
461 if init == &n.Ninit {
462 // not okay to use n->ninit when walking n,
463 // because we might replace n with some other node
464 // and would lose the init list.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200465 Fatalf("walkexpr init == &n->ninit")
Russ Cox8c195bd2015-02-13 14:40:36 -0500466 }
467
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800468 if nodeSeqLen(n.Ninit) != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800469 walkstmtlist(n.Ninit.Slice())
470 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 }
472
473 // annoying case - not typechecked
474 if n.Op == OKEY {
475 walkexpr(&n.Left, init)
476 walkexpr(&n.Right, init)
477 return
478 }
479
Russ Cox382b44e2015-02-23 16:07:24 -0500480 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500481
482 if Debug['w'] > 1 {
483 Dump("walk-before", n)
484 }
485
486 if n.Typecheck != 1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200487 Fatalf("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500488 }
489
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200490opswitch:
Russ Cox8c195bd2015-02-13 14:40:36 -0500491 switch n.Op {
492 default:
493 Dump("walk", n)
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200494 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500495
496 case OTYPE,
497 ONONAME,
498 OINDREG,
499 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400500 OPARAM,
501 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500502
503 case ONOT,
504 OMINUS,
505 OPLUS,
506 OCOM,
507 OREAL,
508 OIMAG,
509 ODOTMETH,
510 ODOTINTER:
511 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500512
513 case OIND:
514 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500515
516 case ODOT:
517 usefield(n)
518 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500519
520 case ODOTPTR:
521 usefield(n)
522 if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
523 // No actual copy will be generated, so emit an explicit nil check.
524 n.Left = cheapexpr(n.Left, init)
525
526 checknil(n.Left, init)
527 }
528
529 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500530
531 case OEFACE:
532 walkexpr(&n.Left, init)
533 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500534
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700535 case OSPTR, OITAB:
Russ Cox8c195bd2015-02-13 14:40:36 -0500536 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500537
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700538 case OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500539 walkexpr(&n.Left, init)
540
541 // replace len(*[10]int) with 10.
542 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500543 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500544
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000545 if Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500546 t = t.Type
547 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500548 if Isfixedarray(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500549 safeexpr(n.Left, init)
550 Nodconst(n, n.Type, t.Bound)
551 n.Typecheck = 1
552 }
553
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700554 case OLSH, ORSH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500555 walkexpr(&n.Left, init)
556 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500557 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500558 n.Bounded = bounded(n.Right, 8*t.Width)
559 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500560 Warn("shift bounds check elided")
561 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500562
563 // Use results from call expression as arguments for complex.
564 case OAND,
565 OSUB,
566 OHMUL,
567 OLT,
568 OLE,
569 OGE,
570 OGT,
571 OADD,
572 OCOMPLEX,
573 OLROT:
574 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800575 n.Left = nodeSeqFirst(n.List)
576 n.Right = nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500577 }
578
579 walkexpr(&n.Left, init)
580 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500581
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700582 case OOR, OXOR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500583 walkexpr(&n.Left, init)
584 walkexpr(&n.Right, init)
585 walkrotate(&n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500586
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700587 case OEQ, ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500588 walkexpr(&n.Left, init)
589 walkexpr(&n.Right, init)
590
591 // Disable safemode while compiling this code: the code we
592 // generate internally can refer to unsafe.Pointer.
593 // In this case it can happen if we need to generate an ==
594 // for a struct containing a reflect.Value, which itself has
595 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500596 old_safemode := safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500597
598 safemode = 0
599 walkcompare(&n, init)
600 safemode = old_safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500601
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700602 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500603 walkexpr(&n.Left, init)
604
David Chaseffe7fbf2015-03-27 12:34:45 -0400605 // cannot put side effects from n.Right on init,
606 // because they cannot run before n.Left is checked.
607 // save elsewhere and store on the eventual n.Right.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800608 var ll Nodes
Russ Cox8c195bd2015-02-13 14:40:36 -0500609
610 walkexpr(&n.Right, &ll)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800611 addinit(&n.Right, ll.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500612
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700613 case OPRINT, OPRINTN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800614 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500615 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500616
617 case OPANIC:
618 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500619
620 case ORECOVER:
621 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500622
623 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700624 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500625
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700626 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700627 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500628
629 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500630 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700631 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500632 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500633
634 case OCALLINTER:
Russ Cox382b44e2015-02-23 16:07:24 -0500635 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800636 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200637 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500638 }
639 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800640 walkexprlist(n.List.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800641 ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List.Slice(), 0, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800642 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500643
644 case OCALLFUNC:
645 if n.Left.Op == OCLOSURE {
646 // Transform direct call of a closure to call of a normal function.
647 // transformclosure already did all preparation work.
648
David Chase731dcda2015-07-23 14:17:07 -0400649 // Prepend captured variables to argument list.
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -0800650 setNodeSeq(&n.List, append(n.Left.Func.Enter.Slice(), nodeSeqSlice(n.List)...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500651
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800652 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500653
654 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400655 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500656
657 // Update type of OCALLFUNC node.
658 // Output arguments had not changed, but their offsets could.
659 if n.Left.Type.Outtuple == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500660 t := getoutargx(n.Left.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 if t.Etype == TFIELD {
662 t = t.Type
663 }
664 n.Type = t
665 } else {
666 n.Type = getoutargx(n.Left.Type)
667 }
668 }
669
Russ Cox382b44e2015-02-23 16:07:24 -0500670 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800671 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200672 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500673 }
674
675 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800676 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500677
Russ Cox92dba0d2015-04-01 16:02:34 -0400678 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
679 switch Thearch.Thechar {
Shenghou Ma764c7512015-04-03 18:15:26 -0400680 case '5', '6', '7':
Russ Cox92dba0d2015-04-01 16:02:34 -0400681 n.Op = OSQRT
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800682 n.Left = nodeSeqFirst(n.List)
683 setNodeSeq(&n.List, nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200684 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400685 }
686 }
687
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800688 ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List.Slice(), 0, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800689 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500690
691 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500692 t := n.Left.Type
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800693 if nodeSeqLen(n.List) != 0 && nodeSeqFirst(n.List).Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200694 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500695 }
696 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800697 walkexprlist(n.List.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800698 ll := ascompatte(n.Op, n, false, getthis(t), []*Node{n.Left.Left}, 0, init)
699 lr := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List.Slice(), 0, init)
700 ll = append(ll, lr...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500701 n.Left.Left = nil
702 ullmancalc(n.Left)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800703 setNodeSeq(&n.List, reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500704
705 case OAS:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800706 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500707
708 walkexpr(&n.Left, init)
709 n.Left = safeexpr(n.Left, init)
710
Russ Coxdc7b54b2015-02-17 22:13:49 -0500711 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200712 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500713 }
714
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700715 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200716 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500717 }
718
719 switch n.Right.Op {
720 default:
721 walkexpr(&n.Right, init)
722
Russ Cox8c195bd2015-02-13 14:40:36 -0500723 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400724 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
725 // It needs to be removed in all three places.
726 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700727 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400728 // handled directly during cgen
729 walkexpr(&n.Right, init)
730 break
731 }
732
David Chaseffe7fbf2015-03-27 12:34:45 -0400733 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400734 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500735 walkexpr(&n.Right.Left, init)
736
Russ Cox382b44e2015-02-23 16:07:24 -0500737 n1 := Nod(OADDR, n.Left, nil)
738 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500739
Russ Cox4224d812015-03-20 00:06:10 -0400740 if Debug_typeassert > 0 {
741 Warn("type assertion not inlined")
742 }
743
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800744 fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
745 substArgTypes(&fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500746
747 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
748 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200749 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500750
Russ Cox8c195bd2015-02-13 14:40:36 -0500751 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400752 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400753 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500754 walkexpr(&n.Right.Left, init)
755
Russ Cox382b44e2015-02-23 16:07:24 -0500756 n1 := Nod(OADDR, n.Left, nil)
757 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500758 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
759 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200760 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400761
762 case OAPPEND:
763 // x = append(...)
764 r := n.Right
765 if r.Isddd {
766 r = appendslice(r, init) // also works for append(slice, string).
767 } else {
768 r = walkappend(r, init, n)
769 }
770 n.Right = r
771 if r.Op == OAPPEND {
772 // Left in place for back end.
773 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200774 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400775 }
776 // Otherwise, lowered for race detector.
777 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500778 }
779
780 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500781 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500782 r.Dodata = n.Dodata
783 n = r
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800784 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500785 }
786
Russ Cox8c195bd2015-02-13 14:40:36 -0500787 case OAS2:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800788 init.AppendNodes(&n.Ninit)
789 walkexprlistsafe(n.List.Slice(), init)
790 walkexprlistsafe(n.Rlist.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800791 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500792 ll = reorder3(ll)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800793 for i, n := range ll {
794 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 }
796 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500797
798 // a,b,... = fn()
799 case OAS2FUNC:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800800 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500801
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800802 r := nodeSeqFirst(n.Rlist)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800803 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500804 walkexpr(&r, init)
805
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200806 ll := ascompatet(n.Op, n.List, &r.Type, 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800807 for i, n := range ll {
808 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500809 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800810 n = liststmt(append([]*Node{r}, ll...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500811
812 // x, y = <-c
813 // orderstmt made sure x is addressable.
814 case OAS2RECV:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800815 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500816
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800817 r := nodeSeqFirst(n.Rlist)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800818 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500819 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500820 var n1 *Node
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800821 if isblank(nodeSeqFirst(n.List)) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500822 n1 = nodnil()
823 } else {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800824 n1 = Nod(OADDR, nodeSeqFirst(n.List), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500825 }
826 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500827 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800828 r = mkcall1(fn, nodeSeqSecond(n.List).Type, init, typename(r.Left.Type), r.Left, n1)
829 n = Nod(OAS, nodeSeqSecond(n.List), r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500830 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500831
832 // a,b = m[i];
833 case OAS2MAPR:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800834 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500835
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800836 r := nodeSeqFirst(n.Rlist)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800837 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500838 walkexpr(&r.Left, init)
839 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500840 t := r.Left.Type
841 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500842 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800843 switch algtype(t.Down) {
844 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500845 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800846 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500847 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800848 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500849 p = "mapaccess2_faststr"
850 }
851 }
852
Russ Cox382b44e2015-02-23 16:07:24 -0500853 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500854 if p != "" {
855 // fast versions take key by value
856 key = r.Right
857 } else {
858 // standard version takes key by reference
859 // orderexpr made sure key is addressable.
860 key = Nod(OADDR, r.Right, nil)
861
862 p = "mapaccess2"
863 }
864
865 // from:
866 // a,b = m[i]
867 // to:
868 // var,b = mapaccess2*(t, m, i)
869 // a = *var
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800870 a := nodeSeqFirst(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500871
Russ Cox382b44e2015-02-23 16:07:24 -0500872 fn := mapfn(p, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500873 r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
874
875 // mapaccess2* returns a typed bool, but due to spec changes,
876 // the boolean result of i.(T) is now untyped so we make it the
877 // same type as the variable on the lhs.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800878 if !isblank(nodeSeqSecond(n.List)) {
879 r.Type.Type.Down.Type = nodeSeqSecond(n.List).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500880 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800881 setNodeSeq(&n.Rlist, list1(r))
Russ Cox8c195bd2015-02-13 14:40:36 -0500882 n.Op = OAS2FUNC
883
884 // don't generate a = *var if a is _
885 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500886 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500887 var_.Typecheck = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800888 it := nodeSeqIterate(n.List)
889 *it.P() = var_
Russ Cox8c195bd2015-02-13 14:40:36 -0500890 walkexpr(&n, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800891 init.Append(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500892 n = Nod(OAS, a, Nod(OIND, var_, nil))
893 }
894
895 typecheck(&n, Etop)
896 walkexpr(&n, init)
897
Russ Cox8c195bd2015-02-13 14:40:36 -0500898 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
Russ Cox8c195bd2015-02-13 14:40:36 -0500899
900 case ODELETE:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800901 init.AppendNodes(&n.Ninit)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800902 map_ := nodeSeqFirst(n.List)
903 key := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500904 walkexpr(&map_, init)
905 walkexpr(&key, init)
906
907 // orderstmt made sure key is addressable.
908 key = Nod(OADDR, key, nil)
909
Russ Cox382b44e2015-02-23 16:07:24 -0500910 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500911 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500912
Russ Cox8c195bd2015-02-13 14:40:36 -0500913 case OAS2DOTTYPE:
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800914 e := nodeSeqFirst(n.Rlist) // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400915 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
916 // It needs to be removed in all three places.
917 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700918 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400919 // handled directly during gen.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800920 walkexprlistsafe(n.List.Slice(), init)
Russ Cox4224d812015-03-20 00:06:10 -0400921 walkexpr(&e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200922 break
Russ Cox4224d812015-03-20 00:06:10 -0400923 }
924
925 // res, ok = i.(T)
926 // orderstmt made sure a is addressable.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800927 init.AppendNodes(&n.Ninit)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700928
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800929 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700930 walkexpr(&e.Left, init)
931 t := e.Type // T
932 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500933
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700934 oktype := Types[TBOOL]
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800935 ok := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -0500936 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700937 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500938 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700939
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000940 fromKind := from.Type.iet()
941 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700942
943 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
944 // This is faster and shorter and allows the corresponding assertX2X2
945 // routines to skip nil checks on their last argument.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800946 if isblank(nodeSeqFirst(n.List)) {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700947 var fast *Node
948 switch {
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000949 case fromKind == 'E' && toKind == 'T':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700950 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
951 typ := Nod(OCONVNOP, typename(t), nil)
952 typ.Type = Ptrto(Types[TUINTPTR])
953 fast = Nod(OEQ, tab, typ)
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000954 case fromKind == 'I' && toKind == 'E',
955 fromKind == 'E' && toKind == 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700956 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700957 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700958 }
959 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400960 if Debug_typeassert > 0 {
961 Warn("type assertion (ok only) inlined")
962 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700963 n = Nod(OAS, ok, fast)
964 typecheck(&n, Etop)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200965 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700966 }
967 }
968
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700969 var resptr *Node // &res
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800970 if isblank(nodeSeqFirst(n.List)) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700971 resptr = nodnil()
972 } else {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -0800973 resptr = Nod(OADDR, nodeSeqFirst(n.List), nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700974 }
975 resptr.Etype = 1 // addr does not escape
976
Russ Cox4224d812015-03-20 00:06:10 -0400977 if Debug_typeassert > 0 {
978 Warn("type assertion not inlined")
979 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800980 fn := syslook(assertFuncName(from.Type, t, true))
981 substArgTypes(&fn, from.Type, t)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700982 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
983 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500984 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500985
Russ Cox4224d812015-03-20 00:06:10 -0400986 case ODOTTYPE, ODOTTYPE2:
987 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200988 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -0400989 }
990 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500991
992 case OCONVIFACE:
993 walkexpr(&n.Left, init)
994
995 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500996 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500997 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500998 l.Type = n.Type
999 l.Typecheck = n.Typecheck
1000 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001001 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001002 }
1003
Russ Cox175929b2015-03-02 14:22:05 -05001004 var ll *NodeList
Russ Coxdc7b54b2015-02-17 22:13:49 -05001005 if !Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001006 ll = list(ll, typename(n.Left.Type))
1007 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001008 if !isnilinter(n.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001009 ll = list(ll, typename(n.Type))
1010 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001011 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Russ Coxc8198342015-03-12 18:45:30 -04001012 sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -05001013 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -05001014 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001015 l.Sym = sym
1016 l.Type = Ptrto(Types[TUINT8])
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001017 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001018 l.Class = PEXTERN
1019 l.Xoffset = 0
1020 sym.Def = l
1021 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
1022 }
1023
Russ Cox382b44e2015-02-23 16:07:24 -05001024 l := Nod(OADDR, sym.Def, nil)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001025 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001026 ll = list(ll, l)
1027
Russ Coxdc7b54b2015-02-17 22:13:49 -05001028 if isdirectiface(n.Left.Type) {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001029 // For pointer types, we can make a special form of optimization
1030 //
1031 // These statements are put onto the expression init list:
1032 // Itab *tab = atomicloadtype(&cache);
1033 // if(tab == nil)
1034 // tab = typ2Itab(type, itype, &cache);
1035 //
1036 // The CONVIFACE expression is replaced with this:
1037 // OEFACE{tab, ptr};
Russ Cox382b44e2015-02-23 16:07:24 -05001038 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001039
Russ Cox382b44e2015-02-23 16:07:24 -05001040 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001041 typecheck(&n1, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001042 init.Append(n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001043
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001044 fn := syslook("typ2Itab")
Russ Cox8c195bd2015-02-13 14:40:36 -05001045 n1 = Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001046 setNodeSeq(&n1.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001047 typecheck(&n1, Erv)
1048 walkexpr(&n1, init)
1049
Russ Cox382b44e2015-02-23 16:07:24 -05001050 n2 := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -04001051 n2.Left = Nod(OEQ, l, nodnil())
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08001052 n2.Nbody.Set([]*Node{Nod(OAS, l, n1)})
Russ Cox8c195bd2015-02-13 14:40:36 -05001053 n2.Likely = -1
1054 typecheck(&n2, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001055 init.Append(n2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001056
1057 l = Nod(OEFACE, l, n.Left)
1058 l.Typecheck = n.Typecheck
1059 l.Type = n.Type
1060 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001061 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001062 }
1063 }
1064
Russ Coxdc7b54b2015-02-17 22:13:49 -05001065 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001066 ll = list(ll, n.Left)
1067 } else {
1068 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001069 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001070 // the conversions it could see. comparison of an interface
1071 // with a non-interface, especially in a switch on interface value
1072 // with non-interface cases, is not visible to orderstmt, so we
1073 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001074 if islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001075 ll = list(ll, Nod(OADDR, n.Left, nil))
1076 } else {
1077 ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
1078 }
David Chase22701332015-03-27 11:21:14 -04001079 dowidth(n.Left.Type)
1080 r := nodnil()
1081 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1082 // Allocate stack buffer for value stored in interface.
1083 r = temp(n.Left.Type)
1084 r = Nod(OAS, r, nil) // zero temp
1085 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001086 init.Append(r)
David Chase22701332015-03-27 11:21:14 -04001087 r = Nod(OADDR, r.Left, nil)
1088 typecheck(&r, Erv)
1089 }
1090 ll = list(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001091 }
1092
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001093 fn := syslook(convFuncName(n.Left.Type, n.Type))
David Chase22701332015-03-27 11:21:14 -04001094 if !Isinter(n.Left.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001095 substArgTypes(&fn, n.Left.Type, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001096 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001097 substArgTypes(&fn, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001098 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001099 dowidth(fn.Type)
1100 n = Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001101 setNodeSeq(&n.List, ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001102 typecheck(&n, Erv)
1103 walkexpr(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001104
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001105 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001106 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001107 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001108 if n.Type.Etype == TINT64 {
1109 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001110 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001111 }
1112
1113 if n.Type.Etype == TUINT64 {
1114 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001115 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001116 }
1117 }
1118
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001119 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001120 if n.Left.Type.Etype == TINT64 {
1121 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001122 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001123 }
1124
1125 if n.Left.Type.Etype == TUINT64 {
1126 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001127 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001128 }
1129 }
1130 }
1131
1132 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001133
1134 case OANDNOT:
1135 walkexpr(&n.Left, init)
1136 n.Op = OAND
1137 n.Right = Nod(OCOM, n.Right, nil)
1138 typecheck(&n.Right, Erv)
1139 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001140
1141 case OMUL:
1142 walkexpr(&n.Left, init)
1143 walkexpr(&n.Right, init)
1144 walkmul(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001145
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001146 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001147 walkexpr(&n.Left, init)
1148 walkexpr(&n.Right, init)
1149
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001150 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001151 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001152
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001153 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001154 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001155 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1156 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001157 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001158 }
1159
1160 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001161 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001162 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001163 }
1164
1165 // Try rewriting as shifts or magic multiplies.
1166 walkdiv(&n, init)
1167
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001168 // rewrite 64-bit div and mod into function calls
1169 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001170 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001171 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001172 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001173 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001174 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001175 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001176 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001177 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001178 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001179 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001180 }
1181 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001182 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001183 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001184 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001185 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001186 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001187 }
1188
Russ Cox8c195bd2015-02-13 14:40:36 -05001189 case OINDEX:
1190 walkexpr(&n.Left, init)
1191
1192 // save the original node for bounds checking elision.
1193 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001194 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001195
1196 walkexpr(&n.Right, init)
1197
1198 // if range of type cannot exceed static array bound,
1199 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001200 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001201 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001202 }
Russ Cox382b44e2015-02-23 16:07:24 -05001203 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001204 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001205 t = t.Type
1206 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001207 if Isfixedarray(t) {
1208 n.Bounded = bounded(r, t.Bound)
1209 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001210 Warn("index bounds check elided")
1211 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001212 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001213 Yyerror("index out of bounds")
1214 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001215 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001216 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001217 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001218 Warn("index bounds check elided")
1219 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001220 if Smallintconst(n.Right) {
1221 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001222 Yyerror("index out of bounds")
1223 } else {
1224 // replace "abc"[1] with 'b'.
1225 // delayed until now because "abc"[1] is not
1226 // an ideal constant.
Russ Cox81d58102015-05-27 00:47:05 -04001227 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05001228
Russ Cox81d58102015-05-27 00:47:05 -04001229 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001230 n.Typecheck = 1
1231 }
1232 }
1233 }
1234
Russ Coxdc7b54b2015-02-17 22:13:49 -05001235 if Isconst(n.Right, CTINT) {
Russ Cox81d58102015-05-27 00:47:05 -04001236 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 -05001237 Yyerror("index out of bounds")
1238 }
1239 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001240
1241 case OINDEXMAP:
1242 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001243 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001244 }
1245 walkexpr(&n.Left, init)
1246 walkexpr(&n.Right, init)
1247
Russ Cox382b44e2015-02-23 16:07:24 -05001248 t := n.Left.Type
1249 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001250 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001251 switch algtype(t.Down) {
1252 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001253 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001254 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001255 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001256 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001257 p = "mapaccess1_faststr"
1258 }
1259 }
1260
Russ Cox382b44e2015-02-23 16:07:24 -05001261 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001262 if p != "" {
1263 // fast versions take key by value
1264 key = n.Right
1265 } else {
1266 // standard version takes key by reference.
1267 // orderexpr made sure key is addressable.
1268 key = Nod(OADDR, n.Right, nil)
1269
1270 p = "mapaccess1"
1271 }
1272
1273 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1274 n = Nod(OIND, n, nil)
1275 n.Type = t.Type
1276 n.Typecheck = 1
1277
Russ Cox8c195bd2015-02-13 14:40:36 -05001278 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001279 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001280
Russ Coxd4472792015-05-06 12:35:53 -04001281 case OSLICE, OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001282 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001283 walkexpr(&n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001284 if n.Right.Left != nil && iszero(n.Right.Left) {
1285 // Reduce x[0:j] to x[:j].
1286 n.Right.Left = nil
1287 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001288 walkexpr(&n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001289 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001290
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001291 case OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -04001292 walkexpr(&n.Left, init)
1293 walkexpr(&n.Right.Left, init)
1294 if n.Right.Left != nil && iszero(n.Right.Left) {
1295 // Reduce x[0:j:k] to x[:j:k].
1296 n.Right.Left = nil
1297 }
1298 walkexpr(&n.Right.Right.Left, init)
1299 walkexpr(&n.Right.Right.Right, init)
1300
1301 r := n.Right.Right.Right
1302 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1303 // Reduce x[i:j:cap(x)] to x[i:j].
1304 n.Right.Right = n.Right.Right.Left
1305 if n.Op == OSLICE3 {
1306 n.Op = OSLICE
1307 } else {
1308 n.Op = OSLICEARR
1309 }
1310 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001311 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001312
1313 case OADDR:
1314 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001315
1316 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001317 if n.Esc == EscNone {
1318 if n.Type.Type.Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001319 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001320 }
Russ Cox382b44e2015-02-23 16:07:24 -05001321 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001322 r = Nod(OAS, r, nil) // zero temp
1323 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001324 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001325 r = Nod(OADDR, r.Left, nil)
1326 typecheck(&r, Erv)
1327 n = r
1328 } else {
1329 n = callnew(n.Type.Type)
1330 }
1331
Russ Cox8c195bd2015-02-13 14:40:36 -05001332 // If one argument to the comparison is an empty string,
1333 // comparing the lengths instead will yield the same result
1334 // without the function call.
1335 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001336 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 +02001337 // TODO(marvin): Fix Node.EType type union.
1338 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001339 typecheck(&r, Erv)
1340 walkexpr(&r, init)
1341 r.Type = n.Type
1342 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001343 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001344 }
1345
1346 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001347 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 +02001348 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001349 r := Nod(Op(n.Etype), Nod(OLEN, nodeSeqFirst(n.Left.List), nil), Nodintconst(0))
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
Russ Cox382b44e2015-02-23 16:07:24 -05001357 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001358 // TODO(marvin): Fix Node.EType type union.
1359 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001360 // prepare for rewrite below
1361 n.Left = cheapexpr(n.Left, init)
1362
1363 n.Right = cheapexpr(n.Right, init)
1364
1365 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1366
1367 // quick check of len before full compare for == or !=
1368 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001369 // TODO(marvin): Fix Node.EType type union.
1370 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001371 // len(left) == len(right) && eqstring(left, right)
1372 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1373 } else {
1374 // len(left) != len(right) || !eqstring(left, right)
1375 r = Nod(ONOT, r, nil)
1376
1377 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1378 }
1379
1380 typecheck(&r, Erv)
1381 walkexpr(&r, nil)
1382 } else {
1383 // sys_cmpstring(s1, s2) :: 0
1384 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1385
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001386 // TODO(marvin): Fix Node.EType type union.
1387 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001388 }
1389
1390 typecheck(&r, Erv)
1391 if n.Type.Etype != TBOOL {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001392 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001393 }
1394 r.Type = n.Type
1395 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001396
1397 case OADDSTR:
1398 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001399
1400 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001401 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001402 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001403
1404 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001405 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001406
1407 // cannot use chanfn - closechan takes any, not chan any
1408 case OCLOSE:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001409 fn := syslook("closechan")
Russ Cox8c195bd2015-02-13 14:40:36 -05001410
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001411 substArgTypes(&fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001412 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001413
1414 case OMAKECHAN:
1415 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 -05001416
1417 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001418 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001419
Russ Cox382b44e2015-02-23 16:07:24 -05001420 a := nodnil() // hmap buffer
1421 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001422 if n.Esc == EscNone {
1423 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001424 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001425
1426 a = Nod(OAS, var_, nil) // zero temp
1427 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001428 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001429 a = Nod(OADDR, var_, nil)
1430
1431 // Allocate one bucket on stack.
1432 // Maximum key/value size is 128 bytes, larger objects
1433 // are stored with an indirection. So max bucket size is 2048+eps.
1434 var_ = temp(mapbucket(t))
1435
1436 r = Nod(OAS, var_, nil) // zero temp
1437 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001438 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001439 r = Nod(OADDR, var_, nil)
1440 }
1441
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001442 fn := syslook("makemap")
1443 substArgTypes(&fn, hmap(t), mapbucket(t), t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001444 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001445
1446 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001447 l := n.Left
1448 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001449 if r == nil {
1450 r = safeexpr(l, init)
1451 l = r
1452 }
Russ Cox382b44e2015-02-23 16:07:24 -05001453 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001454 if n.Esc == EscNone {
1455 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001456 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001457 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001458 // var arr [r]T
1459 // n = arr[:l]
1460 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001461 var_ := temp(t)
1462 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001463 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001464 init.Append(a)
Russ Cox382b44e2015-02-23 16:07:24 -05001465 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001466 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001467 typecheck(&r, Erv)
1468 walkexpr(&r, init)
1469 n = r
1470 } else {
1471 // makeslice(t *Type, nel int64, max int64) (ary []any)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001472 fn := syslook("makeslice")
Russ Cox8c195bd2015-02-13 14:40:36 -05001473
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001474 substArgTypes(&fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001475 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1476 }
1477
Russ Cox8c195bd2015-02-13 14:40:36 -05001478 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001479 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001480 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001481 t := aindex(Nodintconst(4), Types[TUINT8])
1482 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001483 a = Nod(OADDR, var_, nil)
1484 }
1485
1486 // intstring(*[4]byte, rune)
1487 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1488
Russ Cox8c195bd2015-02-13 14:40:36 -05001489 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001490 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001491 if n.Esc == EscNone {
1492 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001493 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001494
1495 a = Nod(OADDR, temp(t), nil)
1496 }
1497
1498 // slicebytetostring(*[32]byte, []byte) string;
1499 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1500
Russ Cox8c195bd2015-02-13 14:40:36 -05001501 // slicebytetostringtmp([]byte) string;
1502 case OARRAYBYTESTRTMP:
1503 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1504
Russ Cox8c195bd2015-02-13 14:40:36 -05001505 // slicerunetostring(*[32]byte, []rune) string;
1506 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001507 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001508
1509 if n.Esc == EscNone {
1510 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001511 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001512
1513 a = Nod(OADDR, temp(t), nil)
1514 }
1515
1516 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001517
1518 // stringtoslicebyte(*32[byte], string) []byte;
1519 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001520 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001521
1522 if n.Esc == EscNone {
1523 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001524 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001525
1526 a = Nod(OADDR, temp(t), nil)
1527 }
1528
1529 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001530
1531 // stringtoslicebytetmp(string) []byte;
1532 case OSTRARRAYBYTETMP:
1533 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1534
Russ Cox8c195bd2015-02-13 14:40:36 -05001535 // stringtoslicerune(*[32]rune, string) []rune
1536 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001537 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001538
1539 if n.Esc == EscNone {
1540 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001541 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001542
1543 a = Nod(OADDR, temp(t), nil)
1544 }
1545
1546 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001547
1548 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1549 case OCMPIFACE:
1550 if !Eqtype(n.Left.Type, n.Right.Type) {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08001551 Fatalf("ifaceeq %v %v %v", Oconv(n.Op, 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001552 }
Russ Cox382b44e2015-02-23 16:07:24 -05001553 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001554 if isnilinter(n.Left.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001555 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001556 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001557 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001558 }
1559
1560 n.Right = cheapexpr(n.Right, init)
1561 n.Left = cheapexpr(n.Left, init)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001562 substArgTypes(&fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001563 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001564 // TODO(marvin): Fix Node.EType type union.
1565 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001566 r = Nod(ONOT, r, nil)
1567 }
1568
1569 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001570 // TODO(marvin): Fix Node.EType type union.
1571 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001572 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1573 } else {
1574 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1575 }
1576 typecheck(&r, Erv)
1577 walkexpr(&r, init)
1578 r.Type = n.Type
1579 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001580
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001581 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001582 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001583 anylit(0, n, var_, init)
1584 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001585
1586 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001587 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001588 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1589 walkexpr(&n1, init)
1590 n1 = Nod(OADDR, n1, nil)
1591 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001592
1593 case OCLOSURE:
1594 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001595
1596 case OCALLPART:
1597 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001598 }
1599
Russ Cox8c195bd2015-02-13 14:40:36 -05001600 // Expressions that are constant at run time but not
1601 // considered const by the language spec are not turned into
1602 // constants until walk. For example, if n is y%1 == 0, the
1603 // walk of y%1 may have replaced it by 0.
1604 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001605 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001606
1607 evconst(n)
1608 n.Type = t
1609 if n.Op == OLITERAL {
1610 typecheck(&n, Erv)
1611 }
1612
1613 ullmancalc(n)
1614
1615 if Debug['w'] != 0 && n != nil {
1616 Dump("walk", n)
1617 }
1618
1619 lineno = lno
1620 *np = n
1621}
1622
Russ Coxd4472792015-05-06 12:35:53 -04001623func reduceSlice(n *Node) *Node {
1624 r := n.Right.Right
1625 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1626 // Reduce x[i:len(x)] to x[i:].
1627 n.Right.Right = nil
1628 }
1629 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1630 // Reduce x[:] to x.
1631 if Debug_slice > 0 {
1632 Warn("slice: omit slice operation")
1633 }
1634 return n.Left
1635 }
1636 return n
1637}
1638
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001639func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001640 // convas will turn map assigns into function calls,
1641 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001642 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001643
1644 if l.Op == OINDEXMAP {
1645 return n
1646 }
1647
1648 return convas(n, init)
1649}
1650
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001651func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001652 // check assign expression list to
1653 // a expression list. called in
1654 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001655
1656 // ensure order of evaluation for function calls
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001657 for nlit := nodeSeqIterate(nl); !nlit.Done(); nlit.Next() {
1658 *nlit.P() = safeexpr(nlit.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001659 }
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001660 for nrit := nodeSeqIterate(nr); !nrit.Done(); nrit.Next() {
1661 *nrit.P() = safeexpr(nrit.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001662 }
1663
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001664 var nn []*Node
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001665 nlit := nodeSeqIterate(nl)
1666 nrit := nodeSeqIterate(nr)
1667 for ; !nlit.Done() && !nrit.Done(); nlit.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001668 // Do not generate 'x = x' during return. See issue 4014.
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001669 if op == ORETURN && nlit.N() == nrit.N() {
1670 nrit.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001671 continue
1672 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001673 nn = append(nn, ascompatee1(op, nlit.N(), nrit.N(), init))
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001674 nrit.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001675 }
1676
1677 // cannot happen: caller checked that lists had same length
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001678 if !nlit.Done() || !nrit.Done() {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001679 var nln, nrn Nodes
1680 nln.Set(nl)
1681 nrn.Set(nr)
1682 Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nln, obj.FmtSign), Oconv(op, 0), Hconv(nrn, obj.FmtSign), nodeSeqLen(nl), nodeSeqLen(nr), Curfn.Func.Nname.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -05001683 }
1684 return nn
1685}
1686
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001687// l is an lv and rt is the type of an rv
1688// return 1 if this implies a function call
1689// evaluating the lv or a function call
1690// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001691func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001692 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001693 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001694 }
Russ Cox175929b2015-03-02 14:22:05 -05001695 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001696 if needwritebarrier(l, &r) {
1697 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001698 }
1699 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001700 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001701 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001702 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001703}
1704
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001705func ascompatet(op Op, nl Nodes, nr **Type, fp int, init *Nodes) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001706 var l *Node
1707 var tmp *Node
1708 var a *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001709 var saver Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001710
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001711 // check assign type list to
1712 // a expression list. called in
1713 // expr-list = func()
Russ Cox382b44e2015-02-23 16:07:24 -05001714 r := Structfirst(&saver, nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001715
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001716 var nn []*Node
1717 var mm []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001718 ucount := 0
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001719 it := nodeSeqIterate(nl)
1720 for ; !it.Done(); it.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001721 if r == nil {
1722 break
1723 }
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001724 l = it.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001725 if isblank(l) {
1726 r = structnext(&saver)
1727 continue
1728 }
1729
1730 // any lv that causes a fn call must be
1731 // deferred until all the return arguments
1732 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001733 if fncall(l, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001734 tmp = temp(r.Type)
1735 typecheck(&tmp, Erv)
1736 a = Nod(OAS, l, tmp)
1737 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001738 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001739 l = tmp
1740 }
1741
1742 a = Nod(OAS, l, nodarg(r, fp))
1743 a = convas(a, init)
1744 ullmancalc(a)
1745 if a.Ullman >= UINF {
1746 Dump("ascompatet ucount", a)
1747 ucount++
1748 }
1749
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001750 nn = append(nn, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001751 r = structnext(&saver)
1752 }
1753
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08001754 if !it.Done() || r != nil {
1755 Yyerror("ascompatet: assignment count mismatch: %d = %d", nodeSeqLen(nl), structcount(*nr))
Russ Cox8c195bd2015-02-13 14:40:36 -05001756 }
1757
1758 if ucount != 0 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001759 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001760 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001761 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001762}
1763
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001764// package all the arguments that match a ... T parameter into a []T.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001765func mkdotargslice(lr0, nn []*Node, l *Type, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001766 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001767 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001768 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001769 }
1770
Russ Cox382b44e2015-02-23 16:07:24 -05001771 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001772 tslice.Type = l.Type.Type
1773 tslice.Bound = -1
1774
Russ Cox382b44e2015-02-23 16:07:24 -05001775 var n *Node
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001776 if nodeSeqLen(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001777 n = nodnil()
1778 n.Type = tslice
1779 } else {
1780 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001781 if ddd != nil && prealloc[ddd] != nil {
1782 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001783 }
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001784 setNodeSeq(&n.List, lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001785 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001786 typecheck(&n, Erv)
1787 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001788 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 }
1790 walkexpr(&n, init)
1791 }
1792
Russ Cox382b44e2015-02-23 16:07:24 -05001793 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001794 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001795 return nn
1796}
1797
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001798// helpers for shape errors
Russ Cox8c195bd2015-02-13 14:40:36 -05001799func dumptypes(nl **Type, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001800 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001801
Russ Cox382b44e2015-02-23 16:07:24 -05001802 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001803 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001804 first := 1
1805 for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 if first != 0 {
1807 first = 0
1808 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001809 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001810 }
Russ Coxc8198342015-03-12 18:45:30 -04001811 fmt_ += Tconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001812 }
1813
1814 if first != 0 {
1815 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1816 }
1817 return fmt_
1818}
1819
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001820func dumpnodetypes(l []*Node, what string) string {
Russ Cox8c195bd2015-02-13 14:40:36 -05001821 var r *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001822
Russ Cox382b44e2015-02-23 16:07:24 -05001823 fmt_ := ""
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001824 fmt_ += "\t"
Russ Cox382b44e2015-02-23 16:07:24 -05001825 first := 1
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001826 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
1827 r = it.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001828 if first != 0 {
1829 first = 0
1830 } else {
Josh Bleecher Snyder05ca0f32015-02-28 20:31:32 +00001831 fmt_ += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 }
Russ Coxc8198342015-03-12 18:45:30 -04001833 fmt_ += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001834 }
1835
1836 if first != 0 {
1837 fmt_ += fmt.Sprintf("[no arguments %s]", what)
1838 }
1839 return fmt_
1840}
1841
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001842// check assign expression list to
1843// a type list. called in
1844// return expr-list
1845// func(expr-list)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001846func ascompatte(op Op, call *Node, isddd bool, nl **Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001847 var savel Iter
Russ Cox8c195bd2015-02-13 14:40:36 -05001848
Russ Cox382b44e2015-02-23 16:07:24 -05001849 lr0 := lr
1850 l := Structfirst(&savel, nl)
Russ Cox175929b2015-03-02 14:22:05 -05001851 var r *Node
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001852 if nodeSeqLen(lr) > 0 {
1853 r = nodeSeqFirst(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001854 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001855 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001856
1857 // f(g()) where g has multiple return values
Russ Cox382b44e2015-02-23 16:07:24 -05001858 var a *Node
1859 var l2 string
1860 var ll *Type
1861 var l1 string
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001862 if r != nil && nodeSeqLen(lr) <= 1 && r.Type.Etype == TSTRUCT && r.Type.Funarg {
Russ Cox8c195bd2015-02-13 14:40:36 -05001863 // optimization - can do block copy
Russ Coxdc7b54b2015-02-17 22:13:49 -05001864 if eqtypenoname(r.Type, *nl) {
Russ Cox382b44e2015-02-23 16:07:24 -05001865 a := nodarg(*nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001866 r = Nod(OCONVNOP, r, nil)
1867 r.Type = a.Type
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001868 nn = []*Node{convas(Nod(OAS, a, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001869 goto ret
1870 }
1871
1872 // conversions involved.
1873 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001874 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001875
Russ Cox382b44e2015-02-23 16:07:24 -05001876 for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001877 a = temp(l.Type)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001878 alist = append(alist, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001879 }
1880
1881 a = Nod(OAS2, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001882 setNodeSeq(&a.List, alist)
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001883 setNodeSeq(&a.Rlist, lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001884 typecheck(&a, Etop)
1885 walkstmt(&a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001886 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001887 lr = alist
Ian Lance Taylorbf390982016-03-03 15:08:25 -08001888 r = nodeSeqFirst(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001889 l = Structfirst(&savel, nl)
1890 }
1891
1892loop:
Dave Cheneyd3287562015-03-09 16:24:07 +11001893 if l != nil && l.Isddd {
Russ Cox8c195bd2015-02-13 14:40:36 -05001894 // the ddd parameter must be last
1895 ll = structnext(&savel)
1896
1897 if ll != nil {
1898 Yyerror("... must be last argument")
1899 }
1900
1901 // special case --
1902 // only if we are assigning a single ddd
1903 // argument to a ddd parameter then it is
1904 // passed thru unencapsulated
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001905 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001906 a = Nod(OAS, nodarg(l, fp), r)
1907 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001908 nn = append(nn, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001909 goto ret
1910 }
1911
1912 // normal case -- make a slice of all
1913 // remaining arguments and pass it to
1914 // the ddd parameter.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001915 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05001916
1917 goto ret
1918 }
1919
1920 if l == nil || r == nil {
1921 if l != nil || r != nil {
1922 l1 = dumptypes(nl, "expected")
1923 l2 = dumpnodetypes(lr0, "given")
1924 if l != nil {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08001925 Yyerror("not enough arguments to %v\n%s\n%s", Oconv(op, 0), l1, l2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001926 } else {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08001927 Yyerror("too many arguments to %v\n%s\n%s", Oconv(op, 0), l1, l2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001928 }
1929 }
1930
1931 goto ret
1932 }
1933
1934 a = Nod(OAS, nodarg(l, fp), r)
1935 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001936 nn = append(nn, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001937
1938 l = structnext(&savel)
1939 r = nil
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001940 lr = lr[1:]
1941 if len(lr) > 0 {
1942 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001943 }
1944 goto loop
1945
1946ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001947 for _, n := range nn {
1948 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001949 }
1950 return nn
1951}
1952
1953// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001954func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001955 var r *Node
1956 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001957 var on *Node
1958 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001959 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001960
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001961 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001962 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001963 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001964 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001965
1966 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001967 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001968
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001969 calls = append(calls, mkcall("printlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001970
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001971 for it := nodeSeqIterate(all); !it.Done(); it.Next() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001972 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001973 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001974 }
1975
Russ Coxdc7b54b2015-02-17 22:13:49 -05001976 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001977
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001978 n = it.N()
Russ Cox8c195bd2015-02-13 14:40:36 -05001979 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04001980 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001981 case CTRUNE:
1982 defaultlit(&n, runetype)
1983
1984 case CTINT:
1985 defaultlit(&n, Types[TINT64])
1986
1987 case CTFLT:
1988 defaultlit(&n, Types[TFLOAT64])
1989 }
1990 }
1991
1992 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
1993 defaultlit(&n, Types[TINT64])
1994 }
1995 defaultlit(&n, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08001996 *it.P() = n
Russ Cox8c195bd2015-02-13 14:40:36 -05001997 if n.Type == nil || n.Type.Etype == TFORW {
1998 continue
1999 }
2000
2001 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002002 et = n.Type.Etype
Russ Coxdc7b54b2015-02-17 22:13:49 -05002003 if Isinter(n.Type) {
2004 if isnilinter(n.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002005 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002006 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002007 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002008 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002009 substArgTypes(&on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002010 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002011 on = syslook("printpointer")
2012 substArgTypes(&on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05002013 } else if Isslice(n.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002014 on = syslook("printslice")
2015 substArgTypes(&on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002016 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002017 if et == TUINT64 {
2018 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002019 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002020 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002021 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002022 }
2023 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002024 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002025 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002026 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002027 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002028 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002029 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002030 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002031 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05002032 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002033 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05002034 } else {
2035 badtype(OPRINT, n.Type, nil)
2036 continue
2037 }
2038
2039 t = *getinarg(on.Type)
2040 if t != nil {
2041 t = t.Type
2042 }
2043 if t != nil {
2044 t = t.Type
2045 }
2046
2047 if !Eqtype(t, n.Type) {
2048 n = Nod(OCONV, n, nil)
2049 n.Type = t
2050 }
2051
2052 r = Nod(OCALL, on, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002053 appendNodeSeqNode(&r.List, n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002054 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002055 }
2056
2057 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002058 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002059 }
2060
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002061 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002062
2063 typechecklist(calls, Etop)
2064 walkexprlist(calls, init)
2065
2066 r = Nod(OEMPTY, nil, nil)
2067 typecheck(&r, Etop)
2068 walkexpr(&r, init)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002069 setNodeSeq(&r.Ninit, calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002070 return r
2071}
2072
2073func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002074 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002075 fn := syslook("newobject")
2076 substArgTypes(&fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002077 return mkcall1(fn, Ptrto(t), nil, typename(t))
2078}
2079
Russ Cox3b6e86f2015-06-29 15:17:14 -04002080func iscallret(n *Node) bool {
2081 n = outervalue(n)
2082 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2083}
2084
Russ Coxdc7b54b2015-02-17 22:13:49 -05002085func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002086 n = outervalue(n)
2087
2088 // If n is *autotmp and autotmp = &foo, replace n with foo.
2089 // We introduce such temps when initializing struct literals.
2090 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002091 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002092 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2093 n = defn.Right.Left
2094 }
2095 }
2096
2097 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002098 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002099 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002100
2101 case ONAME:
2102 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002103 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002104 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002105 }
2106 }
2107
Russ Coxdc7b54b2015-02-17 22:13:49 -05002108 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002109}
2110
Russ Coxdc7b54b2015-02-17 22:13:49 -05002111func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002112 n = outervalue(n)
2113
2114 switch n.Op {
2115 case ONAME:
2116 switch n.Class {
2117 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002118 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002119 }
2120 }
2121
Russ Coxdc7b54b2015-02-17 22:13:49 -05002122 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002123}
2124
2125// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002126func needwritebarrier(l *Node, r *Node) bool {
2127 if use_writebarrier == 0 {
2128 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002129 }
2130
2131 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002132 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002133 }
2134
2135 // No write barrier for write of non-pointers.
2136 dowidth(l.Type)
2137
2138 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002139 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002140 }
2141
2142 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002143 if isstack(l) {
2144 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002145 }
2146
Russ Cox9f90f312015-06-29 12:49:25 -04002147 // No write barrier for implicit zeroing.
2148 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002149 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002150 }
2151
Russ Cox9f90f312015-06-29 12:49:25 -04002152 // Ignore no-op conversions when making decision.
2153 // Ensures that xp = unsafe.Pointer(&x) is treated
2154 // the same as xp = &x.
2155 for r.Op == OCONVNOP {
2156 r = r.Left
2157 }
2158
2159 // No write barrier for zeroing or initialization to constant.
2160 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002161 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002162 }
2163
2164 // No write barrier for storing static (read-only) data.
2165 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002166 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002167 }
2168
2169 // No write barrier for storing address of stack values,
2170 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002171 if r.Op == OADDR && isstack(r.Left) {
2172 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002173 }
2174
2175 // No write barrier for storing address of global, which
2176 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002177 if r.Op == OADDR && isglobal(r.Left) {
2178 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002179 }
2180
Russ Cox8c195bd2015-02-13 14:40:36 -05002181 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002182 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002183}
2184
2185// TODO(rsc): Perhaps componentgen should run before this.
2186
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002187func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002188 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002189 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002190 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002191 }
Russ Cox972a4782015-05-21 15:00:06 -04002192 n.Op = OASWB
2193 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002194 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002195 return n
2196}
2197
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002198func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002199 if n.Op != OAS {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002200 Fatalf("convas: not OAS %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002201 }
2202
2203 n.Typecheck = 1
2204
Russ Cox382b44e2015-02-23 16:07:24 -05002205 var lt *Type
2206 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002207 if n.Left == nil || n.Right == nil {
2208 goto out
2209 }
2210
2211 lt = n.Left.Type
2212 rt = n.Right.Type
2213 if lt == nil || rt == nil {
2214 goto out
2215 }
2216
2217 if isblank(n.Left) {
2218 defaultlit(&n.Right, nil)
2219 goto out
2220 }
2221
2222 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002223 map_ := n.Left.Left
2224 key := n.Left.Right
2225 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002226 walkexpr(&map_, init)
2227 walkexpr(&key, init)
2228 walkexpr(&val, init)
2229
2230 // orderexpr made sure key and val are addressable.
2231 key = Nod(OADDR, key, nil)
2232
2233 val = Nod(OADDR, val, nil)
2234 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2235 goto out
2236 }
2237
2238 if !Eqtype(lt, rt) {
2239 n.Right = assignconv(n.Right, lt, "assignment")
2240 walkexpr(&n.Right, init)
2241 }
2242
2243out:
2244 ullmancalc(n)
2245 return n
2246}
2247
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002248// from ascompat[te]
2249// evaluating actual function arguments.
2250// f(a,b)
2251// if there is exactly one function expr,
2252// then it is done first. otherwise must
2253// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002254func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002255 c := 0 // function calls
2256 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002257
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002258 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002259 t++
2260 ullmancalc(n)
2261 if n.Ullman >= UINF {
2262 c++
2263 }
2264 }
2265
2266 if c == 0 || t == 1 {
2267 return all
2268 }
2269
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002270 var g []*Node // fncalls assigned to tempnames
2271 var f *Node // last fncall assigned to stack
2272 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002273 d := 0
2274 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002275 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002276 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002277 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002278 continue
2279 }
2280
2281 d++
2282 if d == c {
2283 f = n
2284 continue
2285 }
2286
2287 // make assignment of fncall to tempname
2288 a = temp(n.Right.Type)
2289
2290 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002291 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002292
2293 // put normal arg assignment on list
2294 // with fncall replaced by tempname
2295 n.Right = a.Left
2296
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002297 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002298 }
2299
2300 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002301 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002302 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002303 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002304}
2305
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002306// from ascompat[ee]
2307// a,b = c,d
2308// simultaneous assignment. there cannot
2309// be later use of an earlier lvalue.
2310//
2311// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002312func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002313 var l *Node
2314
2315 // If a needed expression may be affected by an
2316 // earlier assignment, make an early copy of that
2317 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002318 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002319
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002320 var mapinit Nodes
2321 for i, n := range all {
2322 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002323
2324 // Save subexpressions needed on left side.
2325 // Drill through non-dereferences.
2326 for {
2327 if l.Op == ODOT || l.Op == OPAREN {
2328 l = l.Left
2329 continue
2330 }
2331
Russ Coxdc7b54b2015-02-17 22:13:49 -05002332 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002333 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002334 l = l.Left
2335 continue
2336 }
2337
2338 break
2339 }
2340
2341 switch l.Op {
2342 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002343 Fatalf("reorder3 unexpected lvalue %v", Oconv(l.Op, obj.FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002344
2345 case ONAME:
2346 break
2347
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002348 case OINDEX, OINDEXMAP:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002349 reorder3save(&l.Left, all, i, &early)
2350 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002351 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002352 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002353 }
2354
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002355 case OIND, ODOTPTR:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002356 reorder3save(&l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002357 }
2358
2359 // Save expression on right side.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002360 reorder3save(&all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002361 }
2362
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002363 early = append(mapinit.Slice(), early...)
2364 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002365}
2366
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002367// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002368// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002369// copy into a temporary during *early and
2370// replace *np with that temp.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002371func reorder3save(np **Node, all []*Node, i int, early *[]*Node) {
Russ Cox382b44e2015-02-23 16:07:24 -05002372 n := *np
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002373 if !aliased(n, all, i) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002374 return
2375 }
2376
Russ Cox382b44e2015-02-23 16:07:24 -05002377 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002378 q = Nod(OAS, q, n)
2379 typecheck(&q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002380 *early = append(*early, q)
Russ Cox8c195bd2015-02-13 14:40:36 -05002381 *np = q.Left
2382}
2383
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002384// what's the outer value that a write to n affects?
2385// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002386func outervalue(n *Node) *Node {
2387 for {
2388 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002389 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002390 }
2391 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2392 n = n.Left
2393 continue
2394 }
2395
Russ Coxdc7b54b2015-02-17 22:13:49 -05002396 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002397 n = n.Left
2398 continue
2399 }
2400
2401 break
2402 }
2403
2404 return n
2405}
2406
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002407// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002408// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002409func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002410 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002411 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002412 }
2413
2414 // Look for obvious aliasing: a variable being assigned
2415 // during the all list and appearing in n.
2416 // Also record whether there are any writes to main memory.
2417 // Also record whether there are any writes to variables
2418 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002419 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002420
Russ Cox382b44e2015-02-23 16:07:24 -05002421 varwrite := 0
2422 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002423 for _, an := range all[:i] {
2424 a = outervalue(an.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05002425 if a.Op != ONAME {
2426 memwrite = 1
2427 continue
2428 }
2429
2430 switch n.Class {
2431 default:
2432 varwrite = 1
2433 continue
2434
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002435 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002436 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002437 varwrite = 1
2438 continue
2439 }
2440
Russ Coxdc7b54b2015-02-17 22:13:49 -05002441 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002442 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002443 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002444 }
2445 }
2446 }
2447
2448 // The variables being written do not appear in n.
2449 // However, n might refer to computed addresses
2450 // that are being written.
2451
2452 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002453 if memwrite == 0 && varwrite == 0 {
2454 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002455 }
2456
2457 // If n does not refer to computed addresses
2458 // (that is, if n only refers to variables whose addresses
2459 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002460 if varexpr(n) {
2461 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002462 }
2463
2464 // Otherwise, both the writes and n refer to computed memory addresses.
2465 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002466 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002467}
2468
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002469// does the evaluation of n only refer to variables
2470// whose addresses have not been taken?
2471// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002472func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002473 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002474 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002475 }
2476
2477 switch n.Op {
2478 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002479 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002480
2481 case ONAME:
2482 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002483 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002484 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002485 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002486 }
2487 }
2488
Russ Coxdc7b54b2015-02-17 22:13:49 -05002489 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002490
2491 case OADD,
2492 OSUB,
2493 OOR,
2494 OXOR,
2495 OMUL,
2496 ODIV,
2497 OMOD,
2498 OLSH,
2499 ORSH,
2500 OAND,
2501 OANDNOT,
2502 OPLUS,
2503 OMINUS,
2504 OCOM,
2505 OPAREN,
2506 OANDAND,
2507 OOROR,
2508 ODOT, // but not ODOTPTR
2509 OCONV,
2510 OCONVNOP,
2511 OCONVIFACE,
2512 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002513 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002514 }
2515
2516 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002517 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002518}
2519
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002520// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002521func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002522 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002523 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002524 }
2525 switch r.Op {
2526 // match each right given left
2527 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002528 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002529
2530 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002531 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002532 }
2533
Russ Coxdc7b54b2015-02-17 22:13:49 -05002534 if vmatch2(l, r.Left) {
2535 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002536 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002537 if vmatch2(l, r.Right) {
2538 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002539 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002540 for it := nodeSeqIterate(r.List); !it.Done(); it.Next() {
2541 if vmatch2(l, it.N()) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002542 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002543 }
2544 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002545 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002546}
2547
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002548// is any name mentioned in l also mentioned in r?
2549// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002550func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002551 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002552 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002553 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002554 }
2555 switch l.Op {
2556 case ONAME:
2557 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002558 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002559 break
2560
2561 // assignment to non-stack variable
2562 // must be delayed if right has function calls.
2563 default:
2564 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002565 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002566 }
2567 }
2568
2569 return vmatch2(l, r)
2570
2571 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002572 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002573 }
2574
Russ Coxdc7b54b2015-02-17 22:13:49 -05002575 if vmatch1(l.Left, r) {
2576 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002577 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002578 if vmatch1(l.Right, r) {
2579 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002580 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002581 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
2582 if vmatch1(it.N(), r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002583 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 }
2585 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002586 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002587}
2588
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002589// walk through argin parameters.
2590// generate and return code to allocate
2591// copies of escaped parameters to the heap.
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002592func paramstoheap(argin **Type, out int) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002593 var savet Iter
2594 var v *Node
2595 var as *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002596
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002597 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002598 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002599 v = t.Nname
2600 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
2601 v = nil
2602 }
2603
2604 // For precise stacks, the garbage collector assumes results
2605 // are always live, so zero them always.
2606 if out != 0 {
2607 // Defer might stop a panic and show the
2608 // return values as they exist at the time of panic.
2609 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002610 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002611 }
2612
Russ Coxdc7b54b2015-02-17 22:13:49 -05002613 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002614 continue
2615 }
2616
2617 // generate allocation & copying code
2618 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002619 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002620 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002621 if prealloc[v] == nil {
2622 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002623 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002624 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002625 if v.Class&^PHEAP != PPARAMOUT {
Russ Coxbd4fff62015-05-27 10:42:55 -04002626 as = Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002627 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002628 typecheck(&as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002629 as = applywritebarrier(as)
2630 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002631 }
2632 }
2633
2634 return nn
2635}
2636
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002637// walk through argout parameters copying back to stack
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002638func returnsfromheap(argin **Type) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002639 var savet Iter
2640 var v *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002641
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002642 var nn []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002643 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002644 v = t.Nname
2645 if v == nil || v.Class != PHEAP|PPARAMOUT {
2646 continue
2647 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002648 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002649 }
2650
2651 return nn
2652}
2653
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002654// take care of migrating any function in/out args
2655// between the stack and the heap. adds code to
2656// curfn's before and after lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002657func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002658 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002659 lineno = Curfn.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -05002660 nn := paramstoheap(getthis(Curfn.Type), 0)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002661 nn = append(nn, paramstoheap(getinarg(Curfn.Type), 0)...)
2662 nn = append(nn, paramstoheap(Getoutarg(Curfn.Type), 1)...)
2663 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002664 lineno = Curfn.Func.Endlineno
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002665 Curfn.Func.Exit.Append(returnsfromheap(Getoutarg(Curfn.Type))...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002666 lineno = lno
2667}
2668
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002669func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002670 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002671 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002672 }
2673
Russ Cox382b44e2015-02-23 16:07:24 -05002674 n := fn.Type.Intuple
Russ Cox8c195bd2015-02-13 14:40:36 -05002675
Russ Cox382b44e2015-02-23 16:07:24 -05002676 r := Nod(OCALL, fn, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002677 setNodeSeq(&r.List, va[:n])
Russ Cox8c195bd2015-02-13 14:40:36 -05002678 if fn.Type.Outtuple > 0 {
2679 typecheck(&r, Erv|Efnstruct)
2680 } else {
2681 typecheck(&r, Etop)
2682 }
2683 walkexpr(&r, init)
2684 r.Type = t
2685 return r
2686}
2687
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002688func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002689 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002690}
2691
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002692func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002693 return vmkcall(fn, t, init, args)
2694}
2695
2696func conv(n *Node, t *Type) *Node {
2697 if Eqtype(n.Type, t) {
2698 return n
2699 }
2700 n = Nod(OCONV, n, nil)
2701 n.Type = t
2702 typecheck(&n, Erv)
2703 return n
2704}
2705
2706func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002707 if t.Etype != TCHAN {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002708 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002709 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002710 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002711 switch n {
2712 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002713 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002714 case 1:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002715 substArgTypes(&fn, t.Type)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002716 case 2:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002717 substArgTypes(&fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002718 }
2719 return fn
2720}
2721
2722func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002723 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002724 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002725 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002726 fn := syslook(name)
2727 substArgTypes(&fn, t.Down, t.Type, t.Down, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002728 return fn
2729}
2730
2731func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002732 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002733 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002734 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002735 fn := syslook(name)
2736 substArgTypes(&fn, t.Down, t.Type, t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05002737 return fn
2738}
2739
2740func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002741 fn := syslook(name)
2742 substArgTypes(&fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002743 return fn
2744}
2745
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002746func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002747 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002748 c := nodeSeqLen(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002749
2750 if c < 2 {
2751 Yyerror("addstr count %d too small", c)
2752 }
2753
Russ Cox382b44e2015-02-23 16:07:24 -05002754 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002755 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002756 sz := int64(0)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002757 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2758 if it.N().Op == OLITERAL {
2759 sz += int64(len(it.N().Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002760 }
2761 }
2762
2763 // Don't allocate the buffer if the result won't fit.
2764 if sz < tmpstringbufsize {
2765 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002766 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002767
2768 buf = Nod(OADDR, temp(t), nil)
2769 }
2770 }
2771
2772 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002773 args := []*Node{buf}
Russ Cox8c195bd2015-02-13 14:40:36 -05002774
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002775 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2776 args = append(args, conv(it.N(), Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002777 }
2778
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002779 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002780 if c <= 5 {
2781 // small numbers of strings use direct runtime helpers.
2782 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002783 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002784 } else {
2785 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002786 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002787
Russ Cox382b44e2015-02-23 16:07:24 -05002788 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002789 t.Type = Types[TSTRING]
2790 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002791 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002792 if prealloc[n] != nil {
2793 prealloc[slice] = prealloc[n]
2794 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002795 setNodeSeq(&slice.List, args[1:]) // skip buf arg
2796 args = []*Node{buf}
2797 args = append(args, slice)
Russ Cox8c195bd2015-02-13 14:40:36 -05002798 slice.Esc = EscNone
2799 }
2800
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002801 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002802 r := Nod(OCALL, cat, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002803 setNodeSeq(&r.List, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002804 typecheck(&r, Erv)
2805 walkexpr(&r, init)
2806 r.Type = n.Type
2807
2808 return r
2809}
2810
2811// expand append(l1, l2...) to
2812// init {
2813// s := l1
2814// if n := len(l1) + len(l2) - cap(s); n > 0 {
Russ Cox32fddad2015-06-25 19:27:20 -04002815// s = growslice_n(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002816// }
2817// s = s[:len(l1)+len(l2)]
2818// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2819// }
2820// s
2821//
2822// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002823func appendslice(n *Node, init *Nodes) *Node {
2824 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002825
2826 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2827 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002828 // modifying here. Fix explicitly.
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002829 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
2830 *it.P() = cheapexpr(it.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002831 }
2832
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002833 l1 := nodeSeqFirst(n.List)
2834 l2 := nodeSeqSecond(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002835
Russ Cox382b44e2015-02-23 16:07:24 -05002836 s := temp(l1.Type) // var s []T
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002837 var l []*Node
2838 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002839
Russ Cox382b44e2015-02-23 16:07:24 -05002840 nt := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05002841
Russ Cox382b44e2015-02-23 16:07:24 -05002842 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002843
2844 // n := len(s) + len(l2) - cap(s)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002845 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 -05002846
Russ Cox66be1482015-05-26 21:30:20 -04002847 nif.Left = Nod(OGT, nt, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002848
Russ Cox32fddad2015-06-25 19:27:20 -04002849 // instantiate growslice_n(Type*, []any, int) []any
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002850 fn := syslook("growslice_n") // growslice_n(<type>, old []T, n int64) (ret []T)
2851 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002852
Russ Cox32fddad2015-06-25 19:27:20 -04002853 // s = growslice_n(T, s, n)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08002854 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 -05002855
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002856 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002857
2858 if haspointers(l1.Type.Type) {
2859 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002860 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 -05002861
2862 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002863 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002864 fn := syslook("typedslicecopy")
2865 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002866 var ln Nodes
2867 ln.Set(l)
2868 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Type), nptr1, nptr2)
2869 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002870 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002871 // rely on runtime to instrument copy.
2872 // copy(s[len(l1):len(l1)+len(l2)], l2)
Russ Cox382b44e2015-02-23 16:07:24 -05002873 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 -05002874
2875 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002876 nptr2 := l2
2877 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002878 if l2.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002879 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002880 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002881 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002882 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002883 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002884 var ln Nodes
2885 ln.Set(l)
2886 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
2887 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002888 } else {
2889 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002890 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002891
Russ Coxdc7b54b2015-02-17 22:13:49 -05002892 nptr1.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -05002893 nptr1 = Nod(OADDR, nptr1, nil)
2894
Russ Cox382b44e2015-02-23 16:07:24 -05002895 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002896
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002897 fn := syslook("memmove")
2898 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002899
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002900 var ln Nodes
2901 ln.Set(l)
2902 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002903
2904 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002905 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2906 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002907 }
2908
2909 // s = s[:len(l1)+len(l2)]
2910 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
2911
2912 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
2913 nt.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002914 l = append(l, Nod(OAS, s, nt))
Russ Cox8c195bd2015-02-13 14:40:36 -05002915
2916 typechecklist(l, Etop)
2917 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002918 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002919 return s
2920}
2921
Russ Cox85520472015-05-06 12:34:30 -04002922// Rewrite append(src, x, y, z) so that any side effects in
2923// x, y, z (including runtime panics) are evaluated in
2924// initialization statements before the append.
2925// For normal code generation, stop there and leave the
2926// rest to cgen_append.
2927//
2928// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002929//
2930// init {
2931// s := src
2932// const argc = len(args) - 1
2933// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002934// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002935// }
2936// n := len(s)
2937// s = s[:n+argc]
2938// s[n] = a
2939// s[n+1] = b
2940// ...
2941// }
2942// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002943func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor2a68c6c2016-03-07 09:36:24 -08002944 if !samesafeexpr(dst, nodeSeqFirst(n.List)) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002945 it := nodeSeqIterate(n.List)
2946 *it.P() = safeexpr(it.N(), init)
2947 walkexpr(it.P(), init)
Russ Cox85520472015-05-06 12:34:30 -04002948 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002949 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002950
2951 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2952 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002953 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002954 // Using cheapexpr also makes sure that the evaluation
2955 // of all arguments (and especially any panics) happen
2956 // before we begin to modify the slice in a visible way.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002957 it := nodeSeqIterate(n.List)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002958 it.Next()
2959 for ; !it.Done(); it.Next() {
2960 *it.P() = cheapexpr(it.N(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002961 }
2962
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002963 nsrc := nodeSeqFirst(n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05002964
2965 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002966 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002967 nsrc.Type = nsrc.Type.Type.Type
2968 }
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002969 argc := nodeSeqLen(n.List) - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002970 if argc < 1 {
2971 return nsrc
2972 }
2973
Russ Cox85520472015-05-06 12:34:30 -04002974 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002975 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002976 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002977 return n
2978 }
2979
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002980 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002981
Russ Cox382b44e2015-02-23 16:07:24 -05002982 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002983 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002984
Russ Cox382b44e2015-02-23 16:07:24 -05002985 na := Nodintconst(int64(argc)) // const argc
2986 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002987 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002988
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002989 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
2990 substArgTypes(&fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002991
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08002992 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 -05002993
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002994 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05002995
Russ Cox382b44e2015-02-23 16:07:24 -05002996 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002997 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05002998
2999 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
3000 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003001 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05003002
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003003 it = nodeSeqIterate(n.List)
3004 it.Next()
3005 for ; !it.Done(); it.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003006 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003007 nx.Bounded = true
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003008 l = append(l, Nod(OAS, nx, it.N())) // s[n] = arg
Ian Lance Taylor55c65d42016-03-04 13:16:48 -08003009 if it.Len() > 1 {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003010 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003011 }
3012 }
3013
3014 typechecklist(l, Etop)
3015 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003016 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003017 return ns
3018}
3019
3020// Lower copy(a, b) to a memmove call or a runtime call.
3021//
3022// init {
3023// n := len(a)
3024// if n > len(b) { n = len(b) }
3025// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3026// }
3027// n;
3028//
3029// Also works if b is a string.
3030//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003031func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003032 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05003033 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003034 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
3035 }
3036
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003037 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003038 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003039 if n.Right.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003040 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003041 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003042 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003043 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003044 substArgTypes(&fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003045 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3046 }
3047
3048 walkexpr(&n.Left, init)
3049 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003050 nl := temp(n.Left.Type)
3051 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003052 var l []*Node
3053 l = append(l, Nod(OAS, nl, n.Left))
3054 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003055
Russ Cox382b44e2015-02-23 16:07:24 -05003056 nfrm := Nod(OSPTR, nr, nil)
3057 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003058
Russ Cox382b44e2015-02-23 16:07:24 -05003059 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003060
3061 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003062 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003063
3064 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003065 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003066
Russ Cox66be1482015-05-26 21:30:20 -04003067 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003068 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003069 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003070
3071 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003072 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003073
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003074 substArgTypes(&fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003075 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003076 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003077 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003078 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003079
3080 typechecklist(l, Etop)
3081 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003082 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003083 return nlen
3084}
3085
Russ Cox8c195bd2015-02-13 14:40:36 -05003086func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003087 // Should only arrive here with large memory or
3088 // a struct/array containing a non-memory field/element.
3089 // Small memory is handled inline, and single non-memory
3090 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003091 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003092
3093 if a != AMEM && a != -1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003094 Fatalf("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003095 }
3096
3097 if a == AMEM {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003098 n := syslook("memequal")
3099 substArgTypes(&n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003100 *needsize = 1
3101 return n
3102 }
3103
Russ Cox382b44e2015-02-23 16:07:24 -05003104 sym := typesymprefix(".eq", t)
3105 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003106 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003107 ntype := Nod(OTFUNC, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003108 appendNodeSeqNode(&ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3109 appendNodeSeqNode(&ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3110 appendNodeSeqNode(&ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003111 typecheck(&ntype, Etype)
3112 n.Type = ntype.Type
3113 *needsize = 0
3114 return n
3115}
3116
3117func countfield(t *Type) int {
Russ Cox382b44e2015-02-23 16:07:24 -05003118 n := 0
3119 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003120 n++
3121 }
3122 return n
3123}
3124
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003125func walkcompare(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003126 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003127
3128 // Given interface value l and concrete value r, rewrite
3129 // l == r
3130 // to
3131 // x, ok := l.(type(r)); ok && x == r
3132 // Handle != similarly.
3133 // This avoids the allocation that would be required
3134 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003135 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003136
Russ Cox175929b2015-03-02 14:22:05 -05003137 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003138 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003139 l = n.Left
3140 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003141 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003142 l = n.Right
3143 r = n.Left
3144 }
3145
3146 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003147 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003148 if haspointers(r.Type) {
3149 a := Nod(OAS, x, nil)
3150 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003151 init.Append(a)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003152 }
Russ Cox382b44e2015-02-23 16:07:24 -05003153 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003154
3155 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003156 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003157
3158 a.Type = r.Type
3159
3160 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003161 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003162
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003163 appendNodeSeqNode(&expr.List, x)
3164 appendNodeSeqNode(&expr.List, ok)
3165 appendNodeSeqNode(&expr.Rlist, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003166 typecheck(&expr, Etop)
3167 walkexpr(&expr, init)
3168
3169 if n.Op == OEQ {
3170 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3171 } else {
3172 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3173 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003174 init.Append(expr)
Russ Cox44928112015-03-02 20:34:22 -05003175 finishcompare(np, n, r, init)
3176 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003177 }
3178
3179 // Must be comparison of array or struct.
3180 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003181 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003182
3183 switch t.Etype {
3184 default:
3185 return
3186
3187 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003188 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003189 return
3190 }
3191
3192 case TSTRUCT:
3193 break
3194 }
3195
Russ Cox44928112015-03-02 20:34:22 -05003196 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003197 for cmpl != nil && cmpl.Op == OCONVNOP {
3198 cmpl = cmpl.Left
3199 }
Russ Cox44928112015-03-02 20:34:22 -05003200 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 for cmpr != nil && cmpr.Op == OCONVNOP {
3202 cmpr = cmpr.Left
3203 }
3204
Russ Coxdc7b54b2015-02-17 22:13:49 -05003205 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003206 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003207 }
3208
3209 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003210 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003211 a.Right.Etype = 1 // addr does not escape
3212 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003213 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003214
3215 r = temp(Ptrto(t))
3216 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3217 a.Right.Etype = 1 // addr does not escape
3218 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003219 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003220
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003221 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003222 if n.Op == ONE {
3223 andor = OOROR
3224 }
3225
Russ Cox44928112015-03-02 20:34:22 -05003226 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003227 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003228 // Four or fewer elements of a basic type.
3229 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003230 var li *Node
3231 var ri *Node
3232 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003233 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3234 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003235 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003236 if expr == nil {
3237 expr = a
3238 } else {
3239 expr = Nod(andor, expr, a)
3240 }
3241 }
3242
3243 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003244 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003245 }
Russ Cox44928112015-03-02 20:34:22 -05003246 finishcompare(np, n, expr, init)
3247 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003248 }
3249
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003250 if t.Etype == TARRAY {
3251 // Zero- or single-element array, of any type.
3252 switch t.Bound {
3253 case 0:
3254 finishcompare(np, n, Nodbool(n.Op == OEQ), init)
3255 return
3256 case 1:
3257 l0 := Nod(OINDEX, l, Nodintconst(0))
3258 r0 := Nod(OINDEX, r, Nodintconst(0))
3259 a := Nod(n.Op, l0, r0)
3260 finishcompare(np, n, a, init)
3261 return
3262 }
3263 }
3264
Russ Cox8c195bd2015-02-13 14:40:36 -05003265 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3266 // Struct of four or fewer fields.
3267 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003268 var li *Node
3269 var ri *Node
3270 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05003271 if isblanksym(t1.Sym) {
3272 continue
3273 }
3274 li = Nod(OXDOT, l, newname(t1.Sym))
3275 ri = Nod(OXDOT, r, newname(t1.Sym))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003276 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003277 if expr == nil {
3278 expr = a
3279 } else {
3280 expr = Nod(andor, expr, a)
3281 }
3282 }
3283
3284 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003285 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003286 }
Russ Cox44928112015-03-02 20:34:22 -05003287 finishcompare(np, n, expr, init)
3288 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003289 }
3290
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003291 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003292 var needsize int
3293 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003294
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003295 appendNodeSeqNode(&call.List, l)
3296 appendNodeSeqNode(&call.List, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003297 if needsize != 0 {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003298 appendNodeSeqNode(&call.List, Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003299 }
3300 r = call
3301 if n.Op != OEQ {
3302 r = Nod(ONOT, r, nil)
3303 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003304
Russ Cox44928112015-03-02 20:34:22 -05003305 finishcompare(np, n, r, init)
3306 return
3307}
3308
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003309func finishcompare(np **Node, n, r *Node, init *Nodes) {
Russ Cox44928112015-03-02 20:34:22 -05003310 // Using np here to avoid passing &r to typecheck.
3311 *np = r
3312 typecheck(np, Erv)
3313 walkexpr(np, init)
3314 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003315 if r.Type != n.Type {
3316 r = Nod(OCONVNOP, r, nil)
3317 r.Type = n.Type
3318 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003319 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003320 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003321}
3322
Russ Coxdc7b54b2015-02-17 22:13:49 -05003323func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003324 var ar *Node
3325 var br *Node
3326 for a != nil && b != nil && a.Op == b.Op {
3327 switch a.Op {
3328 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003329 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003330
3331 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003332 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003333
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003334 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003335 ar = a.Right
3336 br = b.Right
3337 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003338 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003339 }
3340
3341 case OINDEX:
3342 ar = a.Right
3343 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003344 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003345 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003346 }
3347 }
3348
3349 a = a.Left
3350 b = b.Left
3351 }
3352
Russ Coxdc7b54b2015-02-17 22:13:49 -05003353 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003354}
3355
3356func walkrotate(np **Node) {
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003357 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003358 return
3359 }
3360
Russ Cox382b44e2015-02-23 16:07:24 -05003361 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003362
3363 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003364 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003365
Russ Cox382b44e2015-02-23 16:07:24 -05003366 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003367 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 -05003368 return
3369 }
3370
3371 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003372 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003373 return
3374 }
3375
3376 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003377 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003378
Russ Coxdc7b54b2015-02-17 22:13:49 -05003379 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003380 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003381 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003382 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003383 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003384 // Rewrite left shift half to left rotate.
3385 if l.Op == OLSH {
3386 n = l
3387 } else {
3388 n = r
3389 }
3390 n.Op = OLROT
3391
3392 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003393 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003394
3395 if s == 0 || s == w {
3396 n = n.Left
3397 }
3398
3399 *np = n
3400 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003401 }
3402 }
3403 return
3404 }
3405
3406 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3407 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003408}
3409
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003410// walkmul rewrites integer multiplication by powers of two as shifts.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003411func walkmul(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003412 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003413 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003414 return
3415 }
3416
Russ Cox382b44e2015-02-23 16:07:24 -05003417 var nr *Node
3418 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003419 if n.Right.Op == OLITERAL {
3420 nl = n.Left
3421 nr = n.Right
3422 } else if n.Left.Op == OLITERAL {
3423 nl = n.Right
3424 nr = n.Left
3425 } else {
3426 return
3427 }
3428
Russ Cox382b44e2015-02-23 16:07:24 -05003429 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003430
3431 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003432 var pow int
3433 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003434 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003435 cheapexpr(nl, init)
3436 Nodconst(n, n.Type, 0)
3437 goto ret
3438 }
3439
3440 // nr is a constant.
3441 pow = powtwo(nr)
3442
3443 if pow < 0 {
3444 return
3445 }
3446 if pow >= 1000 {
3447 // negative power of 2, like -16
3448 neg = 1
3449
3450 pow -= 1000
3451 }
3452
3453 w = int(nl.Type.Width * 8)
3454 if pow+1 >= w { // too big, shouldn't happen
3455 return
3456 }
3457
3458 nl = cheapexpr(nl, init)
3459
3460 if pow == 0 {
3461 // x*1 is x
3462 n = nl
3463
3464 goto ret
3465 }
3466
3467 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3468
3469ret:
3470 if neg != 0 {
3471 n = Nod(OMINUS, n, nil)
3472 }
3473
3474 typecheck(&n, Erv)
3475 walkexpr(&n, init)
3476 *np = n
3477}
3478
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003479// walkdiv rewrites division by a constant as less expensive
3480// operations.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003481func walkdiv(np **Node, init *Nodes) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003482 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003483
3484 // TODO(minux)
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003485 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003486 return
3487 }
3488
Russ Cox382b44e2015-02-23 16:07:24 -05003489 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003490 if n.Right.Op != OLITERAL {
3491 return
3492 }
3493
3494 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003495 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003496
Russ Cox382b44e2015-02-23 16:07:24 -05003497 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003498
3499 // special cases of mod/div
3500 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003501 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003502
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003503 s := 0 // 1 if nr is negative.
3504 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003505 if pow >= 1000 {
3506 // negative power of 2
3507 s = 1
3508
3509 pow -= 1000
3510 }
3511
3512 if pow+1 >= w {
3513 // divisor too large.
3514 return
3515 }
3516
3517 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003518 // try to do division by multiply by (2^w)/d
3519 // see hacker's delight chapter 10
3520 // TODO: support 64-bit magic multiply here.
3521 var m Magic
3522 m.W = w
3523
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003524 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003525 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003526 Smagic(&m)
3527 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003528 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003529 Umagic(&m)
3530 }
3531
3532 if m.Bad != 0 {
3533 return
3534 }
3535
3536 // We have a quick division method so use it
3537 // for modulo too.
3538 if n.Op == OMOD {
3539 // rewrite as A%B = A - (A/B*B).
3540 n1 := Nod(ODIV, nl, nr)
3541
3542 n2 := Nod(OMUL, n1, nr)
3543 n = Nod(OSUB, nl, n2)
3544 goto ret
3545 }
3546
3547 switch Simtype[nl.Type.Etype] {
3548 default:
3549 return
3550
3551 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003552 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003553 nc := Nod(OXXX, nil, nil)
3554
3555 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003556 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003557 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003558 if m.Ua != 0 {
3559 // Select a Go type with (at least) twice the width.
3560 var twide *Type
3561 switch Simtype[nl.Type.Etype] {
3562 default:
3563 return
3564
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003565 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003566 twide = Types[TUINT32]
3567
3568 case TUINT32:
3569 twide = Types[TUINT64]
3570
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003571 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003572 twide = Types[TINT32]
3573
3574 case TINT32:
3575 twide = Types[TINT64]
3576 }
3577
3578 // add numerator (might overflow).
3579 // n2 = (n1 + nl)
3580 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3581
3582 // shift by m.s
3583 nc := Nod(OXXX, nil, nil)
3584
3585 Nodconst(nc, Types[TUINT], int64(m.S))
3586 n = conv(Nod(ORSH, n2, nc), nl.Type)
3587 } else {
3588 // n = n1 >> m.s
3589 nc := Nod(OXXX, nil, nil)
3590
3591 Nodconst(nc, Types[TUINT], int64(m.S))
3592 n = Nod(ORSH, n1, nc)
3593 }
3594
3595 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003596 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003597 nc := Nod(OXXX, nil, nil)
3598
3599 Nodconst(nc, nl.Type, m.Sm)
Todd Neal765c0f32015-06-23 18:59:52 -05003600 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003601 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003602 if m.Sm < 0 {
3603 // add the numerator.
3604 n1 = Nod(OADD, n1, nl)
3605 }
3606
3607 // shift by m.s
3608 nc = Nod(OXXX, nil, nil)
3609
3610 Nodconst(nc, Types[TUINT], int64(m.S))
3611 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3612
3613 // add 1 iff n1 is negative.
3614 nc = Nod(OXXX, nil, nil)
3615
3616 Nodconst(nc, Types[TUINT], int64(w)-1)
3617 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3618 n = Nod(OSUB, n2, n3)
3619
3620 // apply sign.
3621 if m.Sd < 0 {
3622 n = Nod(OMINUS, n, nil)
3623 }
3624 }
3625
3626 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003627 }
3628
3629 switch pow {
3630 case 0:
3631 if n.Op == OMOD {
3632 // nl % 1 is zero.
3633 Nodconst(n, n.Type, 0)
3634 } else if s != 0 {
3635 // divide by -1
3636 n.Op = OMINUS
3637
3638 n.Right = nil
3639 } else {
3640 // divide by 1
3641 n = nl
3642 }
3643
3644 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003645 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003646 if n.Op == OMOD {
3647 // signed modulo 2^pow is like ANDing
3648 // with the last pow bits, but if nl < 0,
3649 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003650 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003651
3652 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003653 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003654 if pow == 1 {
3655 typecheck(&n1, Erv)
3656 n1 = cheapexpr(n1, init)
3657
3658 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003659 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003660
Russ Cox382b44e2015-02-23 16:07:24 -05003661 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003662 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003663 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003664 n = Nod(OADD, n3, n1)
3665 } else {
3666 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003667 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003668
3669 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003670 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003671 typecheck(&n2, Erv)
3672 n2 = cheapexpr(n2, init)
3673
Russ Cox382b44e2015-02-23 16:07:24 -05003674 n3 := Nod(OADD, nl, n2)
3675 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003676 n = Nod(OSUB, n4, n2)
3677 }
3678
3679 break
3680 } else {
3681 // arithmetic right shift does not give the correct rounding.
3682 // if nl >= 0, nl >> n == nl / nr
3683 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003684 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003685
3686 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003687 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003688 if pow == 1 {
3689 // nl+1 is nl-(-1)
3690 n.Left = Nod(OSUB, nl, n1)
3691 } else {
3692 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003693 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003694
3695 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003696 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003697 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3698 }
3699
3700 // n = (nl + 2^pow-1) >> pow
3701 n.Op = ORSH
3702
3703 nc = Nod(OXXX, nil, nil)
3704 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3705 n.Right = nc
3706 n.Typecheck = 0
3707 }
3708
3709 if s != 0 {
3710 n = Nod(OMINUS, n, nil)
3711 }
3712 break
3713 }
3714
Russ Cox382b44e2015-02-23 16:07:24 -05003715 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003716 if n.Op == OMOD {
3717 // n = nl & (nr-1)
3718 n.Op = OAND
3719
Russ Cox81d58102015-05-27 00:47:05 -04003720 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003721 } else {
3722 // n = nl >> pow
3723 n.Op = ORSH
3724
3725 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3726 }
3727
3728 n.Typecheck = 0
3729 n.Right = nc
3730 }
3731
3732 goto ret
3733
Russ Cox8c195bd2015-02-13 14:40:36 -05003734ret:
3735 typecheck(&n, Erv)
3736 walkexpr(&n, init)
3737 *np = n
3738}
3739
3740// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003741func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003742 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003743 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003744 }
3745
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003746 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003747 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003748
Russ Coxdc7b54b2015-02-17 22:13:49 -05003749 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003750 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003751 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003752 }
3753
3754 switch n.Op {
3755 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003756 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003757 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003758 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003759 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003760 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003761 }
3762
3763 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003764 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003765 }
3766
3767 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003768 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003769 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003770 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003771 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003772 }
3773 }
3774
3775 case ODIV:
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 for bits > 0 && v >= 2 {
3779 bits--
3780 v >>= 1
3781 }
3782 }
3783
3784 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003785 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003786 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003787 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003788 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003789 }
3790 bits -= int32(v)
3791 }
3792 }
3793
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003794 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003795 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003796 }
3797
Russ Coxdc7b54b2015-02-17 22:13:49 -05003798 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003799}
3800
3801func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003802 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003803 return
3804 }
3805
3806 switch n.Op {
3807 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08003808 Fatalf("usefield %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003809
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003810 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 break
3812 }
Keith Randall71d13a82016-03-02 20:54:41 -08003813 if n.Right == nil {
3814 // No field name. This DOTPTR was built by the compiler for access
3815 // to runtime data structures. Ignore.
3816 return
3817 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003818
Russ Cox496ad0a2015-05-26 21:49:31 -04003819 t := n.Left.Type
3820 if Isptr[t.Etype] {
3821 t = t.Type
3822 }
Russ Coxf68d1df2015-08-17 21:38:46 -04003823 field := dotField[typeSym{t.Orig, n.Right.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003824 if field == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003825 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003826 }
Russ Coxbed1f902015-03-02 16:03:26 -05003827 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003828 return
3829 }
3830
3831 // dedup on list
3832 if field.Lastfn == Curfn {
3833 return
3834 }
3835 field.Lastfn = Curfn
3836 field.Outer = n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003837 if Isptr[field.Outer.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003838 field.Outer = field.Outer.Type
3839 }
3840 if field.Outer.Sym == nil {
3841 Yyerror("tracked field must be in named struct type")
3842 }
3843 if !exportname(field.Sym.Name) {
3844 Yyerror("tracked field must be exported (upper case)")
3845 }
3846
Russ Cox496ad0a2015-05-26 21:49:31 -04003847 Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
Russ Cox8c195bd2015-02-13 14:40:36 -05003848}
3849
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003850func candiscardlist(l Nodes) bool {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003851 for it := nodeSeqIterate(l); !it.Done(); it.Next() {
3852 if !candiscard(it.N()) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003853 return false
3854 }
3855 }
3856 return true
3857}
3858
Russ Coxdc7b54b2015-02-17 22:13:49 -05003859func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003860 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003861 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003862 }
3863
3864 switch n.Op {
3865 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003866 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003867
3868 // Discardable as long as the subpieces are.
3869 case ONAME,
3870 ONONAME,
3871 OTYPE,
3872 OPACK,
3873 OLITERAL,
3874 OADD,
3875 OSUB,
3876 OOR,
3877 OXOR,
3878 OADDSTR,
3879 OADDR,
3880 OANDAND,
3881 OARRAYBYTESTR,
3882 OARRAYRUNESTR,
3883 OSTRARRAYBYTE,
3884 OSTRARRAYRUNE,
3885 OCAP,
3886 OCMPIFACE,
3887 OCMPSTR,
3888 OCOMPLIT,
3889 OMAPLIT,
3890 OSTRUCTLIT,
3891 OARRAYLIT,
3892 OPTRLIT,
3893 OCONV,
3894 OCONVIFACE,
3895 OCONVNOP,
3896 ODOT,
3897 OEQ,
3898 ONE,
3899 OLT,
3900 OLE,
3901 OGT,
3902 OGE,
3903 OKEY,
3904 OLEN,
3905 OMUL,
3906 OLSH,
3907 ORSH,
3908 OAND,
3909 OANDNOT,
3910 ONEW,
3911 ONOT,
3912 OCOM,
3913 OPLUS,
3914 OMINUS,
3915 OOROR,
3916 OPAREN,
3917 ORUNESTR,
3918 OREAL,
3919 OIMAG,
3920 OCOMPLEX:
3921 break
3922
3923 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003924 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003925 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003926 break
3927 }
Russ Cox81d58102015-05-27 00:47:05 -04003928 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003929 break
3930 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003931 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003932
3933 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003934 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003935 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003936 break
3937 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003938 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003939
3940 // Difficult to tell what sizes are okay.
3941 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003942 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003943 }
3944
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003945 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 -05003946 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003947 }
3948
Russ Coxdc7b54b2015-02-17 22:13:49 -05003949 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003950}
3951
3952// rewrite
3953// print(x, y, z)
3954// into
3955// func(a1, a2, a3) {
3956// print(a1, a2, a3)
3957// }(x, y, z)
3958// and same for println.
3959
3960var walkprintfunc_prgen int
3961
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003962func walkprintfunc(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003963 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003964
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003965 if nodeSeqLen(n.Ninit) != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003966 walkstmtlist(n.Ninit.Slice())
3967 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05003968 }
3969
Russ Cox382b44e2015-02-23 16:07:24 -05003970 t := Nod(OTFUNC, nil, nil)
3971 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003972 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05003973 var a *Node
3974 var buf string
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003975 for it := nodeSeqIterate(n.List); !it.Done(); it.Next() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003976 buf = fmt.Sprintf("a%d", num)
3977 num++
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003978 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(it.N().Type))
3979 appendNodeSeqNode(&t.List, a)
3980 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05003981 }
3982
Russ Cox382b44e2015-02-23 16:07:24 -05003983 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003984 walkprintfunc_prgen++
3985 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003986 fn.Func.Nname = newname(Lookup(buf))
3987 fn.Func.Nname.Name.Defn = fn
3988 fn.Func.Nname.Name.Param.Ntype = t
3989 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003990
Russ Cox382b44e2015-02-23 16:07:24 -05003991 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05003992 Curfn = nil
3993 funchdr(fn)
3994
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003995 a = Nod(n.Op, nil, nil)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003996 setNodeSeq(&a.List, printargs)
Russ Cox8c195bd2015-02-13 14:40:36 -05003997 typecheck(&a, Etop)
3998 walkstmt(&a)
3999
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08004000 fn.Nbody.Set([]*Node{a})
Russ Cox8c195bd2015-02-13 14:40:36 -05004001
4002 funcbody(fn)
4003
4004 typecheck(&fn, Etop)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08004005 typechecklist(fn.Nbody.Slice(), Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05004006 xtop = list(xtop, fn)
4007 Curfn = oldfn
4008
4009 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004010 a.Left = fn.Func.Nname
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004011 setNodeSeq(&a.List, n.List)
Russ Cox8c195bd2015-02-13 14:40:36 -05004012 typecheck(&a, Etop)
4013 walkexpr(&a, init)
4014 *np = a
4015}