blob: a4fa607c8fa448d99753d131609ccb62caa664b1 [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.
Matthew Dempskyc8377612016-03-17 01:47:16 -0700660 if n.Left.Type.Results().NumFields() == 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 Dempskydbed1c62016-03-17 13:26:08 -07001745 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
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
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002025 typecheckslice(calls, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002026 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
Keith Randall15ed37d2016-03-16 21:51:17 -07002149 // No write barrier for writing a sliced slice back to its
2150 // original location.
2151 if (r.Op == OSLICE || r.Op == OSLICE3 || r.Op == OSLICESTR) &&
2152 samesafeexpr(r.Left, l) {
2153 return false
2154 }
2155
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002157 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002158}
2159
2160// TODO(rsc): Perhaps componentgen should run before this.
2161
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002162func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002163 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002164 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002165 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002166 }
Russ Cox972a4782015-05-21 15:00:06 -04002167 n.Op = OASWB
2168 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002169 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002170 return n
2171}
2172
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002173func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002174 if n.Op != OAS {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002175 Fatalf("convas: not OAS %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002176 }
2177
2178 n.Typecheck = 1
2179
Russ Cox382b44e2015-02-23 16:07:24 -05002180 var lt *Type
2181 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002182 if n.Left == nil || n.Right == nil {
2183 goto out
2184 }
2185
2186 lt = n.Left.Type
2187 rt = n.Right.Type
2188 if lt == nil || rt == nil {
2189 goto out
2190 }
2191
2192 if isblank(n.Left) {
2193 defaultlit(&n.Right, nil)
2194 goto out
2195 }
2196
2197 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002198 map_ := n.Left.Left
2199 key := n.Left.Right
2200 val := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05002201 walkexpr(&map_, init)
2202 walkexpr(&key, init)
2203 walkexpr(&val, init)
2204
2205 // orderexpr made sure key and val are addressable.
2206 key = Nod(OADDR, key, nil)
2207
2208 val = Nod(OADDR, val, nil)
2209 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2210 goto out
2211 }
2212
2213 if !Eqtype(lt, rt) {
2214 n.Right = assignconv(n.Right, lt, "assignment")
2215 walkexpr(&n.Right, init)
2216 }
2217
2218out:
2219 ullmancalc(n)
2220 return n
2221}
2222
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002223// from ascompat[te]
2224// evaluating actual function arguments.
2225// f(a,b)
2226// if there is exactly one function expr,
2227// then it is done first. otherwise must
2228// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002229func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002230 c := 0 // function calls
2231 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002232
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002233 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 t++
2235 ullmancalc(n)
2236 if n.Ullman >= UINF {
2237 c++
2238 }
2239 }
2240
2241 if c == 0 || t == 1 {
2242 return all
2243 }
2244
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002245 var g []*Node // fncalls assigned to tempnames
2246 var f *Node // last fncall assigned to stack
2247 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002248 d := 0
2249 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002250 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002251 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002252 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002253 continue
2254 }
2255
2256 d++
2257 if d == c {
2258 f = n
2259 continue
2260 }
2261
2262 // make assignment of fncall to tempname
2263 a = temp(n.Right.Type)
2264
2265 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002266 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002267
2268 // put normal arg assignment on list
2269 // with fncall replaced by tempname
2270 n.Right = a.Left
2271
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002272 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002273 }
2274
2275 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002276 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002277 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002278 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002279}
2280
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002281// from ascompat[ee]
2282// a,b = c,d
2283// simultaneous assignment. there cannot
2284// be later use of an earlier lvalue.
2285//
2286// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002287func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002288 var l *Node
2289
2290 // If a needed expression may be affected by an
2291 // earlier assignment, make an early copy of that
2292 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002293 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002294
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002295 var mapinit Nodes
2296 for i, n := range all {
2297 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002298
2299 // Save subexpressions needed on left side.
2300 // Drill through non-dereferences.
2301 for {
2302 if l.Op == ODOT || l.Op == OPAREN {
2303 l = l.Left
2304 continue
2305 }
2306
Russ Coxdc7b54b2015-02-17 22:13:49 -05002307 if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002308 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002309 l = l.Left
2310 continue
2311 }
2312
2313 break
2314 }
2315
2316 switch l.Op {
2317 default:
Matthew Dempsky63142022016-03-15 13:06:58 -07002318 Fatalf("reorder3 unexpected lvalue %v", Oconv(l.Op, FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002319
2320 case ONAME:
2321 break
2322
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002323 case OINDEX, OINDEXMAP:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002324 reorder3save(&l.Left, all, i, &early)
2325 reorder3save(&l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002326 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002327 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002328 }
2329
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002330 case OIND, ODOTPTR:
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002331 reorder3save(&l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002332 }
2333
2334 // Save expression on right side.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002335 reorder3save(&all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002336 }
2337
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002338 early = append(mapinit.Slice(), early...)
2339 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002340}
2341
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002342// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002343// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002344// copy into a temporary during *early and
2345// replace *np with that temp.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002346func reorder3save(np **Node, all []*Node, i int, early *[]*Node) {
Russ Cox382b44e2015-02-23 16:07:24 -05002347 n := *np
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002348 if !aliased(n, all, i) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002349 return
2350 }
2351
Russ Cox382b44e2015-02-23 16:07:24 -05002352 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002353 q = Nod(OAS, q, n)
2354 typecheck(&q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002355 *early = append(*early, q)
Russ Cox8c195bd2015-02-13 14:40:36 -05002356 *np = q.Left
2357}
2358
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002359// what's the outer value that a write to n affects?
2360// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002361func outervalue(n *Node) *Node {
2362 for {
2363 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002364 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002365 }
2366 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2367 n = n.Left
2368 continue
2369 }
2370
Russ Coxdc7b54b2015-02-17 22:13:49 -05002371 if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002372 n = n.Left
2373 continue
2374 }
2375
2376 break
2377 }
2378
2379 return n
2380}
2381
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002382// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002383// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002384func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002385 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002386 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002387 }
2388
2389 // Look for obvious aliasing: a variable being assigned
2390 // during the all list and appearing in n.
2391 // Also record whether there are any writes to main memory.
2392 // Also record whether there are any writes to variables
2393 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002394 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002395
Russ Cox382b44e2015-02-23 16:07:24 -05002396 varwrite := 0
2397 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002398 for _, an := range all[:i] {
2399 a = outervalue(an.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05002400 if a.Op != ONAME {
2401 memwrite = 1
2402 continue
2403 }
2404
2405 switch n.Class {
2406 default:
2407 varwrite = 1
2408 continue
2409
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002410 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002411 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002412 varwrite = 1
2413 continue
2414 }
2415
Russ Coxdc7b54b2015-02-17 22:13:49 -05002416 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002417 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002418 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002419 }
2420 }
2421 }
2422
2423 // The variables being written do not appear in n.
2424 // However, n might refer to computed addresses
2425 // that are being written.
2426
2427 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002428 if memwrite == 0 && varwrite == 0 {
2429 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002430 }
2431
2432 // If n does not refer to computed addresses
2433 // (that is, if n only refers to variables whose addresses
2434 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002435 if varexpr(n) {
2436 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002437 }
2438
2439 // Otherwise, both the writes and n refer to computed memory addresses.
2440 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002441 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002442}
2443
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002444// does the evaluation of n only refer to variables
2445// whose addresses have not been taken?
2446// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002447func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002448 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002449 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002450 }
2451
2452 switch n.Op {
2453 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002454 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002455
2456 case ONAME:
2457 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002458 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002459 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002460 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002461 }
2462 }
2463
Russ Coxdc7b54b2015-02-17 22:13:49 -05002464 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002465
2466 case OADD,
2467 OSUB,
2468 OOR,
2469 OXOR,
2470 OMUL,
2471 ODIV,
2472 OMOD,
2473 OLSH,
2474 ORSH,
2475 OAND,
2476 OANDNOT,
2477 OPLUS,
2478 OMINUS,
2479 OCOM,
2480 OPAREN,
2481 OANDAND,
2482 OOROR,
Russ Cox8c195bd2015-02-13 14:40:36 -05002483 OCONV,
2484 OCONVNOP,
2485 OCONVIFACE,
2486 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002487 return varexpr(n.Left) && varexpr(n.Right)
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002488
2489 case ODOT: // but not ODOTPTR
2490 // The original code always returned false for ODOT,
2491 // because n.Right would be an ONAME with n.Class not set.
2492 // TODO(iant): Fix this to remove "&& false".
2493 return varexpr(n.Left) && false
Russ Cox8c195bd2015-02-13 14:40:36 -05002494 }
2495
2496 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002497 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002498}
2499
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002500// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002501func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002502 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002503 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002504 }
2505 switch r.Op {
2506 // match each right given left
2507 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002508 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002509
2510 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002511 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002512 }
2513
Russ Coxdc7b54b2015-02-17 22:13:49 -05002514 if vmatch2(l, r.Left) {
2515 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002516 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002517 if vmatch2(l, r.Right) {
2518 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002519 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002520 for _, n := range r.List.Slice() {
2521 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002522 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002523 }
2524 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002525 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002526}
2527
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002528// is any name mentioned in l also mentioned in r?
2529// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002530func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002531 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002532 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002533 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002534 }
2535 switch l.Op {
2536 case ONAME:
2537 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002538 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002539 break
2540
2541 // assignment to non-stack variable
2542 // must be delayed if right has function calls.
2543 default:
2544 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002545 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002546 }
2547 }
2548
2549 return vmatch2(l, r)
2550
2551 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002552 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002553 }
2554
Russ Coxdc7b54b2015-02-17 22:13:49 -05002555 if vmatch1(l.Left, r) {
2556 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002557 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002558 if vmatch1(l.Right, r) {
2559 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002560 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002561 for _, n := range l.List.Slice() {
2562 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002563 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002564 }
2565 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002566 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002567}
2568
Matthew Dempsky2339b132016-03-09 18:54:26 -08002569// paramstoheap returns code to allocate memory for heap-escaped parameters
2570// and to copy non-result prameters' values from the stack.
2571// If out is true, then code is also produced to zero-initialize their
2572// stack memory addresses.
2573func paramstoheap(params *Type, out bool) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002574 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002575 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002576 v := t.Nname
2577 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
Russ Cox8c195bd2015-02-13 14:40:36 -05002578 v = nil
2579 }
2580
2581 // For precise stacks, the garbage collector assumes results
2582 // are always live, so zero them always.
Matthew Dempsky2339b132016-03-09 18:54:26 -08002583 if out {
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 // Defer might stop a panic and show the
2585 // return values as they exist at the time of panic.
2586 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002587 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002588 }
2589
Russ Coxdc7b54b2015-02-17 22:13:49 -05002590 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002591 continue
2592 }
2593
2594 // generate allocation & copying code
2595 if compiling_runtime != 0 {
Russ Cox17228f42015-04-17 12:03:22 -04002596 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002597 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002598 if prealloc[v] == nil {
2599 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002600 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002601 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002602 if v.Class&^PHEAP != PPARAMOUT {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002603 as := Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002604 v.Name.Param.Stackparam.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002605 typecheck(&as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002606 as = applywritebarrier(as)
2607 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002608 }
2609 }
2610
2611 return nn
2612}
2613
Matthew Dempsky2339b132016-03-09 18:54:26 -08002614// returnsfromheap returns code to copy values for heap-escaped parameters
2615// back to the stack.
2616func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002617 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002618 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002619 v := t.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -05002620 if v == nil || v.Class != PHEAP|PPARAMOUT {
2621 continue
2622 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002623 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002624 }
2625
2626 return nn
2627}
2628
Matthew Dempsky2339b132016-03-09 18:54:26 -08002629// heapmoves generates code to handle migrating heap-escaped parameters
2630// between the stack and the heap. The generated code is added to Curfn's
2631// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002632func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002633 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002634 lineno = Curfn.Lineno
Matthew Dempskyf91b8322016-03-09 20:54:59 -08002635 nn := paramstoheap(Curfn.Type.Recvs(), false)
Matthew Dempsky2339b132016-03-09 18:54:26 -08002636 nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...)
2637 nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002638 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002639 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002640 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002641 lineno = lno
2642}
2643
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002644func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002645 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002646 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002647 }
2648
Matthew Dempskyc8377612016-03-17 01:47:16 -07002649 n := fn.Type.Params().NumFields()
Russ Cox8c195bd2015-02-13 14:40:36 -05002650
Russ Cox382b44e2015-02-23 16:07:24 -05002651 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002652 r.List.Set(va[:n])
Matthew Dempskyc8377612016-03-17 01:47:16 -07002653 if fn.Type.Results().NumFields() > 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002654 typecheck(&r, Erv|Efnstruct)
2655 } else {
2656 typecheck(&r, Etop)
2657 }
2658 walkexpr(&r, init)
2659 r.Type = t
2660 return r
2661}
2662
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002663func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002664 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002665}
2666
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002667func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002668 return vmkcall(fn, t, init, args)
2669}
2670
2671func conv(n *Node, t *Type) *Node {
2672 if Eqtype(n.Type, t) {
2673 return n
2674 }
2675 n = Nod(OCONV, n, nil)
2676 n.Type = t
2677 typecheck(&n, Erv)
2678 return n
2679}
2680
2681func chanfn(name string, n int, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002682 if t.Etype != TCHAN {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002683 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002684 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002685 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002686 switch n {
2687 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002688 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002689 case 1:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002690 substArgTypes(&fn, t.Type)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002691 case 2:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002692 substArgTypes(&fn, t.Type, t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002693 }
2694 return fn
2695}
2696
2697func mapfn(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002698 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002699 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002700 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002701 fn := syslook(name)
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08002702 substArgTypes(&fn, t.Key(), t.Type, t.Key(), t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002703 return fn
2704}
2705
2706func mapfndel(name string, t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002707 if t.Etype != TMAP {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002708 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002709 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002710 fn := syslook(name)
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08002711 substArgTypes(&fn, t.Key(), t.Type, t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002712 return fn
2713}
2714
2715func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002716 fn := syslook(name)
2717 substArgTypes(&fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002718 return fn
2719}
2720
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002721func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002722 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002723 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002724
2725 if c < 2 {
2726 Yyerror("addstr count %d too small", c)
2727 }
2728
Russ Cox382b44e2015-02-23 16:07:24 -05002729 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002730 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002731 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002732 for _, n1 := range n.List.Slice() {
2733 if n1.Op == OLITERAL {
2734 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002735 }
2736 }
2737
2738 // Don't allocate the buffer if the result won't fit.
2739 if sz < tmpstringbufsize {
2740 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002741 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002742
2743 buf = Nod(OADDR, temp(t), nil)
2744 }
2745 }
2746
2747 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002748 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002749 for _, n2 := range n.List.Slice() {
2750 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002751 }
2752
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002753 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002754 if c <= 5 {
2755 // small numbers of strings use direct runtime helpers.
2756 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002757 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002758 } else {
2759 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002760 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002761
Russ Cox382b44e2015-02-23 16:07:24 -05002762 t := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05002763 t.Type = Types[TSTRING]
2764 t.Bound = -1
Russ Cox382b44e2015-02-23 16:07:24 -05002765 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002766 if prealloc[n] != nil {
2767 prealloc[slice] = prealloc[n]
2768 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002769 slice.List.Set(args[1:]) // skip buf arg
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002770 args = []*Node{buf}
2771 args = append(args, slice)
Russ Cox8c195bd2015-02-13 14:40:36 -05002772 slice.Esc = EscNone
2773 }
2774
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002775 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002776 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002777 r.List.Set(args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002778 typecheck(&r, Erv)
2779 walkexpr(&r, init)
2780 r.Type = n.Type
2781
2782 return r
2783}
2784
2785// expand append(l1, l2...) to
2786// init {
2787// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002788// n := len(s) + len(l2)
2789// // Compare as uint so growslice can panic on overflow.
2790// if uint(n) > uint(cap(s)) {
2791// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002792// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002793// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002794// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2795// }
2796// s
2797//
2798// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002799func appendslice(n *Node, init *Nodes) *Node {
2800 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002801
2802 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2803 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002804 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002805 ls := n.List.Slice()
2806 for i1, n1 := range ls {
2807 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002808 }
2809
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002810 l1 := n.List.First()
2811 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002812
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002813 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002814
2815 // var s []T
2816 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002817 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002818
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002819 // n := len(s) + len(l2)
2820 nn := temp(Types[TINT])
2821 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002822
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002823 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002824 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002825 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2826 nif.Left.Left.Type = Types[TUINT]
2827 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002828
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002829 // instantiate growslice(Type*, []any, int) []any
2830 fn := syslook("growslice")
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002831 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002832
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002833 // s = growslice(T, s, n)
2834 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 -08002835 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002836
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002837 // s = s[:n]
2838 nt := Nod(OSLICE, s, Nod(OKEY, nil, nn))
2839 nt.Etype = 1
2840 l = append(l, Nod(OAS, s, nt))
2841
Russ Cox8c195bd2015-02-13 14:40:36 -05002842 if haspointers(l1.Type.Type) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002843 // copy(s[len(l1):], l2)
2844 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002845
2846 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002847 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002848 fn := syslook("typedslicecopy")
2849 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002850 var ln Nodes
2851 ln.Set(l)
2852 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Type), nptr1, nptr2)
2853 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002854 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002855 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002856 // copy(s[len(l1):], l2)
2857 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002858
2859 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002860 nptr2 := l2
2861 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002862 if l2.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002863 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002864 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002865 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002866 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002867 substArgTypes(&fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002868 var ln Nodes
2869 ln.Set(l)
2870 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
2871 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002872 } else {
2873 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002874 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002875 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002876
Russ Cox8c195bd2015-02-13 14:40:36 -05002877 nptr1 = Nod(OADDR, nptr1, nil)
2878
Russ Cox382b44e2015-02-23 16:07:24 -05002879 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002880
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002881 fn := syslook("memmove")
2882 substArgTypes(&fn, s.Type.Type, s.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002883
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002884 var ln Nodes
2885 ln.Set(l)
2886 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002887
2888 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002889 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2890 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002891 }
2892
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002893 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002894 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002895 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002896 return s
2897}
2898
Russ Cox85520472015-05-06 12:34:30 -04002899// Rewrite append(src, x, y, z) so that any side effects in
2900// x, y, z (including runtime panics) are evaluated in
2901// initialization statements before the append.
2902// For normal code generation, stop there and leave the
2903// rest to cgen_append.
2904//
2905// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002906//
2907// init {
2908// s := src
2909// const argc = len(args) - 1
2910// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002911// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002912// }
2913// n := len(s)
2914// s = s[:n+argc]
2915// s[n] = a
2916// s[n+1] = b
2917// ...
2918// }
2919// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002920func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002921 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002922 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
2923 walkexpr(n.List.Addr(0), init)
Russ Cox85520472015-05-06 12:34:30 -04002924 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002925 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002926
2927 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2928 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002929 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002930 // Using cheapexpr also makes sure that the evaluation
2931 // of all arguments (and especially any panics) happen
2932 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002933 ls := n.List.Slice()[1:]
2934 for i, n := range ls {
2935 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002936 }
2937
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002938 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002939
2940 // Resolve slice type of multi-valued return.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002941 if Istype(nsrc.Type, TSTRUCT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002942 nsrc.Type = nsrc.Type.Type.Type
2943 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002944 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002945 if argc < 1 {
2946 return nsrc
2947 }
2948
Russ Cox85520472015-05-06 12:34:30 -04002949 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002950 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002951 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002952 return n
2953 }
2954
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002955 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002956
Russ Cox382b44e2015-02-23 16:07:24 -05002957 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002958 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002959
Russ Cox382b44e2015-02-23 16:07:24 -05002960 na := Nodintconst(int64(argc)) // const argc
2961 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002962 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002963
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002964 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
2965 substArgTypes(&fn, ns.Type.Type, ns.Type.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002966
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08002967 nx.Nbody.Set1(Nod(OAS, ns,
2968 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns,
2969 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002970
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002971 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05002972
Russ Cox382b44e2015-02-23 16:07:24 -05002973 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002974 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05002975
2976 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
2977 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002978 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05002979
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002980 ls = n.List.Slice()[1:]
2981 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05002982 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05002983 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002984 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
2985 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002986 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002987 }
2988 }
2989
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002990 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002991 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002992 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002993 return ns
2994}
2995
2996// Lower copy(a, b) to a memmove call or a runtime call.
2997//
2998// init {
2999// n := len(a)
3000// if n > len(b) { n = len(b) }
3001// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3002// }
3003// n;
3004//
3005// Also works if b is a string.
3006//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003007func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003008 if haspointers(n.Left.Type.Type) {
Russ Cox382b44e2015-02-23 16:07:24 -05003009 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003010 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
3011 }
3012
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003013 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003014 var fn *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003015 if n.Right.Type.Etype == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003016 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003017 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003018 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003019 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003020 substArgTypes(&fn, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05003021 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
3022 }
3023
3024 walkexpr(&n.Left, init)
3025 walkexpr(&n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003026 nl := temp(n.Left.Type)
3027 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003028 var l []*Node
3029 l = append(l, Nod(OAS, nl, n.Left))
3030 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003031
Russ Cox382b44e2015-02-23 16:07:24 -05003032 nfrm := Nod(OSPTR, nr, nil)
3033 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003034
Russ Cox382b44e2015-02-23 16:07:24 -05003035 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003036
3037 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003038 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003039
3040 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003041 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003042
Russ Cox66be1482015-05-26 21:30:20 -04003043 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003044 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003045 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003046
3047 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003048 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003049
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003050 substArgTypes(&fn, nl.Type.Type, nl.Type.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05003051 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003052 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003053 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003054 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003055
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003056 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003057 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003058 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003059 return nlen
3060}
3061
Russ Cox8c195bd2015-02-13 14:40:36 -05003062func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003063 // Should only arrive here with large memory or
3064 // a struct/array containing a non-memory field/element.
3065 // Small memory is handled inline, and single non-memory
3066 // is handled during type check (OCMPSTR etc).
Russ Cox382b44e2015-02-23 16:07:24 -05003067 a := algtype1(t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003068
3069 if a != AMEM && a != -1 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003070 Fatalf("eqfor %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003071 }
3072
3073 if a == AMEM {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003074 n := syslook("memequal")
3075 substArgTypes(&n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003076 *needsize = 1
3077 return n
3078 }
3079
Russ Cox382b44e2015-02-23 16:07:24 -05003080 sym := typesymprefix(".eq", t)
3081 n := newname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003082 n.Class = PFUNC
Russ Cox382b44e2015-02-23 16:07:24 -05003083 ntype := Nod(OTFUNC, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003084 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3085 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3086 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
Russ Cox8c195bd2015-02-13 14:40:36 -05003087 typecheck(&ntype, Etype)
3088 n.Type = ntype.Type
3089 *needsize = 0
3090 return n
3091}
3092
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003093func walkcompare(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003094 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003095
3096 // Given interface value l and concrete value r, rewrite
3097 // l == r
3098 // to
3099 // x, ok := l.(type(r)); ok && x == r
3100 // Handle != similarly.
3101 // This avoids the allocation that would be required
3102 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003103 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003104
Russ Cox175929b2015-03-02 14:22:05 -05003105 var r *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05003106 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003107 l = n.Left
3108 r = n.Right
Russ Coxdc7b54b2015-02-17 22:13:49 -05003109 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003110 l = n.Right
3111 r = n.Left
3112 }
3113
3114 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003115 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003116 if haspointers(r.Type) {
3117 a := Nod(OAS, x, nil)
3118 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003119 init.Append(a)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003120 }
Russ Cox382b44e2015-02-23 16:07:24 -05003121 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003122
3123 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003124 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003125
3126 a.Type = r.Type
3127
3128 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003129 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003130
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003131 expr.List.Append(x)
3132 expr.List.Append(ok)
3133 expr.Rlist.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003134 typecheck(&expr, Etop)
3135 walkexpr(&expr, init)
3136
3137 if n.Op == OEQ {
3138 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3139 } else {
3140 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3141 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003142 init.Append(expr)
Russ Cox44928112015-03-02 20:34:22 -05003143 finishcompare(np, n, r, init)
3144 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003145 }
3146
3147 // Must be comparison of array or struct.
3148 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003149 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003150
3151 switch t.Etype {
3152 default:
3153 return
3154
3155 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003156 if Isslice(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003157 return
3158 }
3159
3160 case TSTRUCT:
3161 break
3162 }
3163
Russ Cox44928112015-03-02 20:34:22 -05003164 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003165 for cmpl != nil && cmpl.Op == OCONVNOP {
3166 cmpl = cmpl.Left
3167 }
Russ Cox44928112015-03-02 20:34:22 -05003168 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003169 for cmpr != nil && cmpr.Op == OCONVNOP {
3170 cmpr = cmpr.Left
3171 }
3172
Russ Coxdc7b54b2015-02-17 22:13:49 -05003173 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003174 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003175 }
3176
3177 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003178 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003179 a.Right.Etype = 1 // addr does not escape
3180 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003181 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003182
3183 r = temp(Ptrto(t))
3184 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3185 a.Right.Etype = 1 // addr does not escape
3186 typecheck(&a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003187 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003188
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003189 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003190 if n.Op == ONE {
3191 andor = OOROR
3192 }
3193
Russ Cox44928112015-03-02 20:34:22 -05003194 var expr *Node
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003195 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003196 // Four or fewer elements of a basic type.
3197 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003198 var li *Node
3199 var ri *Node
3200 for i := 0; int64(i) < t.Bound; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3202 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003203 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003204 if expr == nil {
3205 expr = a
3206 } else {
3207 expr = Nod(andor, expr, a)
3208 }
3209 }
3210
3211 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003212 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003213 }
Russ Cox44928112015-03-02 20:34:22 -05003214 finishcompare(np, n, expr, init)
3215 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003216 }
3217
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003218 if t.Etype == TARRAY {
3219 // Zero- or single-element array, of any type.
3220 switch t.Bound {
3221 case 0:
3222 finishcompare(np, n, Nodbool(n.Op == OEQ), init)
3223 return
3224 case 1:
3225 l0 := Nod(OINDEX, l, Nodintconst(0))
3226 r0 := Nod(OINDEX, r, Nodintconst(0))
3227 a := Nod(n.Op, l0, r0)
3228 finishcompare(np, n, a, init)
3229 return
3230 }
3231 }
3232
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003233 if t.Etype == TSTRUCT && t.NumFields() <= 4 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003234 // Struct of four or fewer fields.
3235 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003236 var li *Node
3237 var ri *Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07003238 for _, t1 := range t.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003239 if isblanksym(t1.Sym) {
3240 continue
3241 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003242 li = NodSym(OXDOT, l, t1.Sym)
3243 ri = NodSym(OXDOT, r, t1.Sym)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003244 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003245 if expr == nil {
3246 expr = a
3247 } else {
3248 expr = Nod(andor, expr, a)
3249 }
3250 }
3251
3252 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003253 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003254 }
Russ Cox44928112015-03-02 20:34:22 -05003255 finishcompare(np, n, expr, init)
3256 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003257 }
3258
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003259 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003260 var needsize int
3261 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003262
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003263 call.List.Append(l)
3264 call.List.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003265 if needsize != 0 {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003266 call.List.Append(Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003267 }
3268 r = call
3269 if n.Op != OEQ {
3270 r = Nod(ONOT, r, nil)
3271 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003272
Russ Cox44928112015-03-02 20:34:22 -05003273 finishcompare(np, n, r, init)
3274 return
3275}
3276
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003277func finishcompare(np **Node, n, r *Node, init *Nodes) {
Russ Cox44928112015-03-02 20:34:22 -05003278 // Using np here to avoid passing &r to typecheck.
3279 *np = r
3280 typecheck(np, Erv)
3281 walkexpr(np, init)
3282 r = *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003283 if r.Type != n.Type {
3284 r = Nod(OCONVNOP, r, nil)
3285 r.Type = n.Type
3286 r.Typecheck = 1
Russ Cox44928112015-03-02 20:34:22 -05003287 *np = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003288 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003289}
3290
Russ Coxdc7b54b2015-02-17 22:13:49 -05003291func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003292 var ar *Node
3293 var br *Node
3294 for a != nil && b != nil && a.Op == b.Op {
3295 switch a.Op {
3296 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003297 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003298
3299 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003300 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003301
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003302 case ODOT, ODOTPTR:
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003303 if a.Sym != b.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003304 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003305 }
3306
3307 case OINDEX:
3308 ar = a.Right
3309 br = b.Right
Russ Cox81d58102015-05-27 00:47:05 -04003310 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003311 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003312 }
3313 }
3314
3315 a = a.Left
3316 b = b.Left
3317 }
3318
Russ Coxdc7b54b2015-02-17 22:13:49 -05003319 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003320}
3321
3322func walkrotate(np **Node) {
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003323 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003324 return
3325 }
3326
Russ Cox382b44e2015-02-23 16:07:24 -05003327 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003328
3329 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003330 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003331
Russ Cox382b44e2015-02-23 16:07:24 -05003332 r := n.Right
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003333 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 -05003334 return
3335 }
3336
3337 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003338 if !samecheap(l.Left, r.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003339 return
3340 }
3341
3342 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003343 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003344
Russ Coxdc7b54b2015-02-17 22:13:49 -05003345 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003346 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003347 if sl >= 0 {
Russ Cox81d58102015-05-27 00:47:05 -04003348 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003349 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003350 // Rewrite left shift half to left rotate.
3351 if l.Op == OLSH {
3352 n = l
3353 } else {
3354 n = r
3355 }
3356 n.Op = OLROT
3357
3358 // Remove rotate 0 and rotate w.
Russ Cox81d58102015-05-27 00:47:05 -04003359 s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003360
3361 if s == 0 || s == w {
3362 n = n.Left
3363 }
3364
3365 *np = n
3366 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003367 }
3368 }
3369 return
3370 }
3371
3372 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
3373 return
Russ Cox8c195bd2015-02-13 14:40:36 -05003374}
3375
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003376// walkmul rewrites integer multiplication by powers of two as shifts.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003377func walkmul(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003378 n := *np
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003379 if !Isint[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003380 return
3381 }
3382
Russ Cox382b44e2015-02-23 16:07:24 -05003383 var nr *Node
3384 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003385 if n.Right.Op == OLITERAL {
3386 nl = n.Left
3387 nr = n.Right
3388 } else if n.Left.Op == OLITERAL {
3389 nl = n.Right
3390 nr = n.Left
3391 } else {
3392 return
3393 }
3394
Russ Cox382b44e2015-02-23 16:07:24 -05003395 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003396
3397 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003398 var pow int
3399 var w int
Russ Cox81d58102015-05-27 00:47:05 -04003400 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003401 cheapexpr(nl, init)
3402 Nodconst(n, n.Type, 0)
3403 goto ret
3404 }
3405
3406 // nr is a constant.
3407 pow = powtwo(nr)
3408
3409 if pow < 0 {
3410 return
3411 }
3412 if pow >= 1000 {
3413 // negative power of 2, like -16
3414 neg = 1
3415
3416 pow -= 1000
3417 }
3418
3419 w = int(nl.Type.Width * 8)
3420 if pow+1 >= w { // too big, shouldn't happen
3421 return
3422 }
3423
3424 nl = cheapexpr(nl, init)
3425
3426 if pow == 0 {
3427 // x*1 is x
3428 n = nl
3429
3430 goto ret
3431 }
3432
3433 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3434
3435ret:
3436 if neg != 0 {
3437 n = Nod(OMINUS, n, nil)
3438 }
3439
3440 typecheck(&n, Erv)
3441 walkexpr(&n, init)
3442 *np = n
3443}
3444
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003445// walkdiv rewrites division by a constant as less expensive
3446// operations.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003447func walkdiv(np **Node, init *Nodes) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003448 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003449
3450 // TODO(minux)
Yao Zhangd5cd4ab2015-09-10 11:33:09 -04003451 if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
Russ Cox8c195bd2015-02-13 14:40:36 -05003452 return
3453 }
3454
Russ Cox382b44e2015-02-23 16:07:24 -05003455 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003456 if n.Right.Op != OLITERAL {
3457 return
3458 }
3459
3460 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003461 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003462
Russ Cox382b44e2015-02-23 16:07:24 -05003463 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003464
3465 // special cases of mod/div
3466 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003467 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003468
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003469 s := 0 // 1 if nr is negative.
3470 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003471 if pow >= 1000 {
3472 // negative power of 2
3473 s = 1
3474
3475 pow -= 1000
3476 }
3477
3478 if pow+1 >= w {
3479 // divisor too large.
3480 return
3481 }
3482
3483 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003484 // try to do division by multiply by (2^w)/d
3485 // see hacker's delight chapter 10
3486 // TODO: support 64-bit magic multiply here.
3487 var m Magic
3488 m.W = w
3489
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003490 if Issigned[nl.Type.Etype] {
Russ Cox81d58102015-05-27 00:47:05 -04003491 m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
Russ Cox79f727a2015-03-02 12:35:15 -05003492 Smagic(&m)
3493 } else {
Russ Cox81d58102015-05-27 00:47:05 -04003494 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
Russ Cox79f727a2015-03-02 12:35:15 -05003495 Umagic(&m)
3496 }
3497
3498 if m.Bad != 0 {
3499 return
3500 }
3501
3502 // We have a quick division method so use it
3503 // for modulo too.
3504 if n.Op == OMOD {
3505 // rewrite as A%B = A - (A/B*B).
3506 n1 := Nod(ODIV, nl, nr)
3507
3508 n2 := Nod(OMUL, n1, nr)
3509 n = Nod(OSUB, nl, n2)
3510 goto ret
3511 }
3512
3513 switch Simtype[nl.Type.Etype] {
3514 default:
3515 return
3516
3517 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003518 case TUINT8, TUINT16, TUINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003519 nc := Nod(OXXX, nil, nil)
3520
3521 Nodconst(nc, nl.Type, int64(m.Um))
Todd Neal765c0f32015-06-23 18:59:52 -05003522 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003523 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003524 if m.Ua != 0 {
3525 // Select a Go type with (at least) twice the width.
3526 var twide *Type
3527 switch Simtype[nl.Type.Etype] {
3528 default:
3529 return
3530
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003531 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003532 twide = Types[TUINT32]
3533
3534 case TUINT32:
3535 twide = Types[TUINT64]
3536
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003537 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003538 twide = Types[TINT32]
3539
3540 case TINT32:
3541 twide = Types[TINT64]
3542 }
3543
3544 // add numerator (might overflow).
3545 // n2 = (n1 + nl)
3546 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3547
3548 // shift by m.s
3549 nc := Nod(OXXX, nil, nil)
3550
3551 Nodconst(nc, Types[TUINT], int64(m.S))
3552 n = conv(Nod(ORSH, n2, nc), nl.Type)
3553 } else {
3554 // n = n1 >> m.s
3555 nc := Nod(OXXX, nil, nil)
3556
3557 Nodconst(nc, Types[TUINT], int64(m.S))
3558 n = Nod(ORSH, n1, nc)
3559 }
3560
3561 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003562 case TINT8, TINT16, TINT32:
Russ Cox79f727a2015-03-02 12:35:15 -05003563 nc := Nod(OXXX, nil, nil)
3564
3565 Nodconst(nc, nl.Type, m.Sm)
Todd Neal765c0f32015-06-23 18:59:52 -05003566 n1 := Nod(OHMUL, nl, nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003567 typecheck(&n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003568 if m.Sm < 0 {
3569 // add the numerator.
3570 n1 = Nod(OADD, n1, nl)
3571 }
3572
3573 // shift by m.s
3574 nc = Nod(OXXX, nil, nil)
3575
3576 Nodconst(nc, Types[TUINT], int64(m.S))
3577 n2 := conv(Nod(ORSH, n1, nc), nl.Type)
3578
3579 // add 1 iff n1 is negative.
3580 nc = Nod(OXXX, nil, nil)
3581
3582 Nodconst(nc, Types[TUINT], int64(w)-1)
3583 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
3584 n = Nod(OSUB, n2, n3)
3585
3586 // apply sign.
3587 if m.Sd < 0 {
3588 n = Nod(OMINUS, n, nil)
3589 }
3590 }
3591
3592 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003593 }
3594
3595 switch pow {
3596 case 0:
3597 if n.Op == OMOD {
3598 // nl % 1 is zero.
3599 Nodconst(n, n.Type, 0)
3600 } else if s != 0 {
3601 // divide by -1
3602 n.Op = OMINUS
3603
3604 n.Right = nil
3605 } else {
3606 // divide by 1
3607 n = nl
3608 }
3609
3610 default:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003611 if Issigned[n.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003612 if n.Op == OMOD {
3613 // signed modulo 2^pow is like ANDing
3614 // with the last pow bits, but if nl < 0,
3615 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Russ Cox382b44e2015-02-23 16:07:24 -05003616 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003617
3618 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003619 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003620 if pow == 1 {
3621 typecheck(&n1, Erv)
3622 n1 = cheapexpr(n1, init)
3623
3624 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003625 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003626
Russ Cox382b44e2015-02-23 16:07:24 -05003627 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003628 Nodconst(nc, nl.Type, 1)
Russ Cox382b44e2015-02-23 16:07:24 -05003629 n3 := Nod(OAND, n2, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003630 n = Nod(OADD, n3, n1)
3631 } else {
3632 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003633 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003634
3635 Nodconst(nc, nl.Type, (1<<uint(pow))-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003636 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003637 typecheck(&n2, Erv)
3638 n2 = cheapexpr(n2, init)
3639
Russ Cox382b44e2015-02-23 16:07:24 -05003640 n3 := Nod(OADD, nl, n2)
3641 n4 := Nod(OAND, n3, nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003642 n = Nod(OSUB, n4, n2)
3643 }
3644
3645 break
3646 } else {
3647 // arithmetic right shift does not give the correct rounding.
3648 // if nl >= 0, nl >> n == nl / nr
3649 // if nl < 0, we want to add 2^n-1 first.
Russ Cox382b44e2015-02-23 16:07:24 -05003650 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003651
3652 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
Russ Cox382b44e2015-02-23 16:07:24 -05003653 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003654 if pow == 1 {
3655 // nl+1 is nl-(-1)
3656 n.Left = Nod(OSUB, nl, n1)
3657 } else {
3658 // Do a logical right right on -1 to keep pow bits.
Russ Cox382b44e2015-02-23 16:07:24 -05003659 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003660
3661 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Russ Cox382b44e2015-02-23 16:07:24 -05003662 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003663 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3664 }
3665
3666 // n = (nl + 2^pow-1) >> pow
3667 n.Op = ORSH
3668
3669 nc = Nod(OXXX, nil, nil)
3670 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3671 n.Right = nc
3672 n.Typecheck = 0
3673 }
3674
3675 if s != 0 {
3676 n = Nod(OMINUS, n, nil)
3677 }
3678 break
3679 }
3680
Russ Cox382b44e2015-02-23 16:07:24 -05003681 nc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003682 if n.Op == OMOD {
3683 // n = nl & (nr-1)
3684 n.Op = OAND
3685
Russ Cox81d58102015-05-27 00:47:05 -04003686 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003687 } else {
3688 // n = nl >> pow
3689 n.Op = ORSH
3690
3691 Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
3692 }
3693
3694 n.Typecheck = 0
3695 n.Right = nc
3696 }
3697
3698 goto ret
3699
Russ Cox8c195bd2015-02-13 14:40:36 -05003700ret:
3701 typecheck(&n, Erv)
3702 walkexpr(&n, init)
3703 *np = n
3704}
3705
3706// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003707func bounded(n *Node, max int64) bool {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003708 if n.Type == nil || !Isint[n.Type.Etype] {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003709 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003710 }
3711
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003712 sign := Issigned[n.Type.Etype]
Russ Cox382b44e2015-02-23 16:07:24 -05003713 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003714
Russ Coxdc7b54b2015-02-17 22:13:49 -05003715 if Smallintconst(n) {
Russ Cox81d58102015-05-27 00:47:05 -04003716 v := Mpgetfix(n.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003717 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003718 }
3719
3720 switch n.Op {
3721 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003722 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003723 if Smallintconst(n.Left) {
Russ Cox81d58102015-05-27 00:47:05 -04003724 v = Mpgetfix(n.Left.Val().U.(*Mpint))
Russ Coxdc7b54b2015-02-17 22:13:49 -05003725 } else if Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003726 v = Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003727 }
3728
3729 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003730 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003731 }
3732
3733 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003734 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003735 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003736 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003737 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003738 }
3739 }
3740
3741 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003742 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003743 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003744 for bits > 0 && v >= 2 {
3745 bits--
3746 v >>= 1
3747 }
3748 }
3749
3750 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003751 if !sign && Smallintconst(n.Right) {
Russ Cox81d58102015-05-27 00:47:05 -04003752 v := Mpgetfix(n.Right.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -05003753 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003754 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003755 }
3756 bits -= int32(v)
3757 }
3758 }
3759
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003760 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003761 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003762 }
3763
Russ Coxdc7b54b2015-02-17 22:13:49 -05003764 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003765}
3766
David Crawshawcc158402016-03-10 16:15:26 -05003767// usemethod check interface method calls for uses of reflect.Type.Method.
3768func usemethod(n *Node) {
3769 t := n.Left.Type
3770
3771 // Looking for either of:
3772 // Method(int) reflect.Method
3773 // MethodByName(string) (reflect.Method, bool)
3774 //
3775 // TODO(crawshaw): improve precision of match by working out
3776 // how to check the method name.
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003777 if n := t.Params().NumFields(); n != 1 {
David Crawshawcc158402016-03-10 16:15:26 -05003778 return
3779 }
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003780 if n := t.Results().NumFields(); n != 1 && n != 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003781 return
3782 }
3783 p0 := t.Params().Field(0)
3784 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003785 var res1 *Field
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003786 if t.Results().NumFields() == 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003787 res1 = t.Results().Field(1)
3788 }
3789
3790 if res1 == nil {
3791 if p0.Type.Etype != TINT {
3792 return
3793 }
3794 } else {
3795 if p0.Type.Etype != TSTRING {
3796 return
3797 }
3798 if res1.Type.Etype != TBOOL {
3799 return
3800 }
3801 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003802 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003803 return
3804 }
3805
3806 Curfn.Func.ReflectMethod = true
3807}
3808
Russ Cox8c195bd2015-02-13 14:40:36 -05003809func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003810 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 return
3812 }
3813
3814 switch n.Op {
3815 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08003816 Fatalf("usefield %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003817
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003818 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003819 break
3820 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003821 if n.Sym == nil {
Keith Randall71d13a82016-03-02 20:54:41 -08003822 // No field name. This DOTPTR was built by the compiler for access
3823 // to runtime data structures. Ignore.
3824 return
3825 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003826
Russ Cox496ad0a2015-05-26 21:49:31 -04003827 t := n.Left.Type
3828 if Isptr[t.Etype] {
3829 t = t.Type
3830 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003831 field := dotField[typeSym{t.Orig, n.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003832 if field == nil {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003833 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003834 }
Russ Coxbed1f902015-03-02 16:03:26 -05003835 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003836 return
3837 }
3838
Matthew Dempskya2a48062016-03-10 16:15:44 -08003839 outer := n.Left.Type
3840 if Isptr[outer.Etype] {
3841 outer = outer.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003842 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003843 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003844 Yyerror("tracked field must be in named struct type")
3845 }
3846 if !exportname(field.Sym.Name) {
3847 Yyerror("tracked field must be exported (upper case)")
3848 }
3849
Matthew Dempskya2a48062016-03-10 16:15:44 -08003850 sym := tracksym(outer, field)
3851 if Curfn.Func.FieldTrack == nil {
3852 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
3853 }
3854 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05003855}
3856
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003857func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003858 for _, n := range l.Slice() {
3859 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003860 return false
3861 }
3862 }
3863 return true
3864}
3865
Russ Coxdc7b54b2015-02-17 22:13:49 -05003866func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003867 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003868 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003869 }
3870
3871 switch n.Op {
3872 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003873 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003874
3875 // Discardable as long as the subpieces are.
3876 case ONAME,
3877 ONONAME,
3878 OTYPE,
3879 OPACK,
3880 OLITERAL,
3881 OADD,
3882 OSUB,
3883 OOR,
3884 OXOR,
3885 OADDSTR,
3886 OADDR,
3887 OANDAND,
3888 OARRAYBYTESTR,
3889 OARRAYRUNESTR,
3890 OSTRARRAYBYTE,
3891 OSTRARRAYRUNE,
3892 OCAP,
3893 OCMPIFACE,
3894 OCMPSTR,
3895 OCOMPLIT,
3896 OMAPLIT,
3897 OSTRUCTLIT,
3898 OARRAYLIT,
3899 OPTRLIT,
3900 OCONV,
3901 OCONVIFACE,
3902 OCONVNOP,
3903 ODOT,
3904 OEQ,
3905 ONE,
3906 OLT,
3907 OLE,
3908 OGT,
3909 OGE,
3910 OKEY,
3911 OLEN,
3912 OMUL,
3913 OLSH,
3914 ORSH,
3915 OAND,
3916 OANDNOT,
3917 ONEW,
3918 ONOT,
3919 OCOM,
3920 OPLUS,
3921 OMINUS,
3922 OOROR,
3923 OPAREN,
3924 ORUNESTR,
3925 OREAL,
3926 OIMAG,
3927 OCOMPLEX:
3928 break
3929
3930 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003931 case ODIV, OMOD:
Russ Cox81d58102015-05-27 00:47:05 -04003932 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003933 break
3934 }
Russ Cox81d58102015-05-27 00:47:05 -04003935 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003936 break
3937 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003938 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003939
3940 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003941 case OMAKECHAN, OMAKEMAP:
Russ Cox81d58102015-05-27 00:47:05 -04003942 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003943 break
3944 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003945 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003946
3947 // Difficult to tell what sizes are okay.
3948 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003949 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003950 }
3951
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003952 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 -05003953 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003954 }
3955
Russ Coxdc7b54b2015-02-17 22:13:49 -05003956 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003957}
3958
3959// rewrite
3960// print(x, y, z)
3961// into
3962// func(a1, a2, a3) {
3963// print(a1, a2, a3)
3964// }(x, y, z)
3965// and same for println.
3966
3967var walkprintfunc_prgen int
3968
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003969func walkprintfunc(np **Node, init *Nodes) {
Russ Cox382b44e2015-02-23 16:07:24 -05003970 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -05003971
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003972 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003973 walkstmtlist(n.Ninit.Slice())
3974 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05003975 }
3976
Russ Cox382b44e2015-02-23 16:07:24 -05003977 t := Nod(OTFUNC, nil, nil)
3978 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003979 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05003980 var a *Node
3981 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003982 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003983 buf = fmt.Sprintf("a%d", num)
3984 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003985 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
3986 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003987 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05003988 }
3989
Russ Cox382b44e2015-02-23 16:07:24 -05003990 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003991 walkprintfunc_prgen++
3992 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003993 fn.Func.Nname = newname(Lookup(buf))
3994 fn.Func.Nname.Name.Defn = fn
3995 fn.Func.Nname.Name.Param.Ntype = t
3996 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003997
Russ Cox382b44e2015-02-23 16:07:24 -05003998 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05003999 Curfn = nil
4000 funchdr(fn)
4001
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02004002 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004003 a.List.Set(printargs)
Russ Cox8c195bd2015-02-13 14:40:36 -05004004 typecheck(&a, Etop)
4005 walkstmt(&a)
4006
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08004007 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004008
4009 funcbody(fn)
4010
4011 typecheck(&fn, Etop)
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07004012 typecheckslice(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08004013 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05004014 Curfn = oldfn
4015
4016 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004017 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004018 a.List.Set(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -05004019 typecheck(&a, Etop)
4020 walkexpr(&a, init)
4021 *np = a
4022}