blob: 4e3079fd7e9f59ca1a6a7a7fe7a3047d7ce9b440 [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 Taylor38921b32016-03-08 15:10:26 -0800122 for _, arg = range callfunc.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500123 if arg.Op != OAS {
124 Yyerror("call arg not assignment")
125 }
126 lhs = arg.Left
127 if lhs.Op == ONAME {
128 // This is a temporary introduced by reorder1.
129 // The real store to the stack appears later in the arg list.
130 continue
131 }
132
133 if lhs.Op != OINDREG {
134 Yyerror("call argument store does not use OINDREG")
135 }
136
137 // can't really check this in machine-indep code.
138 //if(lhs->val.u.reg != D_SP)
139 // yyerror("call arg assign not indreg(SP)");
140 lhs.Xoffset += int64(adjust)
141 }
142}
143
144func walkstmt(np **Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500145 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500146 if n == nil {
147 return
148 }
149 if n.Dodata == 2 { // don't walk, generated by anylit.
150 return
151 }
152
153 setlineno(n)
154
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800155 walkstmtlist(n.Ninit.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500156
157 switch n.Op {
158 default:
159 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400160 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500161 } else {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -0800162 Yyerror("%v is not a top level statement", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500163 }
164 Dump("nottop", n)
165
166 case OAS,
167 OASOP,
168 OAS2,
169 OAS2DOTTYPE,
170 OAS2RECV,
171 OAS2FUNC,
172 OAS2MAPR,
173 OCLOSE,
174 OCOPY,
175 OCALLMETH,
176 OCALLINTER,
177 OCALL,
178 OCALLFUNC,
179 ODELETE,
180 OSEND,
181 OPRINT,
182 OPRINTN,
183 OPANIC,
184 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400185 ORECOVER,
186 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500187 if n.Typecheck == 0 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700188 Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500189 }
Russ Cox382b44e2015-02-23 16:07:24 -0500190 init := n.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800191 n.Ninit.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500192 walkexpr(&n, &init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800193 addinit(&n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500194 if (*np).Op == OCOPY && n.Op == OCONVNOP {
195 n.Op = OEMPTY // don't leave plain values as statements.
196 }
197
198 // special case for a receive where we throw away
199 // the value received.
200 case ORECV:
201 if n.Typecheck == 0 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700202 Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500203 }
Russ Cox382b44e2015-02-23 16:07:24 -0500204 init := n.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800205 n.Ninit.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500206
207 walkexpr(&n.Left, &init)
208 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
209 walkexpr(&n, &init)
210
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800211 addinit(&n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500212
213 case OBREAK,
214 ODCL,
215 OCONTINUE,
216 OFALL,
217 OGOTO,
218 OLABEL,
219 ODCLCONST,
220 ODCLTYPE,
221 OCHECKNIL,
Russ Cox1ac637c2016-01-13 00:46:28 -0500222 OVARKILL,
223 OVARLIVE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500224 break
225
226 case OBLOCK:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800227 walkstmtlist(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500228
229 case OXCASE:
230 Yyerror("case statement out of place")
231 n.Op = OCASE
232 fallthrough
233
234 case OCASE:
235 walkstmt(&n.Right)
236
237 case ODEFER:
HĂ¥vard Haugen25946642015-09-07 22:19:30 +0200238 hasdefer = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500239 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700240 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500241 walkprintfunc(&n.Left, &n.Ninit)
242
243 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700244 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500245
246 default:
247 walkexpr(&n.Left, &n.Ninit)
248 }
249
250 // make room for size & fn arguments.
251 adjustargs(n, 2*Widthptr)
252
253 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400254 if n.Left != nil {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800255 walkstmtlist(n.Left.Ninit.Slice())
Russ Cox66be1482015-05-26 21:30:20 -0400256 init := n.Left.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800257 n.Left.Ninit.Set(nil)
Russ Cox66be1482015-05-26 21:30:20 -0400258 walkexpr(&n.Left, &init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800259 addinit(&n.Left, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500260 }
261
Russ Coxffef1802015-05-22 01:16:52 -0400262 walkstmt(&n.Right)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800263 walkstmtlist(n.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500264
265 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400266 walkexpr(&n.Left, &n.Ninit)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800267 walkstmtlist(n.Nbody.Slice())
268 walkstmtlist(n.Rlist.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500269
270 case OPROC:
271 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700272 case OPRINT, OPRINTN:
Russ Cox8c195bd2015-02-13 14:40:36 -0500273 walkprintfunc(&n.Left, &n.Ninit)
274
275 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700276 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500277
278 default:
279 walkexpr(&n.Left, &n.Ninit)
280 }
281
282 // make room for size & fn arguments.
283 adjustargs(n, 2*Widthptr)
284
285 case ORETURN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800286 walkexprlist(n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800287 if n.List.Len() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500288 break
289 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800290 if (Curfn.Type.Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500291 // assign to the function out parameters,
292 // so that reorder3 can fix up conflicts
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800293 var rl []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500294
Robert Griesemercd7d7382015-10-26 14:57:36 -0700295 var cl Class
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800296 for _, ln := range Curfn.Func.Dcl {
297 cl = ln.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500298 if cl == PAUTO {
299 break
300 }
301 if cl == PPARAMOUT {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800302 rl = append(rl, ln)
Russ Cox8c195bd2015-02-13 14:40:36 -0500303 }
304 }
305
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800306 if got, want := n.List.Len(), len(rl); got != want {
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800307 // order should have rewritten multi-value function calls
308 // with explicit OAS2FUNC nodes.
309 Fatalf("expected %v return arguments, have %v", want, got)
310 }
311
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800312 if samelist(rl, n.List.Slice()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500313 // special return in disguise
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800314 n.List.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500315
316 break
317 }
318
Russ Cox8c195bd2015-02-13 14:40:36 -0500319 // move function calls out, to make reorder3's job easier.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800320 walkexprlistsafe(n.List.Slice(), &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500321
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800322 ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800323 n.List.Set(reorder3(ll))
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800324 ls := n.List.Slice()
325 for i, n := range ls {
326 ls[i] = applywritebarrier(n)
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800327 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500328 break
329 }
330
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800331 ll := ascompatte(n.Op, nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800332 n.List.Set(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 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700352 Fatalf("walkstmt ended up with name: %v", Nconv(n, 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 Taylor38921b32016-03-08 15:10:26 -0800468 if n.Ninit.Len() != 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 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700487 Fatalf("missed typecheck: %v\n", Nconv(n, 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)
Matthew Dempsky63142022016-03-15 13:06:58 -0700494 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, FmtShort|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 Taylor38921b32016-03-08 15:10:26 -0800575 n.Left = n.List.First()
576 n.Right = n.List.Second()
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:
David Crawshawcc158402016-03-10 16:15:26 -0500635 usemethod(n)
Russ Cox382b44e2015-02-23 16:07:24 -0500636 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800637 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200638 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500639 }
640 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800641 walkexprlist(n.List.Slice(), init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800642 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800643 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500644
645 case OCALLFUNC:
646 if n.Left.Op == OCLOSURE {
647 // Transform direct call of a closure to call of a normal function.
648 // transformclosure already did all preparation work.
649
David Chase731dcda2015-07-23 14:17:07 -0400650 // Prepend captured variables to argument list.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800651 n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500652
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800653 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500654
655 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400656 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500657
658 // Update type of OCALLFUNC node.
659 // Output arguments had not changed, but their offsets could.
660 if n.Left.Type.Outtuple == 1 {
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -0700661 n.Type = n.Left.Type.Results().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500662 } else {
Matthew Dempskydb506fe2016-03-08 16:31:28 -0800663 n.Type = n.Left.Type.Results()
Russ Cox8c195bd2015-02-13 14:40:36 -0500664 }
665 }
666
Russ Cox382b44e2015-02-23 16:07:24 -0500667 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800668 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200669 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500670 }
671
672 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800673 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500674
Russ Cox92dba0d2015-04-01 16:02:34 -0400675 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
676 switch Thearch.Thechar {
Lynn Bogerb4b2ddb2016-02-16 12:24:12 -0600677 case '5', '6', '7', '9':
Russ Cox92dba0d2015-04-01 16:02:34 -0400678 n.Op = OSQRT
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800679 n.Left = n.List.First()
680 n.List.Set(nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200681 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400682 }
683 }
684
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800685 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800686 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500687
688 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500689 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800690 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200691 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500692 }
693 walkexpr(&n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800694 walkexprlist(n.List.Slice(), init)
Matthew Dempskyf91b8322016-03-09 20:54:59 -0800695 ll := ascompatte(n.Op, n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800696 lr := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800697 ll = append(ll, lr...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500698 n.Left.Left = nil
699 ullmancalc(n.Left)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800700 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500701
702 case OAS:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800703 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500704
705 walkexpr(&n.Left, init)
706 n.Left = safeexpr(n.Left, init)
707
Russ Coxdc7b54b2015-02-17 22:13:49 -0500708 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200709 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500710 }
711
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700712 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200713 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500714 }
715
716 switch n.Right.Op {
717 default:
718 walkexpr(&n.Right, init)
719
Russ Cox8c195bd2015-02-13 14:40:36 -0500720 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400721 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
722 // It needs to be removed in all three places.
723 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700724 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400725 // handled directly during cgen
726 walkexpr(&n.Right, init)
727 break
728 }
729
David Chaseffe7fbf2015-03-27 12:34:45 -0400730 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400731 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500732 walkexpr(&n.Right.Left, init)
733
Russ Cox382b44e2015-02-23 16:07:24 -0500734 n1 := Nod(OADDR, n.Left, nil)
735 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500736
Russ Cox4224d812015-03-20 00:06:10 -0400737 if Debug_typeassert > 0 {
738 Warn("type assertion not inlined")
739 }
740
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800741 fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
742 substArgTypes(&fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500743
744 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
745 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200746 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500747
Russ Cox8c195bd2015-02-13 14:40:36 -0500748 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400749 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400750 // orderstmt made sure x is addressable.
Russ Cox8c195bd2015-02-13 14:40:36 -0500751 walkexpr(&n.Right.Left, init)
752
Russ Cox382b44e2015-02-23 16:07:24 -0500753 n1 := Nod(OADDR, n.Left, nil)
754 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500755 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
756 walkexpr(&n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200757 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400758
759 case OAPPEND:
760 // x = append(...)
761 r := n.Right
762 if r.Isddd {
763 r = appendslice(r, init) // also works for append(slice, string).
764 } else {
765 r = walkappend(r, init, n)
766 }
767 n.Right = r
768 if r.Op == OAPPEND {
769 // Left in place for back end.
770 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200771 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400772 }
773 // Otherwise, lowered for race detector.
774 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500775 }
776
777 if n.Left != nil && n.Right != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500778 r := convas(Nod(OAS, n.Left, n.Right), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500779 r.Dodata = n.Dodata
780 n = r
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800781 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500782 }
783
Russ Cox8c195bd2015-02-13 14:40:36 -0500784 case OAS2:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800785 init.AppendNodes(&n.Ninit)
786 walkexprlistsafe(n.List.Slice(), init)
787 walkexprlistsafe(n.Rlist.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800788 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500789 ll = reorder3(ll)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800790 for i, n := range ll {
791 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500792 }
793 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500794
795 // a,b,... = fn()
796 case OAS2FUNC:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800797 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500798
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800799 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800800 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500801 walkexpr(&r, init)
802
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800803 ll := ascompatet(n.Op, n.List, r.Type, 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800804 for i, n := range ll {
805 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500806 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800807 n = liststmt(append([]*Node{r}, ll...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500808
809 // x, y = <-c
810 // orderstmt made sure x is addressable.
811 case OAS2RECV:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800812 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500813
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800814 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800815 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500816 walkexpr(&r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500817 var n1 *Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800818 if isblank(n.List.First()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500819 n1 = nodnil()
820 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800821 n1 = Nod(OADDR, n.List.First(), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500822 }
823 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500824 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800825 r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
826 n = Nod(OAS, n.List.Second(), r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500827 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500828
829 // a,b = m[i];
830 case OAS2MAPR:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800831 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500832
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800833 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800834 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500835 walkexpr(&r.Left, init)
836 walkexpr(&r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500837 t := r.Left.Type
838 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -0500839 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800840 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800841 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500842 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800843 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500844 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800845 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500846 p = "mapaccess2_faststr"
847 }
848 }
849
Russ Cox382b44e2015-02-23 16:07:24 -0500850 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500851 if p != "" {
852 // fast versions take key by value
853 key = r.Right
854 } else {
855 // standard version takes key by reference
856 // orderexpr made sure key is addressable.
857 key = Nod(OADDR, r.Right, nil)
858
859 p = "mapaccess2"
860 }
861
862 // from:
863 // a,b = m[i]
864 // to:
865 // var,b = mapaccess2*(t, m, i)
866 // a = *var
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800867 a := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -0500868
Russ Cox382b44e2015-02-23 16:07:24 -0500869 fn := mapfn(p, t)
Matthew Dempskydb506fe2016-03-08 16:31:28 -0800870 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500871
872 // mapaccess2* returns a typed bool, but due to spec changes,
873 // the boolean result of i.(T) is now untyped so we make it the
874 // same type as the variable on the lhs.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800875 if !isblank(n.List.Second()) {
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800876 r.Type.Field(1).Type = n.List.Second().Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500877 }
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800878 n.Rlist.Set1(r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500879 n.Op = OAS2FUNC
880
881 // don't generate a = *var if a is _
882 if !isblank(a) {
Russ Cox382b44e2015-02-23 16:07:24 -0500883 var_ := temp(Ptrto(t.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500884 var_.Typecheck = 1
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800885 n.List.SetIndex(0, var_)
Russ Cox8c195bd2015-02-13 14:40:36 -0500886 walkexpr(&n, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800887 init.Append(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500888 n = Nod(OAS, a, Nod(OIND, var_, nil))
889 }
890
891 typecheck(&n, Etop)
892 walkexpr(&n, init)
893
Russ Cox8c195bd2015-02-13 14:40:36 -0500894 // TODO: ptr is always non-nil, so disable nil check for this OIND op.
Russ Cox8c195bd2015-02-13 14:40:36 -0500895
896 case ODELETE:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800897 init.AppendNodes(&n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800898 map_ := n.List.First()
899 key := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500900 walkexpr(&map_, init)
901 walkexpr(&key, init)
902
903 // orderstmt made sure key is addressable.
904 key = Nod(OADDR, key, nil)
905
Russ Cox382b44e2015-02-23 16:07:24 -0500906 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500907 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500908
Russ Cox8c195bd2015-02-13 14:40:36 -0500909 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800910 e := n.Rlist.First() // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400911 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
912 // It needs to be removed in all three places.
913 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700914 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400915 // handled directly during gen.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800916 walkexprlistsafe(n.List.Slice(), init)
Russ Cox4224d812015-03-20 00:06:10 -0400917 walkexpr(&e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200918 break
Russ Cox4224d812015-03-20 00:06:10 -0400919 }
920
921 // res, ok = i.(T)
922 // orderstmt made sure a is addressable.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800923 init.AppendNodes(&n.Ninit)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700924
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800925 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700926 walkexpr(&e.Left, init)
927 t := e.Type // T
928 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500929
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700930 oktype := Types[TBOOL]
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800931 ok := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500932 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700933 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500934 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700935
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000936 fromKind := from.Type.iet()
937 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700938
939 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
940 // This is faster and shorter and allows the corresponding assertX2X2
941 // routines to skip nil checks on their last argument.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800942 if isblank(n.List.First()) {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700943 var fast *Node
944 switch {
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000945 case fromKind == 'E' && toKind == 'T':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700946 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
947 typ := Nod(OCONVNOP, typename(t), nil)
948 typ.Type = Ptrto(Types[TUINTPTR])
949 fast = Nod(OEQ, tab, typ)
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000950 case fromKind == 'I' && toKind == 'E',
951 fromKind == 'E' && toKind == 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700952 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700953 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700954 }
955 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400956 if Debug_typeassert > 0 {
957 Warn("type assertion (ok only) inlined")
958 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700959 n = Nod(OAS, ok, fast)
960 typecheck(&n, Etop)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200961 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700962 }
963 }
964
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700965 var resptr *Node // &res
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800966 if isblank(n.List.First()) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700967 resptr = nodnil()
968 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800969 resptr = Nod(OADDR, n.List.First(), nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700970 }
971 resptr.Etype = 1 // addr does not escape
972
Russ Cox4224d812015-03-20 00:06:10 -0400973 if Debug_typeassert > 0 {
974 Warn("type assertion not inlined")
975 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800976 fn := syslook(assertFuncName(from.Type, t, true))
977 substArgTypes(&fn, from.Type, t)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700978 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
979 n = Nod(OAS, ok, call)
Russ Cox8c195bd2015-02-13 14:40:36 -0500980 typecheck(&n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500981
Russ Cox4224d812015-03-20 00:06:10 -0400982 case ODOTTYPE, ODOTTYPE2:
983 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200984 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -0400985 }
986 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500987
988 case OCONVIFACE:
989 walkexpr(&n.Left, init)
990
991 // Optimize convT2E as a two-word copy when T is pointer-shaped.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500992 if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -0500993 l := Nod(OEFACE, typename(n.Left.Type), n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500994 l.Type = n.Type
995 l.Typecheck = n.Typecheck
996 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200997 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500998 }
999
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001000 var ll []*Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001001 if !Isinter(n.Left.Type) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001002 ll = append(ll, typename(n.Left.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001003 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001004 if !isnilinter(n.Type) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001005 ll = append(ll, typename(n.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001006 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001007 if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
Matthew Dempsky63142022016-03-15 13:06:58 -07001008 sym := Pkglookup(Tconv(n.Left.Type, FmtLeft)+"."+Tconv(n.Type, FmtLeft), itabpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -05001009 if sym.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -05001010 l := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001011 l.Sym = sym
1012 l.Type = Ptrto(Types[TUINT8])
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001013 l.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001014 l.Class = PEXTERN
1015 l.Xoffset = 0
1016 sym.Def = l
1017 ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
1018 }
1019
Russ Cox382b44e2015-02-23 16:07:24 -05001020 l := Nod(OADDR, sym.Def, nil)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001021 l.Addable = true
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001022 ll = append(ll, l)
Russ Cox8c195bd2015-02-13 14:40:36 -05001023
Russ Coxdc7b54b2015-02-17 22:13:49 -05001024 if isdirectiface(n.Left.Type) {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001025 // For pointer types, we can make a special form of optimization
1026 //
1027 // These statements are put onto the expression init list:
1028 // Itab *tab = atomicloadtype(&cache);
1029 // if(tab == nil)
1030 // tab = typ2Itab(type, itype, &cache);
1031 //
1032 // The CONVIFACE expression is replaced with this:
1033 // OEFACE{tab, ptr};
Russ Cox382b44e2015-02-23 16:07:24 -05001034 l := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001035
Russ Cox382b44e2015-02-23 16:07:24 -05001036 n1 := Nod(OAS, l, sym.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001037 typecheck(&n1, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001038 init.Append(n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001039
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001040 fn := syslook("typ2Itab")
Russ Cox8c195bd2015-02-13 14:40:36 -05001041 n1 = Nod(OCALL, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001042 n1.List.Set(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001043 typecheck(&n1, Erv)
1044 walkexpr(&n1, init)
1045
Russ Cox382b44e2015-02-23 16:07:24 -05001046 n2 := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -04001047 n2.Left = Nod(OEQ, l, nodnil())
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08001048 n2.Nbody.Set1(Nod(OAS, l, n1))
Russ Cox8c195bd2015-02-13 14:40:36 -05001049 n2.Likely = -1
1050 typecheck(&n2, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001051 init.Append(n2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001052
1053 l = Nod(OEFACE, l, n.Left)
1054 l.Typecheck = n.Typecheck
1055 l.Type = n.Type
1056 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001057 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001058 }
1059 }
1060
Russ Coxdc7b54b2015-02-17 22:13:49 -05001061 if Isinter(n.Left.Type) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001062 ll = append(ll, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001063 } else {
1064 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001065 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001066 // the conversions it could see. comparison of an interface
1067 // with a non-interface, especially in a switch on interface value
1068 // with non-interface cases, is not visible to orderstmt, so we
1069 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001070 if islvalue(n.Left) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001071 ll = append(ll, Nod(OADDR, n.Left, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001072 } else {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001073 ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001074 }
David Chase22701332015-03-27 11:21:14 -04001075 dowidth(n.Left.Type)
1076 r := nodnil()
1077 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1078 // Allocate stack buffer for value stored in interface.
1079 r = temp(n.Left.Type)
1080 r = Nod(OAS, r, nil) // zero temp
1081 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001082 init.Append(r)
David Chase22701332015-03-27 11:21:14 -04001083 r = Nod(OADDR, r.Left, nil)
1084 typecheck(&r, Erv)
1085 }
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001086 ll = append(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001087 }
1088
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001089 fn := syslook(convFuncName(n.Left.Type, n.Type))
David Chase22701332015-03-27 11:21:14 -04001090 if !Isinter(n.Left.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001091 substArgTypes(&fn, n.Left.Type, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001092 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001093 substArgTypes(&fn, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001094 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001095 dowidth(fn.Type)
1096 n = Nod(OCALL, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001097 n.List.Set(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -05001098 typecheck(&n, Erv)
1099 walkexpr(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001100
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001101 case OCONV, OCONVNOP:
Russ Cox8c195bd2015-02-13 14:40:36 -05001102 if Thearch.Thechar == '5' {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001103 if Isfloat[n.Left.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001104 if n.Type.Etype == TINT64 {
1105 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001106 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001107 }
1108
1109 if n.Type.Etype == TUINT64 {
1110 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001111 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001112 }
1113 }
1114
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001115 if Isfloat[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001116 if n.Left.Type.Etype == TINT64 {
1117 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001118 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001119 }
1120
1121 if n.Left.Type.Etype == TUINT64 {
1122 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001123 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001124 }
1125 }
1126 }
1127
1128 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001129
1130 case OANDNOT:
1131 walkexpr(&n.Left, init)
1132 n.Op = OAND
1133 n.Right = Nod(OCOM, n.Right, nil)
1134 typecheck(&n.Right, Erv)
1135 walkexpr(&n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001136
1137 case OMUL:
1138 walkexpr(&n.Left, init)
1139 walkexpr(&n.Right, init)
1140 walkmul(&n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001141
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001142 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -05001143 walkexpr(&n.Left, init)
1144 walkexpr(&n.Right, init)
1145
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001146 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001147 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001148
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001149 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001150 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001151 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1152 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001153 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001154 }
1155
1156 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001157 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001158 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001159 }
1160
1161 // Try rewriting as shifts or magic multiplies.
1162 walkdiv(&n, init)
1163
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001164 // rewrite 64-bit div and mod into function calls
1165 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001166 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001167 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001168 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001169 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001170 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001171 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001172 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001173 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001174 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001175 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001176 }
1177 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001178 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001179 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001180 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001181 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001182 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001183 }
1184
Russ Cox8c195bd2015-02-13 14:40:36 -05001185 case OINDEX:
1186 walkexpr(&n.Left, init)
1187
1188 // save the original node for bounds checking elision.
1189 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001190 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001191
1192 walkexpr(&n.Right, init)
1193
1194 // if range of type cannot exceed static array bound,
1195 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001196 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001197 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001198 }
Russ Cox382b44e2015-02-23 16:07:24 -05001199 t := n.Left.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001200 if t != nil && Isptr[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001201 t = t.Type
1202 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001203 if Isfixedarray(t) {
1204 n.Bounded = bounded(r, t.Bound)
1205 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001206 Warn("index bounds check elided")
1207 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001208 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001209 Yyerror("index out of bounds")
1210 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001211 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001212 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001213 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001214 Warn("index bounds check elided")
1215 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001216 if Smallintconst(n.Right) {
1217 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001218 Yyerror("index out of bounds")
1219 } else {
1220 // replace "abc"[1] with 'b'.
1221 // delayed until now because "abc"[1] is not
1222 // an ideal constant.
Russ Cox81d58102015-05-27 00:47:05 -04001223 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05001224
Russ Cox81d58102015-05-27 00:47:05 -04001225 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001226 n.Typecheck = 1
1227 }
1228 }
1229 }
1230
Russ Coxdc7b54b2015-02-17 22:13:49 -05001231 if Isconst(n.Right, CTINT) {
Russ Cox81d58102015-05-27 00:47:05 -04001232 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 -05001233 Yyerror("index out of bounds")
1234 }
1235 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001236
1237 case OINDEXMAP:
1238 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001239 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001240 }
1241 walkexpr(&n.Left, init)
1242 walkexpr(&n.Right, init)
1243
Russ Cox382b44e2015-02-23 16:07:24 -05001244 t := n.Left.Type
1245 p := ""
Russ Cox8c195bd2015-02-13 14:40:36 -05001246 if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08001247 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001248 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001249 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001250 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001251 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001252 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001253 p = "mapaccess1_faststr"
1254 }
1255 }
1256
Russ Cox382b44e2015-02-23 16:07:24 -05001257 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001258 if p != "" {
1259 // fast versions take key by value
1260 key = n.Right
1261 } else {
1262 // standard version takes key by reference.
1263 // orderexpr made sure key is addressable.
1264 key = Nod(OADDR, n.Right, nil)
1265
1266 p = "mapaccess1"
1267 }
1268
1269 n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
1270 n = Nod(OIND, n, nil)
1271 n.Type = t.Type
1272 n.Typecheck = 1
1273
Russ Cox8c195bd2015-02-13 14:40:36 -05001274 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001275 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001276
Russ Coxd4472792015-05-06 12:35:53 -04001277 case OSLICE, OSLICEARR, OSLICESTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05001278 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001279 walkexpr(&n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001280 if n.Right.Left != nil && iszero(n.Right.Left) {
1281 // Reduce x[0:j] to x[:j].
1282 n.Right.Left = nil
1283 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001284 walkexpr(&n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001285 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001286
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001287 case OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -04001288 walkexpr(&n.Left, init)
1289 walkexpr(&n.Right.Left, init)
1290 if n.Right.Left != nil && iszero(n.Right.Left) {
1291 // Reduce x[0:j:k] to x[:j:k].
1292 n.Right.Left = nil
1293 }
1294 walkexpr(&n.Right.Right.Left, init)
1295 walkexpr(&n.Right.Right.Right, init)
1296
1297 r := n.Right.Right.Right
1298 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1299 // Reduce x[i:j:cap(x)] to x[i:j].
1300 n.Right.Right = n.Right.Right.Left
1301 if n.Op == OSLICE3 {
1302 n.Op = OSLICE
1303 } else {
1304 n.Op = OSLICEARR
1305 }
1306 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001307 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001308
1309 case OADDR:
1310 walkexpr(&n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001311
1312 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001313 if n.Esc == EscNone {
1314 if n.Type.Type.Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001315 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001316 }
Russ Cox382b44e2015-02-23 16:07:24 -05001317 r := temp(n.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001318 r = Nod(OAS, r, nil) // zero temp
1319 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001320 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001321 r = Nod(OADDR, r.Left, nil)
1322 typecheck(&r, Erv)
1323 n = r
1324 } else {
1325 n = callnew(n.Type.Type)
1326 }
1327
Russ Cox8c195bd2015-02-13 14:40:36 -05001328 // If one argument to the comparison is an empty string,
1329 // comparing the lengths instead will yield the same result
1330 // without the function call.
1331 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001332 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 +02001333 // TODO(marvin): Fix Node.EType type union.
1334 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001335 typecheck(&r, Erv)
1336 walkexpr(&r, init)
1337 r.Type = n.Type
1338 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001339 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001340 }
1341
1342 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001343 if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001344 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001345 r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001346 typecheck(&r, Erv)
1347 walkexpr(&r, init)
1348 r.Type = n.Type
1349 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001350 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001351 }
1352
Russ Cox382b44e2015-02-23 16:07:24 -05001353 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001354 // TODO(marvin): Fix Node.EType type union.
1355 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001356 // prepare for rewrite below
1357 n.Left = cheapexpr(n.Left, init)
1358
1359 n.Right = cheapexpr(n.Right, init)
1360
1361 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1362
1363 // quick check of len before full compare for == or !=
1364 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001365 // TODO(marvin): Fix Node.EType type union.
1366 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001367 // len(left) == len(right) && eqstring(left, right)
1368 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1369 } else {
1370 // len(left) != len(right) || !eqstring(left, right)
1371 r = Nod(ONOT, r, nil)
1372
1373 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1374 }
1375
1376 typecheck(&r, Erv)
1377 walkexpr(&r, nil)
1378 } else {
1379 // sys_cmpstring(s1, s2) :: 0
1380 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1381
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001382 // TODO(marvin): Fix Node.EType type union.
1383 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001384 }
1385
1386 typecheck(&r, Erv)
1387 if n.Type.Etype != TBOOL {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001388 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001389 }
1390 r.Type = n.Type
1391 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001392
1393 case OADDSTR:
1394 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001395
1396 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001397 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001398 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001399
1400 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001401 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001402
1403 // cannot use chanfn - closechan takes any, not chan any
1404 case OCLOSE:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001405 fn := syslook("closechan")
Russ Cox8c195bd2015-02-13 14:40:36 -05001406
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001407 substArgTypes(&fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001408 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001409
1410 case OMAKECHAN:
1411 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 -05001412
1413 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001414 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001415
Russ Cox382b44e2015-02-23 16:07:24 -05001416 a := nodnil() // hmap buffer
1417 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001418 if n.Esc == EscNone {
1419 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001420 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001421
1422 a = Nod(OAS, var_, nil) // zero temp
1423 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001424 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001425 a = Nod(OADDR, var_, nil)
1426
1427 // Allocate one bucket on stack.
1428 // Maximum key/value size is 128 bytes, larger objects
1429 // are stored with an indirection. So max bucket size is 2048+eps.
1430 var_ = temp(mapbucket(t))
1431
1432 r = Nod(OAS, var_, nil) // zero temp
1433 typecheck(&r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001434 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001435 r = Nod(OADDR, var_, nil)
1436 }
1437
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001438 fn := syslook("makemap")
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08001439 substArgTypes(&fn, hmap(t), mapbucket(t), t.Key(), t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001440 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001441
1442 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001443 l := n.Left
1444 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001445 if r == nil {
1446 r = safeexpr(l, init)
1447 l = r
1448 }
Russ Cox382b44e2015-02-23 16:07:24 -05001449 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001450 if n.Esc == EscNone {
1451 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001452 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001453 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001454 // var arr [r]T
1455 // n = arr[:l]
1456 t = aindex(r, t.Type) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001457 var_ := temp(t)
1458 a := Nod(OAS, var_, nil) // zero temp
Russ Cox8c195bd2015-02-13 14:40:36 -05001459 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001460 init.Append(a)
Russ Cox382b44e2015-02-23 16:07:24 -05001461 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001462 r = conv(r, n.Type) // in case n.Type is named.
Russ Cox8c195bd2015-02-13 14:40:36 -05001463 typecheck(&r, Erv)
1464 walkexpr(&r, init)
1465 n = r
1466 } else {
1467 // makeslice(t *Type, nel int64, max int64) (ary []any)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001468 fn := syslook("makeslice")
Russ Cox8c195bd2015-02-13 14:40:36 -05001469
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001470 substArgTypes(&fn, t.Type) // any-1
Russ Cox8c195bd2015-02-13 14:40:36 -05001471 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
1472 }
1473
Russ Cox8c195bd2015-02-13 14:40:36 -05001474 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001475 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001476 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001477 t := aindex(Nodintconst(4), Types[TUINT8])
1478 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001479 a = Nod(OADDR, var_, nil)
1480 }
1481
1482 // intstring(*[4]byte, rune)
1483 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1484
Russ Cox8c195bd2015-02-13 14:40:36 -05001485 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001486 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001487 if n.Esc == EscNone {
1488 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001489 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001490
1491 a = Nod(OADDR, temp(t), nil)
1492 }
1493
1494 // slicebytetostring(*[32]byte, []byte) string;
1495 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1496
Russ Cox8c195bd2015-02-13 14:40:36 -05001497 // slicebytetostringtmp([]byte) string;
1498 case OARRAYBYTESTRTMP:
1499 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1500
Russ Cox8c195bd2015-02-13 14:40:36 -05001501 // slicerunetostring(*[32]byte, []rune) string;
1502 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001503 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001504
1505 if n.Esc == EscNone {
1506 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001507 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001508
1509 a = Nod(OADDR, temp(t), nil)
1510 }
1511
1512 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001513
1514 // stringtoslicebyte(*32[byte], string) []byte;
1515 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001516 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001517
1518 if n.Esc == EscNone {
1519 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001520 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001521
1522 a = Nod(OADDR, temp(t), nil)
1523 }
1524
1525 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001526
1527 // stringtoslicebytetmp(string) []byte;
1528 case OSTRARRAYBYTETMP:
1529 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1530
Russ Cox8c195bd2015-02-13 14:40:36 -05001531 // stringtoslicerune(*[32]rune, string) []rune
1532 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001533 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001534
1535 if n.Esc == EscNone {
1536 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001537 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001538
1539 a = Nod(OADDR, temp(t), nil)
1540 }
1541
1542 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001543
1544 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1545 case OCMPIFACE:
1546 if !Eqtype(n.Left.Type, n.Right.Type) {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08001547 Fatalf("ifaceeq %v %v %v", Oconv(n.Op, 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001548 }
Russ Cox382b44e2015-02-23 16:07:24 -05001549 var fn *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001550 if isnilinter(n.Left.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001551 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001552 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001553 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001554 }
1555
1556 n.Right = cheapexpr(n.Right, init)
1557 n.Left = cheapexpr(n.Left, init)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001558 substArgTypes(&fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001559 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001560 // TODO(marvin): Fix Node.EType type union.
1561 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001562 r = Nod(ONOT, r, nil)
1563 }
1564
1565 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001566 // TODO(marvin): Fix Node.EType type union.
1567 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001568 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1569 } else {
1570 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1571 }
1572 typecheck(&r, Erv)
1573 walkexpr(&r, init)
1574 r.Type = n.Type
1575 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001576
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001577 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Russ Cox382b44e2015-02-23 16:07:24 -05001578 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001579 anylit(0, n, var_, init)
1580 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001581
1582 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001583 n1 := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001584 n1 = assignconv(n1, n.Left.Type.Type, "chan send")
1585 walkexpr(&n1, init)
1586 n1 = Nod(OADDR, n1, nil)
1587 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001588
1589 case OCLOSURE:
1590 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001591
1592 case OCALLPART:
1593 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001594 }
1595
Russ Cox8c195bd2015-02-13 14:40:36 -05001596 // Expressions that are constant at run time but not
1597 // considered const by the language spec are not turned into
1598 // constants until walk. For example, if n is y%1 == 0, the
1599 // walk of y%1 may have replaced it by 0.
1600 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001601 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001602
1603 evconst(n)
1604 n.Type = t
1605 if n.Op == OLITERAL {
1606 typecheck(&n, Erv)
1607 }
1608
1609 ullmancalc(n)
1610
1611 if Debug['w'] != 0 && n != nil {
1612 Dump("walk", n)
1613 }
1614
1615 lineno = lno
1616 *np = n
1617}
1618
Russ Coxd4472792015-05-06 12:35:53 -04001619func reduceSlice(n *Node) *Node {
1620 r := n.Right.Right
1621 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1622 // Reduce x[i:len(x)] to x[i:].
1623 n.Right.Right = nil
1624 }
1625 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1626 // Reduce x[:] to x.
1627 if Debug_slice > 0 {
1628 Warn("slice: omit slice operation")
1629 }
1630 return n.Left
1631 }
1632 return n
1633}
1634
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001635func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001636 // convas will turn map assigns into function calls,
1637 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001638 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001639
1640 if l.Op == OINDEXMAP {
1641 return n
1642 }
1643
1644 return convas(n, init)
1645}
1646
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001647func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001648 // check assign expression list to
1649 // a expression list. called in
1650 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001651
1652 // ensure order of evaluation for function calls
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001653 for i := range nl {
1654 nl[i] = safeexpr(nl[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001655 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001656 for i1 := range nr {
1657 nr[i1] = safeexpr(nr[i1], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001658 }
1659
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001660 var nn []*Node
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001661 i := 0
1662 for ; i < len(nl); i++ {
1663 if i >= len(nr) {
1664 break
1665 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001666 // Do not generate 'x = x' during return. See issue 4014.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001667 if op == ORETURN && nl[i] == nr[i] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001668 continue
1669 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001670 nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001671 }
1672
1673 // cannot happen: caller checked that lists had same length
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001674 if i < len(nl) || i < len(nr) {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001675 var nln, nrn Nodes
1676 nln.Set(nl)
1677 nrn.Set(nr)
Matthew Dempsky63142022016-03-15 13:06:58 -07001678 Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nln, FmtSign), Oconv(op, 0), Hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -05001679 }
1680 return nn
1681}
1682
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001683// l is an lv and rt is the type of an rv
1684// return 1 if this implies a function call
1685// evaluating the lv or a function call
1686// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001687func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001688 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001689 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001690 }
Russ Cox175929b2015-03-02 14:22:05 -05001691 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001692 if needwritebarrier(l, &r) {
1693 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001694 }
1695 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001696 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001697 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001698 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001699}
1700
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001701// check assign type list to
1702// a expression list. called in
1703// expr-list = func()
1704func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
1705 r, saver := IterFields(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001706
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001707 var nn, mm []*Node
1708 var ullmanOverflow bool
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001709 var i int
1710 for i = 0; i < nl.Len(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001711 if r == nil {
1712 break
1713 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001714 l := nl.Index(i)
Russ Cox8c195bd2015-02-13 14:40:36 -05001715 if isblank(l) {
Matthew Dempsky7758a942016-03-08 15:02:40 -08001716 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001717 continue
1718 }
1719
1720 // any lv that causes a fn call must be
1721 // deferred until all the return arguments
1722 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001723 if fncall(l, r.Type) {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001724 tmp := temp(r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001725 typecheck(&tmp, Erv)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001726 a := Nod(OAS, l, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001727 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001728 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001729 l = tmp
1730 }
1731
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001732 a := Nod(OAS, l, nodarg(r, fp))
Russ Cox8c195bd2015-02-13 14:40:36 -05001733 a = convas(a, init)
1734 ullmancalc(a)
1735 if a.Ullman >= UINF {
1736 Dump("ascompatet ucount", a)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001737 ullmanOverflow = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001738 }
1739
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001740 nn = append(nn, a)
Matthew Dempsky7758a942016-03-08 15:02:40 -08001741 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001742 }
1743
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001744 if i < nl.Len() || r != nil {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001745 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), structcount(nr))
Russ Cox8c195bd2015-02-13 14:40:36 -05001746 }
1747
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001748 if ullmanOverflow {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001749 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001750 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001751 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001752}
1753
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001754// package all the arguments that match a ... T parameter into a []T.
Matthew Dempsky2e936902016-03-14 01:20:49 -07001755func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001756 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001757 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001758 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001759 }
1760
Russ Cox382b44e2015-02-23 16:07:24 -05001761 tslice := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001762 tslice.Type = l.Type.Type
1763 tslice.Bound = -1
1764
Russ Cox382b44e2015-02-23 16:07:24 -05001765 var n *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001766 if len(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001767 n = nodnil()
1768 n.Type = tslice
1769 } else {
1770 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001771 if ddd != nil && prealloc[ddd] != nil {
1772 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001773 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001774 n.List.Set(lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001775 n.Esc = esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001776 typecheck(&n, Erv)
1777 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001778 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001779 }
1780 walkexpr(&n, init)
1781 }
1782
Russ Cox382b44e2015-02-23 16:07:24 -05001783 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001784 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001785 return nn
1786}
1787
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001788// helpers for shape errors
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001789func dumptypes(nl *Type, what string) string {
1790 s := ""
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001791 for _, l := range nl.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001792 if s != "" {
1793 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001794 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07001795 s += Fldconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001796 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001797 if s == "" {
1798 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001799 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001800 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001801}
1802
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001803func dumpnodetypes(l []*Node, what string) string {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001804 s := ""
1805 for _, r := range l {
1806 if s != "" {
1807 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001808 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001809 s += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001810 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001811 if s == "" {
1812 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001813 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001814 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001815}
1816
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001817// check assign expression list to
1818// a type list. called in
1819// return expr-list
1820// func(expr-list)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001821func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05001822 lr0 := lr
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001823 l, savel := IterFields(nl)
Russ Cox175929b2015-03-02 14:22:05 -05001824 var r *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001825 if len(lr) > 0 {
1826 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001827 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001828 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001829
1830 // f(g()) where g has multiple return values
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001831 if r != nil && len(lr) <= 1 && r.Type.Etype == TSTRUCT && r.Type.Funarg {
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 // optimization - can do block copy
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001833 if eqtypenoname(r.Type, nl) {
1834 arg := nodarg(nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001835 r = Nod(OCONVNOP, r, nil)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001836 r.Type = arg.Type
1837 nn = []*Node{convas(Nod(OAS, arg, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001838 goto ret
1839 }
1840
1841 // conversions involved.
1842 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001843 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001844
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001845 for _, l := range r.Type.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001846 tmp := temp(l.Type)
1847 alist = append(alist, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001848 }
1849
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001850 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001851 a.List.Set(alist)
1852 a.Rlist.Set(lr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001853 typecheck(&a, Etop)
1854 walkstmt(&a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001855 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001856 lr = alist
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001857 r = lr[0]
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001858 l, savel = IterFields(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -05001859 }
1860
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001861 for {
1862 if l != nil && l.Isddd {
1863 // the ddd parameter must be last
1864 ll := savel.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001865
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001866 if ll != nil {
1867 Yyerror("... must be last argument")
Russ Cox8c195bd2015-02-13 14:40:36 -05001868 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001869
1870 // special case --
1871 // only if we are assigning a single ddd
1872 // argument to a ddd parameter then it is
1873 // passed thru unencapsulated
1874 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
1875 a := Nod(OAS, nodarg(l, fp), r)
1876 a = convas(a, init)
1877 nn = append(nn, a)
1878 break
1879 }
1880
1881 // normal case -- make a slice of all
1882 // remaining arguments and pass it to
1883 // the ddd parameter.
1884 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1885
1886 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001887 }
1888
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001889 if l == nil || r == nil {
1890 if l != nil || r != nil {
1891 l1 := dumptypes(nl, "expected")
1892 l2 := dumpnodetypes(lr0, "given")
1893 if l != nil {
1894 Yyerror("not enough arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
1895 } else {
1896 Yyerror("too many arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
1897 }
1898 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001899
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001900 break
1901 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001902
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001903 a := Nod(OAS, nodarg(l, fp), r)
1904 a = convas(a, init)
1905 nn = append(nn, a)
1906
1907 l = savel.Next()
1908 r = nil
1909 lr = lr[1:]
1910 if len(lr) > 0 {
1911 r = lr[0]
1912 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001913 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001914
1915ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001916 for _, n := range nn {
1917 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001918 }
1919 return nn
1920}
1921
1922// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001923func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001924 var r *Node
1925 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001926 var on *Node
1927 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001928 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001929
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001930 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001931 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001932 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001933 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001934
1935 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001936 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001937
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001938 calls = append(calls, mkcall("printlock", nil, init))
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001939 for i1, n1 := range all.Slice() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001940 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001941 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001942 }
1943
Russ Coxdc7b54b2015-02-17 22:13:49 -05001944 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001945
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001946 n = n1
Russ Cox8c195bd2015-02-13 14:40:36 -05001947 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04001948 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001949 case CTRUNE:
1950 defaultlit(&n, runetype)
1951
1952 case CTINT:
1953 defaultlit(&n, Types[TINT64])
1954
1955 case CTFLT:
1956 defaultlit(&n, Types[TFLOAT64])
1957 }
1958 }
1959
1960 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
1961 defaultlit(&n, Types[TINT64])
1962 }
1963 defaultlit(&n, nil)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001964 all.SetIndex(i1, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001965 if n.Type == nil || n.Type.Etype == TFORW {
1966 continue
1967 }
1968
1969 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001970 et = n.Type.Etype
Russ Coxdc7b54b2015-02-17 22:13:49 -05001971 if Isinter(n.Type) {
1972 if isnilinter(n.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001973 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05001974 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001975 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05001976 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001977 substArgTypes(&on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001978 } else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001979 on = syslook("printpointer")
1980 substArgTypes(&on, n.Type) // any-1
Russ Coxdc7b54b2015-02-17 22:13:49 -05001981 } else if Isslice(n.Type) {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001982 on = syslook("printslice")
1983 substArgTypes(&on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001984 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001985 if et == TUINT64 {
1986 if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001987 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05001988 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001989 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05001990 }
1991 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001992 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05001993 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001994 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001995 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001996 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001997 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05001998 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001999 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05002000 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002001 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05002002 } else {
2003 badtype(OPRINT, n.Type, nil)
2004 continue
2005 }
2006
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -07002007 t = on.Type.Params().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002008
2009 if !Eqtype(t, n.Type) {
2010 n = Nod(OCONV, n, nil)
2011 n.Type = t
2012 }
2013
2014 r = Nod(OCALL, on, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002015 r.List.Append(n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002016 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002017 }
2018
2019 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002020 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002021 }
2022
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002023 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002024
2025 typechecklist(calls, Etop)
2026 walkexprlist(calls, init)
2027
2028 r = Nod(OEMPTY, nil, nil)
2029 typecheck(&r, Etop)
2030 walkexpr(&r, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002031 r.Ninit.Set(calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002032 return r
2033}
2034
2035func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002036 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002037 fn := syslook("newobject")
2038 substArgTypes(&fn, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002039 return mkcall1(fn, Ptrto(t), nil, typename(t))
2040}
2041
Russ Cox3b6e86f2015-06-29 15:17:14 -04002042func iscallret(n *Node) bool {
2043 n = outervalue(n)
2044 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2045}
2046
Russ Coxdc7b54b2015-02-17 22:13:49 -05002047func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002048 n = outervalue(n)
2049
2050 // If n is *autotmp and autotmp = &foo, replace n with foo.
2051 // We introduce such temps when initializing struct literals.
2052 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002053 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002054 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2055 n = defn.Right.Left
2056 }
2057 }
2058
2059 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002060 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002061 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002062
2063 case ONAME:
2064 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002065 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002066 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002067 }
2068 }
2069
Russ Coxdc7b54b2015-02-17 22:13:49 -05002070 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002071}
2072
Russ Coxdc7b54b2015-02-17 22:13:49 -05002073func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002074 n = outervalue(n)
2075
2076 switch n.Op {
2077 case ONAME:
2078 switch n.Class {
2079 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002080 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002081 }
2082 }
2083
Russ Coxdc7b54b2015-02-17 22:13:49 -05002084 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002085}
2086
2087// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002088func needwritebarrier(l *Node, r *Node) bool {
2089 if use_writebarrier == 0 {
2090 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002091 }
2092
2093 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002094 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002095 }
2096
2097 // No write barrier for write of non-pointers.
2098 dowidth(l.Type)
2099
2100 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002101 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002102 }
2103
2104 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002105 if isstack(l) {
2106 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002107 }
2108
Russ Cox9f90f312015-06-29 12:49:25 -04002109 // No write barrier for implicit zeroing.
2110 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002111 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002112 }
2113
Russ Cox9f90f312015-06-29 12:49:25 -04002114 // Ignore no-op conversions when making decision.
2115 // Ensures that xp = unsafe.Pointer(&x) is treated
2116 // the same as xp = &x.
2117 for r.Op == OCONVNOP {
2118 r = r.Left
2119 }
2120
2121 // No write barrier for zeroing or initialization to constant.
2122 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002123 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002124 }
2125
2126 // No write barrier for storing static (read-only) data.
2127 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002128 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002129 }
2130
2131 // No write barrier for storing address of stack values,
2132 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002133 if r.Op == OADDR && isstack(r.Left) {
2134 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002135 }
2136
2137 // No write barrier for storing address of global, which
2138 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002139 if r.Op == OADDR && isglobal(r.Left) {
2140 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002141 }
2142
Austin Clements3e54ca92016-03-16 18:22:58 -04002143 // No write barrier for storing global function, which is live
2144 // no matter what.
2145 if r.Op == ONAME && r.Class == PFUNC {
2146 return false
2147 }
2148
Russ Cox8c195bd2015-02-13 14:40:36 -05002149 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002150 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002151}
2152
2153// TODO(rsc): Perhaps componentgen should run before this.
2154
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002155func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002156 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002157 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002158 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002159 }
Russ Cox972a4782015-05-21 15:00:06 -04002160 n.Op = OASWB
2161 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002162 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002163 return n
2164}
2165
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002166func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002167 if n.Op != OAS {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002168 Fatalf("convas: not OAS %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002169 }
2170
2171 n.Typecheck = 1
2172
Russ Cox382b44e2015-02-23 16:07:24 -05002173 var lt *Type
2174 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002175 if n.Left == nil || n.Right == nil {
2176 goto out
2177 }
2178
2179 lt = n.Left.Type
2180 rt = n.Right.Type
2181 if lt == nil || rt == nil {
2182 goto out
2183 }
2184
2185 if isblank(n.Left) {
2186 defaultlit(&n.Right, nil)
2187 goto out
2188 }
2189
2190 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002191 map_ := n.Left.Left
2192 key := n.Left.Right
2193 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002194 walkexpr(&map_, init)
2195 walkexpr(&key, init)
2196 walkexpr(&val, init)
2197
2198 // orderexpr made sure key and val are addressable.
2199 key = Nod(OADDR, key, nil)
2200
2201 val = Nod(OADDR, val, nil)
2202 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2203 goto out
2204 }
2205
2206 if !Eqtype(lt, rt) {
2207 n.Right = assignconv(n.Right, lt, "assignment")
2208 walkexpr(&n.Right, init)
2209 }
2210
2211out:
2212 ullmancalc(n)
2213 return n
2214}
2215
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002216// from ascompat[te]
2217// evaluating actual function arguments.
2218// f(a,b)
2219// if there is exactly one function expr,
2220// then it is done first. otherwise must
2221// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002222func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002223 c := 0 // function calls
2224 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002225
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002226 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002227 t++
2228 ullmancalc(n)
2229 if n.Ullman >= UINF {
2230 c++
2231 }
2232 }
2233
2234 if c == 0 || t == 1 {
2235 return all
2236 }
2237
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002238 var g []*Node // fncalls assigned to tempnames
2239 var f *Node // last fncall assigned to stack
2240 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002241 d := 0
2242 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002243 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002244 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002245 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002246 continue
2247 }
2248
2249 d++
2250 if d == c {
2251 f = n
2252 continue
2253 }
2254
2255 // make assignment of fncall to tempname
2256 a = temp(n.Right.Type)
2257
2258 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002259 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002260
2261 // put normal arg assignment on list
2262 // with fncall replaced by tempname
2263 n.Right = a.Left
2264
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002265 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002266 }
2267
2268 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002269 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002270 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002271 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002272}
2273
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002274// from ascompat[ee]
2275// a,b = c,d
2276// simultaneous assignment. there cannot
2277// be later use of an earlier lvalue.
2278//
2279// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002280func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002281 var l *Node
2282
2283 // If a needed expression may be affected by an
2284 // earlier assignment, make an early copy of that
2285 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002286 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002287
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002288 var mapinit Nodes
2289 for i, n := range all {
2290 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002291
2292 // Save subexpressions needed on left side.
2293 // Drill through non-dereferences.
2294 for {
2295 if l.Op == ODOT || l.Op == OPAREN {
2296 l = l.Left
2297 continue
2298 }
2299
Russ Coxdc7b54b2015-02-17 22:13:49 -05002300 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002301 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002302 l = l.Left
2303 continue
2304 }
2305
2306 break
2307 }
2308
2309 switch l.Op {
2310 default:
Matthew Dempsky63142022016-03-15 13:06:58 -07002311 Fatalf("reorder3 unexpected lvalue %v", Oconv(l.Op, FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002312
2313 case ONAME:
2314 break
2315
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002316 case OINDEX, OINDEXMAP:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002317 reorder3save(&l.Left, all, i, &early)
2318 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002319 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002320 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002321 }
2322
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002323 case OIND, ODOTPTR:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002324 reorder3save(&l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002325 }
2326
2327 // Save expression on right side.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002328 reorder3save(&all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002329 }
2330
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002331 early = append(mapinit.Slice(), early...)
2332 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002333}
2334
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002335// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002336// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002337// copy into a temporary during *early and
2338// replace *np with that temp.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002339func reorder3save(np **Node, all []*Node, i int, early *[]*Node) {
Russ Cox382b44e2015-02-23 16:07:24 -05002340 n := *np
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002341 if !aliased(n, all, i) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002342 return
2343 }
2344
Russ Cox382b44e2015-02-23 16:07:24 -05002345 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002346 q = Nod(OAS, q, n)
2347 typecheck(&q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002348 *early = append(*early, q)
Russ Cox8c195bd2015-02-13 14:40:36 -05002349 *np = q.Left
2350}
2351
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002352// what's the outer value that a write to n affects?
2353// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002354func outervalue(n *Node) *Node {
2355 for {
2356 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002357 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002358 }
2359 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2360 n = n.Left
2361 continue
2362 }
2363
Russ Coxdc7b54b2015-02-17 22:13:49 -05002364 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002365 n = n.Left
2366 continue
2367 }
2368
2369 break
2370 }
2371
2372 return n
2373}
2374
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002375// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002376// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002377func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002378 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002379 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002380 }
2381
2382 // Look for obvious aliasing: a variable being assigned
2383 // during the all list and appearing in n.
2384 // Also record whether there are any writes to main memory.
2385 // Also record whether there are any writes to variables
2386 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002387 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002388
Russ Cox382b44e2015-02-23 16:07:24 -05002389 varwrite := 0
2390 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002391 for _, an := range all[:i] {
2392 a = outervalue(an.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05002393 if a.Op != ONAME {
2394 memwrite = 1
2395 continue
2396 }
2397
2398 switch n.Class {
2399 default:
2400 varwrite = 1
2401 continue
2402
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002403 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002404 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002405 varwrite = 1
2406 continue
2407 }
2408
Russ Coxdc7b54b2015-02-17 22:13:49 -05002409 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002410 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002411 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002412 }
2413 }
2414 }
2415
2416 // The variables being written do not appear in n.
2417 // However, n might refer to computed addresses
2418 // that are being written.
2419
2420 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002421 if memwrite == 0 && varwrite == 0 {
2422 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002423 }
2424
2425 // If n does not refer to computed addresses
2426 // (that is, if n only refers to variables whose addresses
2427 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002428 if varexpr(n) {
2429 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002430 }
2431
2432 // Otherwise, both the writes and n refer to computed memory addresses.
2433 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002434 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002435}
2436
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002437// does the evaluation of n only refer to variables
2438// whose addresses have not been taken?
2439// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002440func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002441 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002442 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002443 }
2444
2445 switch n.Op {
2446 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002447 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002448
2449 case ONAME:
2450 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002451 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002452 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002453 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002454 }
2455 }
2456
Russ Coxdc7b54b2015-02-17 22:13:49 -05002457 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002458
2459 case OADD,
2460 OSUB,
2461 OOR,
2462 OXOR,
2463 OMUL,
2464 ODIV,
2465 OMOD,
2466 OLSH,
2467 ORSH,
2468 OAND,
2469 OANDNOT,
2470 OPLUS,
2471 OMINUS,
2472 OCOM,
2473 OPAREN,
2474 OANDAND,
2475 OOROR,
2476 ODOT, // but not ODOTPTR
2477 OCONV,
2478 OCONVNOP,
2479 OCONVIFACE,
2480 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002481 return varexpr(n.Left) && varexpr(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002482 }
2483
2484 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002485 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002486}
2487
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002488// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002489func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002490 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002491 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002492 }
2493 switch r.Op {
2494 // match each right given left
2495 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002496 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002497
2498 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002499 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002500 }
2501
Russ Coxdc7b54b2015-02-17 22:13:49 -05002502 if vmatch2(l, r.Left) {
2503 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002504 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002505 if vmatch2(l, r.Right) {
2506 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002507 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002508 for _, n := range r.List.Slice() {
2509 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002510 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002511 }
2512 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002513 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002514}
2515
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002516// is any name mentioned in l also mentioned in r?
2517// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002518func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002519 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002520 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002521 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002522 }
2523 switch l.Op {
2524 case ONAME:
2525 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002526 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002527 break
2528
2529 // assignment to non-stack variable
2530 // must be delayed if right has function calls.
2531 default:
2532 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002533 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002534 }
2535 }
2536
2537 return vmatch2(l, r)
2538
2539 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002540 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002541 }
2542
Russ Coxdc7b54b2015-02-17 22:13:49 -05002543 if vmatch1(l.Left, r) {
2544 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002545 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002546 if vmatch1(l.Right, r) {
2547 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002548 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002549 for _, n := range l.List.Slice() {
2550 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002551 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002552 }
2553 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002554 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002555}
2556
Matthew Dempsky2339b132016-03-09 18:54:26 -08002557// paramstoheap returns code to allocate memory for heap-escaped parameters
2558// and to copy non-result prameters' values from the stack.
2559// If out is true, then code is also produced to zero-initialize their
2560// stack memory addresses.
2561func paramstoheap(params *Type, out bool) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002562 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002563 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002564 v := t.Nname
2565 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
Russ Cox8c195bd2015-02-13 14:40:36 -05002566 v = nil
2567 }
2568
2569 // For precise stacks, the garbage collector assumes results
2570 // are always live, so zero them always.
Matthew Dempsky2339b132016-03-09 18:54:26 -08002571 if out {
Russ Cox8c195bd2015-02-13 14:40:36 -05002572 // Defer might stop a panic and show the
2573 // return values as they exist at the time of panic.
2574 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002575 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002576 }
2577
Russ Coxdc7b54b2015-02-17 22:13:49 -05002578 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002579 continue
2580 }
2581
2582 // generate allocation & copying code
2583 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002584 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002585 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002586 if prealloc[v] == nil {
2587 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002588 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002589 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002590 if v.Class&^PHEAP != PPARAMOUT {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002591 as := Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002592 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002593 typecheck(&as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002594 as = applywritebarrier(as)
2595 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002596 }
2597 }
2598
2599 return nn
2600}
2601
Matthew Dempsky2339b132016-03-09 18:54:26 -08002602// returnsfromheap returns code to copy values for heap-escaped parameters
2603// back to the stack.
2604func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002605 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002606 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002607 v := t.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -05002608 if v == nil || v.Class != PHEAP|PPARAMOUT {
2609 continue
2610 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002611 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002612 }
2613
2614 return nn
2615}
2616
Matthew Dempsky2339b132016-03-09 18:54:26 -08002617// heapmoves generates code to handle migrating heap-escaped parameters
2618// between the stack and the heap. The generated code is added to Curfn's
2619// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002620func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002621 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002622 lineno = Curfn.Lineno
Matthew Dempskyf91b8322016-03-09 20:54:59 -08002623 nn := paramstoheap(Curfn.Type.Recvs(), false)
Matthew Dempsky2339b132016-03-09 18:54:26 -08002624 nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...)
2625 nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002626 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002627 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002628 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002629 lineno = lno
2630}
2631
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002632func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002633 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002634 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002635 }
2636
Russ Cox382b44e2015-02-23 16:07:24 -05002637 n := fn.Type.Intuple
Russ Cox8c195bd2015-02-13 14:40:36 -05002638
Russ Cox382b44e2015-02-23 16:07:24 -05002639 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002640 r.List.Set(va[:n])
Russ Cox8c195bd2015-02-13 14:40:36 -05002641 if fn.Type.Outtuple > 0 {
2642 typecheck(&r, Erv|Efnstruct)
2643 } else {
2644 typecheck(&r, Etop)
2645 }
2646 walkexpr(&r, init)
2647 r.Type = t
2648 return r
2649}
2650
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002651func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002652 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002653}
2654
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002655func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002656 return vmkcall(fn, t, init, args)
2657}
2658
2659func conv(n *Node, t *Type) *Node {
2660 if Eqtype(n.Type, t) {
2661 return n
2662 }
2663 n = Nod(OCONV, n, nil)
2664 n.Type = t
2665 typecheck(&n, Erv)
2666 return n
2667}
2668
2669func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002670 if t.Etype != TCHAN {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002671 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002672 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002673 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002674 switch n {
2675 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002676 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002677 case 1:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002678 substArgTypes(&fn, t.Type)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002679 case 2:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002680 substArgTypes(&fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002681 }
2682 return fn
2683}
2684
2685func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002686 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002687 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002688 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002689 fn := syslook(name)
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08002690 substArgTypes(&fn, t.Key(), t.Type, t.Key(), t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002691 return fn
2692}
2693
2694func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002695 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002696 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002697 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002698 fn := syslook(name)
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08002699 substArgTypes(&fn, t.Key(), t.Type, t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002700 return fn
2701}
2702
2703func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002704 fn := syslook(name)
2705 substArgTypes(&fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002706 return fn
2707}
2708
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002709func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002710 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002711 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002712
2713 if c < 2 {
2714 Yyerror("addstr count %d too small", c)
2715 }
2716
Russ Cox382b44e2015-02-23 16:07:24 -05002717 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002718 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002719 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002720 for _, n1 := range n.List.Slice() {
2721 if n1.Op == OLITERAL {
2722 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002723 }
2724 }
2725
2726 // Don't allocate the buffer if the result won't fit.
2727 if sz < tmpstringbufsize {
2728 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002729 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002730
2731 buf = Nod(OADDR, temp(t), nil)
2732 }
2733 }
2734
2735 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002736 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002737 for _, n2 := range n.List.Slice() {
2738 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002739 }
2740
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002741 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002742 if c <= 5 {
2743 // small numbers of strings use direct runtime helpers.
2744 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002745 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002746 } else {
2747 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002748 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002749
Russ Cox382b44e2015-02-23 16:07:24 -05002750 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002751 t.Type = Types[TSTRING]
2752 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002753 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002754 if prealloc[n] != nil {
2755 prealloc[slice] = prealloc[n]
2756 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002757 slice.List.Set(args[1:]) // skip buf arg
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002758 args = []*Node{buf}
2759 args = append(args, slice)
Russ Cox8c195bd2015-02-13 14:40:36 -05002760 slice.Esc = EscNone
2761 }
2762
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002763 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002764 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002765 r.List.Set(args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002766 typecheck(&r, Erv)
2767 walkexpr(&r, init)
2768 r.Type = n.Type
2769
2770 return r
2771}
2772
2773// expand append(l1, l2...) to
2774// init {
2775// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002776// n := len(s) + len(l2)
2777// // Compare as uint so growslice can panic on overflow.
2778// if uint(n) > uint(cap(s)) {
2779// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002780// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002781// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002782// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2783// }
2784// s
2785//
2786// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002787func appendslice(n *Node, init *Nodes) *Node {
2788 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002789
2790 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2791 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002792 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002793 ls := n.List.Slice()
2794 for i1, n1 := range ls {
2795 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002796 }
2797
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002798 l1 := n.List.First()
2799 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002800
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002801 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002802
2803 // var s []T
2804 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002805 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002806
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002807 // n := len(s) + len(l2)
2808 nn := temp(Types[TINT])
2809 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002810
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002811 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002812 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002813 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2814 nif.Left.Left.Type = Types[TUINT]
2815 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002816
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002817 // instantiate growslice(Type*, []any, int) []any
2818 fn := syslook("growslice")
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002819 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002820
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002821 // s = growslice(T, s, n)
2822 nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nn)))
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002823 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002824
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002825 // s = s[:n]
2826 nt := Nod(OSLICE, s, Nod(OKEY, nil, nn))
2827 nt.Etype = 1
2828 l = append(l, Nod(OAS, s, nt))
2829
Russ Cox8c195bd2015-02-13 14:40:36 -05002830 if haspointers(l1.Type.Type) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002831 // copy(s[len(l1):], l2)
2832 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002833
2834 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002835 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002836 fn := syslook("typedslicecopy")
2837 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002838 var ln Nodes
2839 ln.Set(l)
2840 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Type), nptr1, nptr2)
2841 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002842 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002843 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002844 // copy(s[len(l1):], l2)
2845 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002846
2847 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002848 nptr2 := l2
2849 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002850 if l2.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002851 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002852 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002853 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002854 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002855 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002856 var ln Nodes
2857 ln.Set(l)
2858 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
2859 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002860 } else {
2861 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002862 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002863 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002864
Russ Cox8c195bd2015-02-13 14:40:36 -05002865 nptr1 = Nod(OADDR, nptr1, nil)
2866
Russ Cox382b44e2015-02-23 16:07:24 -05002867 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002868
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002869 fn := syslook("memmove")
2870 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002871
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002872 var ln Nodes
2873 ln.Set(l)
2874 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002875
2876 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002877 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2878 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002879 }
2880
Russ Cox8c195bd2015-02-13 14:40:36 -05002881 typechecklist(l, Etop)
2882 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002883 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002884 return s
2885}
2886
Russ Cox85520472015-05-06 12:34:30 -04002887// Rewrite append(src, x, y, z) so that any side effects in
2888// x, y, z (including runtime panics) are evaluated in
2889// initialization statements before the append.
2890// For normal code generation, stop there and leave the
2891// rest to cgen_append.
2892//
2893// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002894//
2895// init {
2896// s := src
2897// const argc = len(args) - 1
2898// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002899// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002900// }
2901// n := len(s)
2902// s = s[:n+argc]
2903// s[n] = a
2904// s[n+1] = b
2905// ...
2906// }
2907// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002908func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002909 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002910 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
2911 walkexpr(n.List.Addr(0), init)
Russ Cox85520472015-05-06 12:34:30 -04002912 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002913 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002914
2915 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2916 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002917 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002918 // Using cheapexpr also makes sure that the evaluation
2919 // of all arguments (and especially any panics) happen
2920 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002921 ls := n.List.Slice()[1:]
2922 for i, n := range ls {
2923 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002924 }
2925
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002926 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002927
2928 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002929 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002930 nsrc.Type = nsrc.Type.Type.Type
2931 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002932 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002933 if argc < 1 {
2934 return nsrc
2935 }
2936
Russ Cox85520472015-05-06 12:34:30 -04002937 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002938 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002939 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002940 return n
2941 }
2942
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002943 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002944
Russ Cox382b44e2015-02-23 16:07:24 -05002945 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002946 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002947
Russ Cox382b44e2015-02-23 16:07:24 -05002948 na := Nodintconst(int64(argc)) // const argc
2949 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002950 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002951
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002952 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
2953 substArgTypes(&fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002954
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08002955 nx.Nbody.Set1(Nod(OAS, ns,
2956 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns,
2957 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002958
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002959 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05002960
Russ Cox382b44e2015-02-23 16:07:24 -05002961 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002962 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05002963
2964 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
2965 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002966 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05002967
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002968 ls = n.List.Slice()[1:]
2969 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05002970 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05002971 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002972 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
2973 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002974 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002975 }
2976 }
2977
2978 typechecklist(l, Etop)
2979 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002980 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002981 return ns
2982}
2983
2984// Lower copy(a, b) to a memmove call or a runtime call.
2985//
2986// init {
2987// n := len(a)
2988// if n > len(b) { n = len(b) }
2989// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
2990// }
2991// n;
2992//
2993// Also works if b is a string.
2994//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002995func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002996 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05002997 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002998 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
2999 }
3000
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003001 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003002 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003003 if n.Right.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003004 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003005 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003006 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003007 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003008 substArgTypes(&fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003009 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3010 }
3011
3012 walkexpr(&n.Left, init)
3013 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003014 nl := temp(n.Left.Type)
3015 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003016 var l []*Node
3017 l = append(l, Nod(OAS, nl, n.Left))
3018 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003019
Russ Cox382b44e2015-02-23 16:07:24 -05003020 nfrm := Nod(OSPTR, nr, nil)
3021 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003022
Russ Cox382b44e2015-02-23 16:07:24 -05003023 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003024
3025 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003026 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003027
3028 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003029 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003030
Russ Cox66be1482015-05-26 21:30:20 -04003031 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003032 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003033 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003034
3035 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003036 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003037
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003038 substArgTypes(&fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003039 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003040 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003041 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003042 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003043
3044 typechecklist(l, Etop)
3045 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003046 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003047 return nlen
3048}
3049
Russ Cox8c195bd2015-02-13 14:40:36 -05003050func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003051 // Should only arrive here with large memory or
3052 // a struct/array containing a non-memory field/element.
3053 // Small memory is handled inline, and single non-memory
3054 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003055 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003056
3057 if a != AMEM && a != -1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003058 Fatalf("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003059 }
3060
3061 if a == AMEM {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003062 n := syslook("memequal")
3063 substArgTypes(&n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003064 *needsize = 1
3065 return n
3066 }
3067
Russ Cox382b44e2015-02-23 16:07:24 -05003068 sym := typesymprefix(".eq", t)
3069 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003070 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003071 ntype := Nod(OTFUNC, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003072 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3073 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3074 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003075 typecheck(&ntype, Etype)
3076 n.Type = ntype.Type
3077 *needsize = 0
3078 return n
3079}
3080
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003081func walkcompare(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003082 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003083
3084 // Given interface value l and concrete value r, rewrite
3085 // l == r
3086 // to
3087 // x, ok := l.(type(r)); ok && x == r
3088 // Handle != similarly.
3089 // This avoids the allocation that would be required
3090 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003091 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003092
Russ Cox175929b2015-03-02 14:22:05 -05003093 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003094 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003095 l = n.Left
3096 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003097 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003098 l = n.Right
3099 r = n.Left
3100 }
3101
3102 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003103 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003104 if haspointers(r.Type) {
3105 a := Nod(OAS, x, nil)
3106 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003107 init.Append(a)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003108 }
Russ Cox382b44e2015-02-23 16:07:24 -05003109 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003110
3111 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003112 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003113
3114 a.Type = r.Type
3115
3116 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003117 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003118
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003119 expr.List.Append(x)
3120 expr.List.Append(ok)
3121 expr.Rlist.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003122 typecheck(&expr, Etop)
3123 walkexpr(&expr, init)
3124
3125 if n.Op == OEQ {
3126 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3127 } else {
3128 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3129 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003130 init.Append(expr)
Russ Cox44928112015-03-02 20:34:22 -05003131 finishcompare(np, n, r, init)
3132 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003133 }
3134
3135 // Must be comparison of array or struct.
3136 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003137 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003138
3139 switch t.Etype {
3140 default:
3141 return
3142
3143 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003144 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003145 return
3146 }
3147
3148 case TSTRUCT:
3149 break
3150 }
3151
Russ Cox44928112015-03-02 20:34:22 -05003152 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003153 for cmpl != nil && cmpl.Op == OCONVNOP {
3154 cmpl = cmpl.Left
3155 }
Russ Cox44928112015-03-02 20:34:22 -05003156 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003157 for cmpr != nil && cmpr.Op == OCONVNOP {
3158 cmpr = cmpr.Left
3159 }
3160
Russ Coxdc7b54b2015-02-17 22:13:49 -05003161 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003162 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003163 }
3164
3165 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003166 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003167 a.Right.Etype = 1 // addr does not escape
3168 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003169 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003170
3171 r = temp(Ptrto(t))
3172 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3173 a.Right.Etype = 1 // addr does not escape
3174 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003175 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003176
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003177 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003178 if n.Op == ONE {
3179 andor = OOROR
3180 }
3181
Russ Cox44928112015-03-02 20:34:22 -05003182 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003183 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003184 // Four or fewer elements of a basic type.
3185 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003186 var li *Node
3187 var ri *Node
3188 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003189 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3190 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003191 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003192 if expr == nil {
3193 expr = a
3194 } else {
3195 expr = Nod(andor, expr, a)
3196 }
3197 }
3198
3199 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003200 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 }
Russ Cox44928112015-03-02 20:34:22 -05003202 finishcompare(np, n, expr, init)
3203 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003204 }
3205
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003206 if t.Etype == TARRAY {
3207 // Zero- or single-element array, of any type.
3208 switch t.Bound {
3209 case 0:
3210 finishcompare(np, n, Nodbool(n.Op == OEQ), init)
3211 return
3212 case 1:
3213 l0 := Nod(OINDEX, l, Nodintconst(0))
3214 r0 := Nod(OINDEX, r, Nodintconst(0))
3215 a := Nod(n.Op, l0, r0)
3216 finishcompare(np, n, a, init)
3217 return
3218 }
3219 }
3220
Russ Cox8c195bd2015-02-13 14:40:36 -05003221 if t.Etype == TSTRUCT && countfield(t) <= 4 {
3222 // Struct of four or fewer fields.
3223 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003224 var li *Node
3225 var ri *Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07003226 for _, t1 := range t.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003227 if isblanksym(t1.Sym) {
3228 continue
3229 }
3230 li = Nod(OXDOT, l, newname(t1.Sym))
3231 ri = Nod(OXDOT, r, newname(t1.Sym))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003232 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003233 if expr == nil {
3234 expr = a
3235 } else {
3236 expr = Nod(andor, expr, a)
3237 }
3238 }
3239
3240 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003241 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003242 }
Russ Cox44928112015-03-02 20:34:22 -05003243 finishcompare(np, n, expr, init)
3244 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003245 }
3246
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003247 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003248 var needsize int
3249 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003250
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003251 call.List.Append(l)
3252 call.List.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003253 if needsize != 0 {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003254 call.List.Append(Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003255 }
3256 r = call
3257 if n.Op != OEQ {
3258 r = Nod(ONOT, r, nil)
3259 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003260
Russ Cox44928112015-03-02 20:34:22 -05003261 finishcompare(np, n, r, init)
3262 return
3263}
3264
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003265func finishcompare(np **Node, n, r *Node, init *Nodes) {
Russ Cox44928112015-03-02 20:34:22 -05003266 // Using np here to avoid passing &r to typecheck.
3267 *np = r
3268 typecheck(np, Erv)
3269 walkexpr(np, init)
3270 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003271 if r.Type != n.Type {
3272 r = Nod(OCONVNOP, r, nil)
3273 r.Type = n.Type
3274 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003275 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003276 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003277}
3278
Russ Coxdc7b54b2015-02-17 22:13:49 -05003279func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003280 var ar *Node
3281 var br *Node
3282 for a != nil && b != nil && a.Op == b.Op {
3283 switch a.Op {
3284 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003285 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003286
3287 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003288 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003289
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003290 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003291 ar = a.Right
3292 br = b.Right
3293 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003294 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003295 }
3296
3297 case OINDEX:
3298 ar = a.Right
3299 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003300 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003301 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003302 }
3303 }
3304
3305 a = a.Left
3306 b = b.Left
3307 }
3308
Russ Coxdc7b54b2015-02-17 22:13:49 -05003309 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003310}
3311
3312func walkrotate(np **Node) {
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003313 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003314 return
3315 }
3316
Russ Cox382b44e2015-02-23 16:07:24 -05003317 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003318
3319 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003320 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003321
Russ Cox382b44e2015-02-23 16:07:24 -05003322 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003323 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 -05003324 return
3325 }
3326
3327 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003328 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003329 return
3330 }
3331
3332 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003333 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003334
Russ Coxdc7b54b2015-02-17 22:13:49 -05003335 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003336 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003337 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003338 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003339 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003340 // Rewrite left shift half to left rotate.
3341 if l.Op == OLSH {
3342 n = l
3343 } else {
3344 n = r
3345 }
3346 n.Op = OLROT
3347
3348 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003349 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003350
3351 if s == 0 || s == w {
3352 n = n.Left
3353 }
3354
3355 *np = n
3356 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003357 }
3358 }
3359 return
3360 }
3361
3362 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3363 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003364}
3365
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003366// walkmul rewrites integer multiplication by powers of two as shifts.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003367func walkmul(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003368 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003369 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003370 return
3371 }
3372
Russ Cox382b44e2015-02-23 16:07:24 -05003373 var nr *Node
3374 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003375 if n.Right.Op == OLITERAL {
3376 nl = n.Left
3377 nr = n.Right
3378 } else if n.Left.Op == OLITERAL {
3379 nl = n.Right
3380 nr = n.Left
3381 } else {
3382 return
3383 }
3384
Russ Cox382b44e2015-02-23 16:07:24 -05003385 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003386
3387 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003388 var pow int
3389 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003390 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003391 cheapexpr(nl, init)
3392 Nodconst(n, n.Type, 0)
3393 goto ret
3394 }
3395
3396 // nr is a constant.
3397 pow = powtwo(nr)
3398
3399 if pow < 0 {
3400 return
3401 }
3402 if pow >= 1000 {
3403 // negative power of 2, like -16
3404 neg = 1
3405
3406 pow -= 1000
3407 }
3408
3409 w = int(nl.Type.Width * 8)
3410 if pow+1 >= w { // too big, shouldn't happen
3411 return
3412 }
3413
3414 nl = cheapexpr(nl, init)
3415
3416 if pow == 0 {
3417 // x*1 is x
3418 n = nl
3419
3420 goto ret
3421 }
3422
3423 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3424
3425ret:
3426 if neg != 0 {
3427 n = Nod(OMINUS, n, nil)
3428 }
3429
3430 typecheck(&n, Erv)
3431 walkexpr(&n, init)
3432 *np = n
3433}
3434
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003435// walkdiv rewrites division by a constant as less expensive
3436// operations.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003437func walkdiv(np **Node, init *Nodes) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003438 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003439
3440 // TODO(minux)
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003441 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003442 return
3443 }
3444
Russ Cox382b44e2015-02-23 16:07:24 -05003445 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003446 if n.Right.Op != OLITERAL {
3447 return
3448 }
3449
3450 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003451 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003452
Russ Cox382b44e2015-02-23 16:07:24 -05003453 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003454
3455 // special cases of mod/div
3456 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003457 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003458
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003459 s := 0 // 1 if nr is negative.
3460 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003461 if pow >= 1000 {
3462 // negative power of 2
3463 s = 1
3464
3465 pow -= 1000
3466 }
3467
3468 if pow+1 >= w {
3469 // divisor too large.
3470 return
3471 }
3472
3473 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003474 // try to do division by multiply by (2^w)/d
3475 // see hacker's delight chapter 10
3476 // TODO: support 64-bit magic multiply here.
3477 var m Magic
3478 m.W = w
3479
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003480 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003481 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003482 Smagic(&m)
3483 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003484 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003485 Umagic(&m)
3486 }
3487
3488 if m.Bad != 0 {
3489 return
3490 }
3491
3492 // We have a quick division method so use it
3493 // for modulo too.
3494 if n.Op == OMOD {
3495 // rewrite as A%B = A - (A/B*B).
3496 n1 := Nod(ODIV, nl, nr)
3497
3498 n2 := Nod(OMUL, n1, nr)
3499 n = Nod(OSUB, nl, n2)
3500 goto ret
3501 }
3502
3503 switch Simtype[nl.Type.Etype] {
3504 default:
3505 return
3506
3507 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003508 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003509 nc := Nod(OXXX, nil, nil)
3510
3511 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003512 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003513 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003514 if m.Ua != 0 {
3515 // Select a Go type with (at least) twice the width.
3516 var twide *Type
3517 switch Simtype[nl.Type.Etype] {
3518 default:
3519 return
3520
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003521 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003522 twide = Types[TUINT32]
3523
3524 case TUINT32:
3525 twide = Types[TUINT64]
3526
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003527 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003528 twide = Types[TINT32]
3529
3530 case TINT32:
3531 twide = Types[TINT64]
3532 }
3533
3534 // add numerator (might overflow).
3535 // n2 = (n1 + nl)
3536 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3537
3538 // shift by m.s
3539 nc := Nod(OXXX, nil, nil)
3540
3541 Nodconst(nc, Types[TUINT], int64(m.S))
3542 n = conv(Nod(ORSH, n2, nc), nl.Type)
3543 } else {
3544 // n = n1 >> m.s
3545 nc := Nod(OXXX, nil, nil)
3546
3547 Nodconst(nc, Types[TUINT], int64(m.S))
3548 n = Nod(ORSH, n1, nc)
3549 }
3550
3551 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003552 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003553 nc := Nod(OXXX, nil, nil)
3554
3555 Nodconst(nc, nl.Type, m.Sm)
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.Sm < 0 {
3559 // add the numerator.
3560 n1 = Nod(OADD, n1, nl)
3561 }
3562
3563 // shift by m.s
3564 nc = Nod(OXXX, nil, nil)
3565
3566 Nodconst(nc, Types[TUINT], int64(m.S))
3567 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3568
3569 // add 1 iff n1 is negative.
3570 nc = Nod(OXXX, nil, nil)
3571
3572 Nodconst(nc, Types[TUINT], int64(w)-1)
3573 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3574 n = Nod(OSUB, n2, n3)
3575
3576 // apply sign.
3577 if m.Sd < 0 {
3578 n = Nod(OMINUS, n, nil)
3579 }
3580 }
3581
3582 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003583 }
3584
3585 switch pow {
3586 case 0:
3587 if n.Op == OMOD {
3588 // nl % 1 is zero.
3589 Nodconst(n, n.Type, 0)
3590 } else if s != 0 {
3591 // divide by -1
3592 n.Op = OMINUS
3593
3594 n.Right = nil
3595 } else {
3596 // divide by 1
3597 n = nl
3598 }
3599
3600 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003601 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003602 if n.Op == OMOD {
3603 // signed modulo 2^pow is like ANDing
3604 // with the last pow bits, but if nl < 0,
3605 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003606 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003607
3608 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003609 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003610 if pow == 1 {
3611 typecheck(&n1, Erv)
3612 n1 = cheapexpr(n1, init)
3613
3614 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003615 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003616
Russ Cox382b44e2015-02-23 16:07:24 -05003617 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003618 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003619 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003620 n = Nod(OADD, n3, n1)
3621 } else {
3622 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003623 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003624
3625 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003626 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003627 typecheck(&n2, Erv)
3628 n2 = cheapexpr(n2, init)
3629
Russ Cox382b44e2015-02-23 16:07:24 -05003630 n3 := Nod(OADD, nl, n2)
3631 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003632 n = Nod(OSUB, n4, n2)
3633 }
3634
3635 break
3636 } else {
3637 // arithmetic right shift does not give the correct rounding.
3638 // if nl >= 0, nl >> n == nl / nr
3639 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003640 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003641
3642 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003643 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003644 if pow == 1 {
3645 // nl+1 is nl-(-1)
3646 n.Left = Nod(OSUB, nl, n1)
3647 } else {
3648 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003649 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003650
3651 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003652 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003653 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3654 }
3655
3656 // n = (nl + 2^pow-1) >> pow
3657 n.Op = ORSH
3658
3659 nc = Nod(OXXX, nil, nil)
3660 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3661 n.Right = nc
3662 n.Typecheck = 0
3663 }
3664
3665 if s != 0 {
3666 n = Nod(OMINUS, n, nil)
3667 }
3668 break
3669 }
3670
Russ Cox382b44e2015-02-23 16:07:24 -05003671 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003672 if n.Op == OMOD {
3673 // n = nl & (nr-1)
3674 n.Op = OAND
3675
Russ Cox81d58102015-05-27 00:47:05 -04003676 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003677 } else {
3678 // n = nl >> pow
3679 n.Op = ORSH
3680
3681 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3682 }
3683
3684 n.Typecheck = 0
3685 n.Right = nc
3686 }
3687
3688 goto ret
3689
Russ Cox8c195bd2015-02-13 14:40:36 -05003690ret:
3691 typecheck(&n, Erv)
3692 walkexpr(&n, init)
3693 *np = n
3694}
3695
3696// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003697func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003698 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003699 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003700 }
3701
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003702 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003703 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003704
Russ Coxdc7b54b2015-02-17 22:13:49 -05003705 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003706 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003707 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003708 }
3709
3710 switch n.Op {
3711 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003712 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003713 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003714 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003715 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003716 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003717 }
3718
3719 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003720 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003721 }
3722
3723 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003724 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003725 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003726 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003727 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003728 }
3729 }
3730
3731 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003732 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003733 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003734 for bits > 0 && v >= 2 {
3735 bits--
3736 v >>= 1
3737 }
3738 }
3739
3740 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003741 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003742 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003743 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003744 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003745 }
3746 bits -= int32(v)
3747 }
3748 }
3749
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003750 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003751 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003752 }
3753
Russ Coxdc7b54b2015-02-17 22:13:49 -05003754 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003755}
3756
David Crawshawcc158402016-03-10 16:15:26 -05003757// usemethod check interface method calls for uses of reflect.Type.Method.
3758func usemethod(n *Node) {
3759 t := n.Left.Type
3760
3761 // Looking for either of:
3762 // Method(int) reflect.Method
3763 // MethodByName(string) (reflect.Method, bool)
3764 //
3765 // TODO(crawshaw): improve precision of match by working out
3766 // how to check the method name.
3767 if n := countfield(t.Params()); n != 1 {
3768 return
3769 }
3770 if n := countfield(t.Results()); n != 1 && n != 2 {
3771 return
3772 }
3773 p0 := t.Params().Field(0)
3774 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003775 var res1 *Field
David Crawshawcc158402016-03-10 16:15:26 -05003776 if countfield(t.Results()) == 2 {
3777 res1 = t.Results().Field(1)
3778 }
3779
3780 if res1 == nil {
3781 if p0.Type.Etype != TINT {
3782 return
3783 }
3784 } else {
3785 if p0.Type.Etype != TSTRING {
3786 return
3787 }
3788 if res1.Type.Etype != TBOOL {
3789 return
3790 }
3791 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003792 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003793 return
3794 }
3795
3796 Curfn.Func.ReflectMethod = true
3797}
3798
Russ Cox8c195bd2015-02-13 14:40:36 -05003799func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003800 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003801 return
3802 }
3803
3804 switch n.Op {
3805 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08003806 Fatalf("usefield %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003807
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003808 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003809 break
3810 }
Keith Randall71d13a82016-03-02 20:54:41 -08003811 if n.Right == nil {
3812 // No field name. This DOTPTR was built by the compiler for access
3813 // to runtime data structures. Ignore.
3814 return
3815 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003816
Russ Cox496ad0a2015-05-26 21:49:31 -04003817 t := n.Left.Type
3818 if Isptr[t.Etype] {
3819 t = t.Type
3820 }
Russ Coxf68d1df2015-08-17 21:38:46 -04003821 field := dotField[typeSym{t.Orig, n.Right.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003822 if field == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003823 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003824 }
Russ Coxbed1f902015-03-02 16:03:26 -05003825 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003826 return
3827 }
3828
Matthew Dempskya2a48062016-03-10 16:15:44 -08003829 outer := n.Left.Type
3830 if Isptr[outer.Etype] {
3831 outer = outer.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003832 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003833 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003834 Yyerror("tracked field must be in named struct type")
3835 }
3836 if !exportname(field.Sym.Name) {
3837 Yyerror("tracked field must be exported (upper case)")
3838 }
3839
Matthew Dempskya2a48062016-03-10 16:15:44 -08003840 sym := tracksym(outer, field)
3841 if Curfn.Func.FieldTrack == nil {
3842 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
3843 }
3844 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05003845}
3846
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003847func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003848 for _, n := range l.Slice() {
3849 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003850 return false
3851 }
3852 }
3853 return true
3854}
3855
Russ Coxdc7b54b2015-02-17 22:13:49 -05003856func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003857 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003858 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003859 }
3860
3861 switch n.Op {
3862 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003863 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003864
3865 // Discardable as long as the subpieces are.
3866 case ONAME,
3867 ONONAME,
3868 OTYPE,
3869 OPACK,
3870 OLITERAL,
3871 OADD,
3872 OSUB,
3873 OOR,
3874 OXOR,
3875 OADDSTR,
3876 OADDR,
3877 OANDAND,
3878 OARRAYBYTESTR,
3879 OARRAYRUNESTR,
3880 OSTRARRAYBYTE,
3881 OSTRARRAYRUNE,
3882 OCAP,
3883 OCMPIFACE,
3884 OCMPSTR,
3885 OCOMPLIT,
3886 OMAPLIT,
3887 OSTRUCTLIT,
3888 OARRAYLIT,
3889 OPTRLIT,
3890 OCONV,
3891 OCONVIFACE,
3892 OCONVNOP,
3893 ODOT,
3894 OEQ,
3895 ONE,
3896 OLT,
3897 OLE,
3898 OGT,
3899 OGE,
3900 OKEY,
3901 OLEN,
3902 OMUL,
3903 OLSH,
3904 ORSH,
3905 OAND,
3906 OANDNOT,
3907 ONEW,
3908 ONOT,
3909 OCOM,
3910 OPLUS,
3911 OMINUS,
3912 OOROR,
3913 OPAREN,
3914 ORUNESTR,
3915 OREAL,
3916 OIMAG,
3917 OCOMPLEX:
3918 break
3919
3920 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003921 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003922 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003923 break
3924 }
Russ Cox81d58102015-05-27 00:47:05 -04003925 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003926 break
3927 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003928 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003929
3930 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003931 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003932 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003933 break
3934 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003935 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003936
3937 // Difficult to tell what sizes are okay.
3938 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003939 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003940 }
3941
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003942 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 -05003943 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003944 }
3945
Russ Coxdc7b54b2015-02-17 22:13:49 -05003946 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003947}
3948
3949// rewrite
3950// print(x, y, z)
3951// into
3952// func(a1, a2, a3) {
3953// print(a1, a2, a3)
3954// }(x, y, z)
3955// and same for println.
3956
3957var walkprintfunc_prgen int
3958
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003959func walkprintfunc(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003960 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003961
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003962 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003963 walkstmtlist(n.Ninit.Slice())
3964 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05003965 }
3966
Russ Cox382b44e2015-02-23 16:07:24 -05003967 t := Nod(OTFUNC, nil, nil)
3968 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003969 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05003970 var a *Node
3971 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003972 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003973 buf = fmt.Sprintf("a%d", num)
3974 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003975 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
3976 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003977 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05003978 }
3979
Russ Cox382b44e2015-02-23 16:07:24 -05003980 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003981 walkprintfunc_prgen++
3982 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003983 fn.Func.Nname = newname(Lookup(buf))
3984 fn.Func.Nname.Name.Defn = fn
3985 fn.Func.Nname.Name.Param.Ntype = t
3986 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003987
Russ Cox382b44e2015-02-23 16:07:24 -05003988 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05003989 Curfn = nil
3990 funchdr(fn)
3991
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003992 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003993 a.List.Set(printargs)
Russ Cox8c195bd2015-02-13 14:40:36 -05003994 typecheck(&a, Etop)
3995 walkstmt(&a)
3996
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003997 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003998
3999 funcbody(fn)
4000
4001 typecheck(&fn, Etop)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08004002 typechecklist(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08004003 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05004004 Curfn = oldfn
4005
4006 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004007 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004008 a.List.Set(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -05004009 typecheck(&a, Etop)
4010 walkexpr(&a, init)
4011 *np = a
4012}