blob: 55a29e5bad668075ac518ba15afc19ec063b3184 [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"
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07009 "cmd/internal/sys"
Russ Cox8c195bd2015-02-13 14:40:36 -050010 "fmt"
11 "strings"
12)
13
Russ Cox8c195bd2015-02-13 14:40:36 -050014// The constant is known to runtime.
15const (
16 tmpstringbufsize = 32
17)
18
19func walk(fn *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -050020 Curfn = fn
21
22 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040023 s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080024 dumplist(s, Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050025 }
26
Robert Griesemerc41608f2016-03-02 17:34:42 -080027 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -050028
29 // Final typecheck for any unused variables.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080030 for i, ln := range fn.Func.Dcl {
Russ Coxb6dc3e62016-05-25 01:33:24 -040031 if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070032 ln = typecheck(ln, Erv|Easgn)
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080033 fn.Func.Dcl[i] = ln
Russ Cox8c195bd2015-02-13 14:40:36 -050034 }
35 }
36
37 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080038 for _, ln := range fn.Func.Dcl {
Russ Coxb6dc3e62016-05-25 01:33:24 -040039 if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080040 ln.Name.Defn.Left.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -050041 }
42 }
43
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080044 for _, ln := range fn.Func.Dcl {
Russ Coxb6dc3e62016-05-25 01:33:24 -040045 if ln.Op != ONAME || (ln.Class != PAUTO && ln.Class != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050046 continue
47 }
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080048 if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
Russ Cox4fdd5362015-05-26 22:19:27 -040049 if defn.Left.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050050 continue
51 }
Russ Cox4fdd5362015-05-26 22:19:27 -040052 lineno = defn.Left.Lineno
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080053 Yyerror("%v declared and not used", ln.Sym)
Russ Cox4fdd5362015-05-26 22:19:27 -040054 defn.Left.Used = true // suppress repeats
Russ Cox8c195bd2015-02-13 14:40:36 -050055 } else {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080056 lineno = ln.Lineno
57 Yyerror("%v declared and not used", ln.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050058 }
59 }
60
Robert Griesemerc41608f2016-03-02 17:34:42 -080061 lineno = lno
Russ Cox8c195bd2015-02-13 14:40:36 -050062 if nerrors != 0 {
63 return
64 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080065 walkstmtlist(Curfn.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -050066 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040067 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080068 dumplist(s, Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050069 }
70
71 heapmoves()
Josh Bleecher Snyder1da62af2016-04-24 13:50:26 -070072 if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040073 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080074 dumplist(s, Curfn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050075 }
76}
77
Ian Lance Taylore28a8902016-03-07 22:54:46 -080078func walkstmtlist(s []*Node) {
79 for i := range s {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070080 s[i] = walkstmt(s[i])
Russ Cox8c195bd2015-02-13 14:40:36 -050081 }
82}
83
Ian Lance Taylore28a8902016-03-07 22:54:46 -080084func samelist(a, b []*Node) bool {
85 if len(a) != len(b) {
86 return false
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080087 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080088 for i, n := range a {
89 if n != b[i] {
Russ Coxdc7b54b2015-02-17 22:13:49 -050090 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050091 }
92 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080093 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050094}
95
Dave Cheneyb006d382015-03-06 18:42:58 +110096func paramoutheap(fn *Node) bool {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080097 for _, ln := range fn.Func.Dcl {
98 switch ln.Class {
Russ Coxb6dc3e62016-05-25 01:33:24 -040099 case PPARAMOUT:
100 if ln.isParamStackCopy() || ln.Addrtaken {
101 return true
102 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500103
Russ Coxb6dc3e62016-05-25 01:33:24 -0400104 case PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -0500105 // stop early - parameters are over
Dave Cheneyb006d382015-03-06 18:42:58 +1100106 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500107 }
108 }
109
Dave Cheneyb006d382015-03-06 18:42:58 +1100110 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500111}
112
113// adds "adjust" to all the argument locations for the call n.
114// n must be a defer or go node that has already been walked.
115func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500116 var arg *Node
117 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500118
Russ Cox382b44e2015-02-23 16:07:24 -0500119 callfunc := n.Left
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800120 for _, arg = range callfunc.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500121 if arg.Op != OAS {
122 Yyerror("call arg not assignment")
123 }
124 lhs = arg.Left
125 if lhs.Op == ONAME {
126 // This is a temporary introduced by reorder1.
127 // The real store to the stack appears later in the arg list.
128 continue
129 }
130
131 if lhs.Op != OINDREG {
132 Yyerror("call argument store does not use OINDREG")
133 }
134
135 // can't really check this in machine-indep code.
136 //if(lhs->val.u.reg != D_SP)
137 // yyerror("call arg assign not indreg(SP)");
138 lhs.Xoffset += int64(adjust)
139 }
140}
141
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700142// The result of walkstmt MUST be assigned back to n, e.g.
143// n.Left = walkstmt(n.Left)
144func walkstmt(n *Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500145 if n == nil {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700146 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500147 }
148 if n.Dodata == 2 { // don't walk, generated by anylit.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700149 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500150 }
151
152 setlineno(n)
153
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800154 walkstmtlist(n.Ninit.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500155
156 switch n.Op {
157 default:
158 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400159 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500160 } else {
Dave Cheneyd3c79d32016-04-27 15:10:10 +1000161 Yyerror("%v is not a top level statement", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -0500162 }
163 Dump("nottop", n)
164
165 case OAS,
166 OASOP,
167 OAS2,
168 OAS2DOTTYPE,
169 OAS2RECV,
170 OAS2FUNC,
171 OAS2MAPR,
172 OCLOSE,
173 OCOPY,
174 OCALLMETH,
175 OCALLINTER,
176 OCALL,
177 OCALLFUNC,
178 ODELETE,
179 OSEND,
180 OPRINT,
181 OPRINTN,
182 OPANIC,
183 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400184 ORECOVER,
185 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500186 if n.Typecheck == 0 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700187 Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500188 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700189 wascopy := n.Op == OCOPY
Russ Cox382b44e2015-02-23 16:07:24 -0500190 init := n.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800191 n.Ninit.Set(nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700192 n = walkexpr(n, &init)
193 n = addinit(n, init.Slice())
194 if wascopy && n.Op == OCONVNOP {
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 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
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700207 n.Left = walkexpr(n.Left, &init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500208 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700209 n = walkexpr(n, &init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500210
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700211 n = addinit(n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500212
213 case OBREAK,
Russ Cox8c195bd2015-02-13 14:40:36 -0500214 OCONTINUE,
215 OFALL,
216 OGOTO,
217 OLABEL,
218 ODCLCONST,
219 ODCLTYPE,
220 OCHECKNIL,
Russ Cox1ac637c2016-01-13 00:46:28 -0500221 OVARKILL,
222 OVARLIVE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500223 break
224
Russ Coxb6dc3e62016-05-25 01:33:24 -0400225 case ODCL:
226 v := n.Left
227 if v.Class == PAUTOHEAP {
228 if compiling_runtime {
229 Yyerror("%v escapes to heap, not allowed in runtime.", v)
230 }
231 if prealloc[v] == nil {
232 prealloc[v] = callnew(v.Type)
233 }
234 nn := Nod(OAS, v.Name.Heapaddr, prealloc[v])
235 nn.Colas = true
236 nn = typecheck(nn, Etop)
237 return walkstmt(nn)
238 }
239
Russ Cox8c195bd2015-02-13 14:40:36 -0500240 case OBLOCK:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800241 walkstmtlist(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500242
243 case OXCASE:
244 Yyerror("case statement out of place")
245 n.Op = OCASE
246 fallthrough
247
248 case OCASE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700249 n.Right = walkstmt(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500250
251 case ODEFER:
HĂ¥vard Haugen25946642015-09-07 22:19:30 +0200252 hasdefer = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500253 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700254 case OPRINT, OPRINTN:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700255 n.Left = walkprintfunc(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500256
257 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700258 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500259
260 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700261 n.Left = walkexpr(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500262 }
263
264 // make room for size & fn arguments.
265 adjustargs(n, 2*Widthptr)
266
267 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400268 if n.Left != nil {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800269 walkstmtlist(n.Left.Ninit.Slice())
Russ Cox66be1482015-05-26 21:30:20 -0400270 init := n.Left.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800271 n.Left.Ninit.Set(nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700272 n.Left = walkexpr(n.Left, &init)
273 n.Left = addinit(n.Left, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500274 }
275
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700276 n.Right = walkstmt(n.Right)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800277 walkstmtlist(n.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500278
279 case OIF:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700280 n.Left = walkexpr(n.Left, &n.Ninit)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800281 walkstmtlist(n.Nbody.Slice())
282 walkstmtlist(n.Rlist.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500283
284 case OPROC:
285 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700286 case OPRINT, OPRINTN:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700287 n.Left = walkprintfunc(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500288
289 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700290 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500291
292 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700293 n.Left = walkexpr(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500294 }
295
296 // make room for size & fn arguments.
297 adjustargs(n, 2*Widthptr)
298
299 case ORETURN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800300 walkexprlist(n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800301 if n.List.Len() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500302 break
303 }
Josh Bleecher Snyderf38f43d2016-04-01 20:11:30 -0700304 if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500305 // assign to the function out parameters,
306 // so that reorder3 can fix up conflicts
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800307 var rl []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500308
Robert Griesemercd7d7382015-10-26 14:57:36 -0700309 var cl Class
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800310 for _, ln := range Curfn.Func.Dcl {
Russ Coxb6dc3e62016-05-25 01:33:24 -0400311 cl = ln.Class
312 if cl == PAUTO || cl == PAUTOHEAP {
Russ Cox8c195bd2015-02-13 14:40:36 -0500313 break
314 }
315 if cl == PPARAMOUT {
Russ Coxb6dc3e62016-05-25 01:33:24 -0400316 if ln.isParamStackCopy() {
317 ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
318 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800319 rl = append(rl, ln)
Russ Cox8c195bd2015-02-13 14:40:36 -0500320 }
321 }
322
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800323 if got, want := n.List.Len(), len(rl); got != want {
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800324 // order should have rewritten multi-value function calls
325 // with explicit OAS2FUNC nodes.
326 Fatalf("expected %v return arguments, have %v", want, got)
327 }
328
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800329 if samelist(rl, n.List.Slice()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500330 // special return in disguise
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800331 n.List.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500332
333 break
334 }
335
Russ Cox8c195bd2015-02-13 14:40:36 -0500336 // move function calls out, to make reorder3's job easier.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800337 walkexprlistsafe(n.List.Slice(), &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500338
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800339 ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800340 n.List.Set(reorder3(ll))
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800341 ls := n.List.Slice()
342 for i, n := range ls {
343 ls[i] = applywritebarrier(n)
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800344 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500345 break
346 }
347
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800348 ll := ascompatte(n.Op, nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800349 n.List.Set(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500350
351 case ORETJMP:
352 break
353
354 case OSELECT:
355 walkselect(n)
356
357 case OSWITCH:
358 walkswitch(n)
359
360 case ORANGE:
361 walkrange(n)
362
363 case OXFALL:
364 Yyerror("fallthrough statement out of place")
365 n.Op = OFALL
366 }
367
368 if n.Op == ONAME {
Matthew Dempsky63142022016-03-15 13:06:58 -0700369 Fatalf("walkstmt ended up with name: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500370 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700371 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500372}
373
David Chasee5060c72015-05-20 15:16:34 -0400374func isSmallMakeSlice(n *Node) bool {
375 if n.Op != OMAKESLICE {
376 return false
377 }
378 l := n.Left
379 r := n.Right
380 if r == nil {
381 r = l
382 }
383 t := n.Type
384
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -0700385 return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
David Chasee5060c72015-05-20 15:16:34 -0400386}
387
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900388// walk the whole tree of the body of an
389// expression or simple statement.
390// the types expressions are calculated.
391// compile-time constants are evaluated.
392// complex side effects like statements are appended to init
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800393func walkexprlist(s []*Node, init *Nodes) {
394 for i := range s {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700395 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500396 }
397}
398
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800399func walkexprlistsafe(s []*Node, init *Nodes) {
400 for i, n := range s {
401 s[i] = safeexpr(n, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700402 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500403 }
404}
405
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800406func walkexprlistcheap(s []*Node, init *Nodes) {
407 for i, n := range s {
408 s[i] = cheapexpr(n, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700409 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500410 }
411}
412
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000413// Build name of function: convI2E etc.
414// Not all names are possible
415// (e.g., we'll never generate convE2E or convE2I).
416func convFuncName(from, to *Type) string {
417 tkind := to.iet()
418 switch from.iet() {
419 case 'I':
420 switch tkind {
421 case 'E':
422 return "convI2E"
423 case 'I':
424 return "convI2I"
425 }
426 case 'T':
427 switch tkind {
428 case 'E':
429 return "convT2E"
430 case 'I':
431 return "convT2I"
432 }
433 }
434 Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
435 panic("unreachable")
436}
437
438// Build name of function: assertI2E etc.
439// If with2suffix is true, the form ending in "2" is returned".
440func assertFuncName(from, to *Type, with2suffix bool) string {
441 l := len("assertX2X2")
442 if !with2suffix {
443 l--
444 }
445 tkind := to.iet()
446 switch from.iet() {
447 case 'E':
448 switch tkind {
449 case 'I':
450 return "assertE2I2"[:l]
451 case 'E':
452 return "assertE2E2"[:l]
453 case 'T':
454 return "assertE2T2"[:l]
455 }
456 case 'I':
457 switch tkind {
458 case 'I':
459 return "assertI2I2"[:l]
460 case 'E':
461 return "assertI2E2"[:l]
462 case 'T':
463 return "assertI2T2"[:l]
464 }
465 }
466 Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
467 panic("unreachable")
468}
469
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700470// The result of walkexpr MUST be assigned back to n, e.g.
471// n.Left = walkexpr(n.Left, init)
472func walkexpr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500473 if n == nil {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700474 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500475 }
476
477 if init == &n.Ninit {
478 // not okay to use n->ninit when walking n,
479 // because we might replace n with some other node
480 // and would lose the init list.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200481 Fatalf("walkexpr init == &n->ninit")
Russ Cox8c195bd2015-02-13 14:40:36 -0500482 }
483
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800484 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800485 walkstmtlist(n.Ninit.Slice())
486 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500487 }
488
489 // annoying case - not typechecked
490 if n.Op == OKEY {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700491 n.Left = walkexpr(n.Left, init)
492 n.Right = walkexpr(n.Right, init)
493 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500494 }
495
Russ Cox382b44e2015-02-23 16:07:24 -0500496 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500497
498 if Debug['w'] > 1 {
499 Dump("walk-before", n)
500 }
501
502 if n.Typecheck != 1 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700503 Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500504 }
505
Russ Coxb6dc3e62016-05-25 01:33:24 -0400506 if n.Op == ONAME && n.Class == PAUTOHEAP {
507 nn := Nod(OIND, n.Name.Heapaddr, nil)
508 nn = typecheck(nn, Erv)
Cherry Zhang4c4ca832016-08-11 09:54:04 -0400509 nn = walkexpr(nn, init)
510 nn.Left.NonNil = true
511 return nn
Russ Coxb6dc3e62016-05-25 01:33:24 -0400512 }
513
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200514opswitch:
Russ Cox8c195bd2015-02-13 14:40:36 -0500515 switch n.Op {
516 default:
517 Dump("walk", n)
Matthew Dempsky63142022016-03-15 13:06:58 -0700518 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, FmtShort|FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500519
520 case OTYPE,
521 ONONAME,
522 OINDREG,
523 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400524 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500525
526 case ONOT,
527 OMINUS,
528 OPLUS,
529 OCOM,
530 OREAL,
531 OIMAG,
532 ODOTMETH,
533 ODOTINTER:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700534 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500535
536 case OIND:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700537 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500538
539 case ODOT:
540 usefield(n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700541 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500542
543 case ODOTPTR:
544 usefield(n)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700545 if n.Op == ODOTPTR && n.Left.Type.Elem().Width == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500546 // No actual copy will be generated, so emit an explicit nil check.
547 n.Left = cheapexpr(n.Left, init)
548
549 checknil(n.Left, init)
550 }
551
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700552 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500553
554 case OEFACE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700555 n.Left = walkexpr(n.Left, init)
556 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500557
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700558 case OSPTR, OITAB, OIDATA:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700559 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500560
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700561 case OLEN, OCAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700562 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500563
564 // replace len(*[10]int) with 10.
565 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500566 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500567
Matthew Dempskye76fc1b2016-03-30 15:09:25 -0700568 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700569 t = t.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -0500570 }
Matthew Dempsky1624a9c2016-03-30 14:45:47 -0700571 if t.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500572 safeexpr(n.Left, init)
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -0700573 Nodconst(n, n.Type, t.NumElem())
Russ Cox8c195bd2015-02-13 14:40:36 -0500574 n.Typecheck = 1
575 }
576
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700577 case OLSH, ORSH:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700578 n.Left = walkexpr(n.Left, init)
579 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500580 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500581 n.Bounded = bounded(n.Right, 8*t.Width)
582 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500583 Warn("shift bounds check elided")
584 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500585
586 // Use results from call expression as arguments for complex.
587 case OAND,
588 OSUB,
589 OHMUL,
590 OLT,
591 OLE,
592 OGE,
593 OGT,
594 OADD,
595 OCOMPLEX,
596 OLROT:
597 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800598 n.Left = n.List.First()
599 n.Right = n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500600 }
601
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700602 n.Left = walkexpr(n.Left, init)
603 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500604
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700605 case OOR, OXOR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700606 n.Left = walkexpr(n.Left, init)
607 n.Right = walkexpr(n.Right, init)
608 n = walkrotate(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500609
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700610 case OEQ, ONE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700611 n.Left = walkexpr(n.Left, init)
612 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500613
614 // Disable safemode while compiling this code: the code we
615 // generate internally can refer to unsafe.Pointer.
616 // In this case it can happen if we need to generate an ==
617 // for a struct containing a reflect.Value, which itself has
618 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500619 old_safemode := safemode
Matthew Dempsky980ab122016-04-13 18:37:18 -0700620 safemode = false
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700621 n = walkcompare(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500622 safemode = old_safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500623
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700624 case OANDAND, OOROR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700625 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500626
David Chaseffe7fbf2015-03-27 12:34:45 -0400627 // cannot put side effects from n.Right on init,
628 // because they cannot run before n.Left is checked.
629 // save elsewhere and store on the eventual n.Right.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800630 var ll Nodes
Russ Cox8c195bd2015-02-13 14:40:36 -0500631
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700632 n.Right = walkexpr(n.Right, &ll)
633 n.Right = addinit(n.Right, ll.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500634
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700635 case OPRINT, OPRINTN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800636 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500637 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500638
639 case OPANIC:
640 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500641
642 case ORECOVER:
643 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500644
645 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700646 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500647
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700648 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700649 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500650
651 case ONAME:
Russ Cox20803b82016-05-25 10:29:50 -0400652 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500653
654 case OCALLINTER:
David Crawshawcc158402016-03-10 16:15:26 -0500655 usemethod(n)
Russ Cox382b44e2015-02-23 16:07:24 -0500656 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800657 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200658 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500659 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700660 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800661 walkexprlist(n.List.Slice(), init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800662 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800663 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500664
665 case OCALLFUNC:
666 if n.Left.Op == OCLOSURE {
667 // Transform direct call of a closure to call of a normal function.
668 // transformclosure already did all preparation work.
669
David Chase731dcda2015-07-23 14:17:07 -0400670 // Prepend captured variables to argument list.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800671 n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500672
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800673 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500674
675 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400676 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500677
678 // Update type of OCALLFUNC node.
679 // Output arguments had not changed, but their offsets could.
Matthew Dempskyc8377612016-03-17 01:47:16 -0700680 if n.Left.Type.Results().NumFields() == 1 {
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -0700681 n.Type = n.Left.Type.Results().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500682 } else {
Matthew Dempskydb506fe2016-03-08 16:31:28 -0800683 n.Type = n.Left.Type.Results()
Russ Cox8c195bd2015-02-13 14:40:36 -0500684 }
685 }
686
Russ Cox382b44e2015-02-23 16:07:24 -0500687 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800688 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200689 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500690 }
691
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700692 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800693 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500694
Russ Cox92dba0d2015-04-01 16:02:34 -0400695 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
Michael Munday613ba6c2016-04-12 12:26:17 -0400696 if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
Russ Cox92dba0d2015-04-01 16:02:34 -0400697 n.Op = OSQRT
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800698 n.Left = n.List.First()
699 n.List.Set(nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200700 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400701 }
702 }
703
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800704 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800705 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500706
707 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500708 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800709 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200710 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500711 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700712 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800713 walkexprlist(n.List.Slice(), init)
Matthew Dempskyf91b8322016-03-09 20:54:59 -0800714 ll := ascompatte(n.Op, n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800715 lr := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800716 ll = append(ll, lr...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500717 n.Left.Left = nil
718 ullmancalc(n.Left)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800719 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500720
721 case OAS:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800722 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500723
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700724 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500725 n.Left = safeexpr(n.Left, init)
726
Russ Coxdc7b54b2015-02-17 22:13:49 -0500727 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200728 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500729 }
730
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700731 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200732 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500733 }
734
735 switch n.Right.Op {
736 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700737 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500738
Russ Cox8c195bd2015-02-13 14:40:36 -0500739 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400740 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
741 // It needs to be removed in all three places.
742 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700743 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400744 // handled directly during cgen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700745 n.Right = walkexpr(n.Right, init)
Russ Cox4224d812015-03-20 00:06:10 -0400746 break
747 }
748
David Chaseffe7fbf2015-03-27 12:34:45 -0400749 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400750 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700751 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500752
Russ Cox382b44e2015-02-23 16:07:24 -0500753 n1 := Nod(OADDR, n.Left, nil)
754 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500755
Russ Cox4224d812015-03-20 00:06:10 -0400756 if Debug_typeassert > 0 {
757 Warn("type assertion not inlined")
758 }
759
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800760 fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700761 fn = substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500762
763 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700764 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200765 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500766
Russ Cox8c195bd2015-02-13 14:40:36 -0500767 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400768 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400769 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700770 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500771
Russ Cox382b44e2015-02-23 16:07:24 -0500772 n1 := Nod(OADDR, n.Left, nil)
773 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500774 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700775 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200776 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400777
778 case OAPPEND:
779 // x = append(...)
780 r := n.Right
781 if r.Isddd {
782 r = appendslice(r, init) // also works for append(slice, string).
783 } else {
784 r = walkappend(r, init, n)
785 }
786 n.Right = r
787 if r.Op == OAPPEND {
788 // Left in place for back end.
789 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200790 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400791 }
792 // Otherwise, lowered for race detector.
793 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500794 }
795
796 if n.Left != nil && n.Right != nil {
Josh Bleecher Snyder68884052016-03-26 08:17:43 -0700797 dd := n.Dodata
798 n = convas(n, init)
799 n.Dodata = dd
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800800 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500801 }
802
Russ Cox8c195bd2015-02-13 14:40:36 -0500803 case OAS2:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800804 init.AppendNodes(&n.Ninit)
805 walkexprlistsafe(n.List.Slice(), init)
806 walkexprlistsafe(n.Rlist.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800807 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500808 ll = reorder3(ll)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800809 for i, n := range ll {
810 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500811 }
812 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500813
814 // a,b,... = fn()
815 case OAS2FUNC:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800816 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500817
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800818 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800819 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700820 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500821
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800822 ll := ascompatet(n.Op, n.List, r.Type, 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800823 for i, n := range ll {
824 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500825 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800826 n = liststmt(append([]*Node{r}, ll...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500827
828 // x, y = <-c
829 // orderstmt made sure x is addressable.
830 case OAS2RECV:
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)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700835 r.Left = walkexpr(r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500836 var n1 *Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800837 if isblank(n.List.First()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500838 n1 = nodnil()
839 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800840 n1 = Nod(OADDR, n.List.First(), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500841 }
842 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500843 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800844 r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
845 n = Nod(OAS, n.List.Second(), r)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700846 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500847
848 // a,b = m[i];
849 case OAS2MAPR:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800850 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500851
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800852 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800853 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700854 r.Left = walkexpr(r.Left, init)
855 r.Right = walkexpr(r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500856 t := r.Left.Type
857 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700858 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800859 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800860 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500861 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800862 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500863 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800864 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500865 p = "mapaccess2_faststr"
866 }
867 }
868
Russ Cox382b44e2015-02-23 16:07:24 -0500869 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500870 if p != "" {
871 // fast versions take key by value
872 key = r.Right
873 } else {
874 // standard version takes key by reference
875 // orderexpr made sure key is addressable.
876 key = Nod(OADDR, r.Right, nil)
877
878 p = "mapaccess2"
879 }
880
881 // from:
882 // a,b = m[i]
883 // to:
884 // var,b = mapaccess2*(t, m, i)
885 // a = *var
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800886 a := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -0500887
Keith Randall60fd32a2016-04-19 08:31:04 -0700888 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
889 fn := mapfn(p, t)
890 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
891 } else {
892 fn := mapfn("mapaccess2_fat", t)
893 z := zeroaddr(w)
894 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
895 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500896
897 // mapaccess2* returns a typed bool, but due to spec changes,
898 // the boolean result of i.(T) is now untyped so we make it the
899 // same type as the variable on the lhs.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800900 if !isblank(n.List.Second()) {
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800901 r.Type.Field(1).Type = n.List.Second().Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500902 }
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800903 n.Rlist.Set1(r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500904 n.Op = OAS2FUNC
905
906 // don't generate a = *var if a is _
907 if !isblank(a) {
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700908 var_ := temp(Ptrto(t.Val()))
Russ Cox8c195bd2015-02-13 14:40:36 -0500909 var_.Typecheck = 1
Keith Randall3c1a4c12016-04-19 21:06:53 -0700910 var_.NonNil = true // mapaccess always returns a non-nil pointer
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800911 n.List.SetIndex(0, var_)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700912 n = walkexpr(n, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800913 init.Append(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500914 n = Nod(OAS, a, Nod(OIND, var_, nil))
915 }
916
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700917 n = typecheck(n, Etop)
918 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500919
Russ Cox8c195bd2015-02-13 14:40:36 -0500920 case ODELETE:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800921 init.AppendNodes(&n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800922 map_ := n.List.First()
923 key := n.List.Second()
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700924 map_ = walkexpr(map_, init)
925 key = walkexpr(key, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500926
927 // orderstmt made sure key is addressable.
928 key = Nod(OADDR, key, nil)
929
Russ Cox382b44e2015-02-23 16:07:24 -0500930 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500931 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500932
Russ Cox8c195bd2015-02-13 14:40:36 -0500933 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800934 e := n.Rlist.First() // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400935 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
936 // It needs to be removed in all three places.
937 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700938 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400939 // handled directly during gen.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800940 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700941 e.Left = walkexpr(e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200942 break
Russ Cox4224d812015-03-20 00:06:10 -0400943 }
944
945 // res, ok = i.(T)
946 // orderstmt made sure a is addressable.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800947 init.AppendNodes(&n.Ninit)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700948
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800949 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700950 e.Left = walkexpr(e.Left, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700951 t := e.Type // T
952 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500953
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700954 oktype := Types[TBOOL]
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800955 ok := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500956 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700957 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500958 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700959
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000960 fromKind := from.Type.iet()
961 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700962
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700963 res := n.List.First()
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700964 scalar := !haspointers(res.Type)
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700965
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700966 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
967 // This is faster and shorter and allows the corresponding assertX2X2
968 // routines to skip nil checks on their last argument.
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700969 // Also avoid runtime calls for converting interfaces to scalar concrete types.
970 if isblank(res) || (scalar && toKind == 'T') {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700971 var fast *Node
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700972 switch toKind {
973 case 'T':
974 tab := Nod(OITAB, from, nil)
975 if fromKind == 'E' {
976 typ := Nod(OCONVNOP, typename(t), nil)
977 typ.Type = Ptrto(Types[TUINTPTR])
978 fast = Nod(OEQ, tab, typ)
979 break
980 }
981 fast = Nod(OANDAND,
982 Nod(ONE, nodnil(), tab),
983 Nod(OEQ, itabType(tab), typename(t)),
984 )
985 case 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700986 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700987 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700988 }
989 if fast != nil {
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700990 if isblank(res) {
991 if Debug_typeassert > 0 {
992 Warn("type assertion (ok only) inlined")
993 }
994 n = Nod(OAS, ok, fast)
995 n = typecheck(n, Etop)
996 } else {
997 if Debug_typeassert > 0 {
998 Warn("type assertion (scalar result) inlined")
999 }
1000 n = Nod(OIF, ok, nil)
1001 n.Likely = 1
1002 if isblank(ok) {
1003 n.Left = fast
1004 } else {
1005 n.Ninit.Set1(Nod(OAS, ok, fast))
1006 }
1007 n.Nbody.Set1(Nod(OAS, res, ifaceData(from, res.Type)))
1008 n.Rlist.Set1(Nod(OAS, res, nil))
1009 n = typecheck(n, Etop)
Russ Cox4224d812015-03-20 00:06:10 -04001010 }
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001011 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -07001012 }
1013 }
1014
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001015 var resptr *Node // &res
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -07001016 if isblank(res) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001017 resptr = nodnil()
1018 } else {
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -07001019 resptr = Nod(OADDR, res, nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001020 }
1021 resptr.Etype = 1 // addr does not escape
1022
Russ Cox4224d812015-03-20 00:06:10 -04001023 if Debug_typeassert > 0 {
1024 Warn("type assertion not inlined")
1025 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001026 fn := syslook(assertFuncName(from.Type, t, true))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001027 fn = substArgTypes(fn, from.Type, t)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001028 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
1029 n = Nod(OAS, ok, call)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001030 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05001031
Russ Cox4224d812015-03-20 00:06:10 -04001032 case ODOTTYPE, ODOTTYPE2:
1033 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001034 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -04001035 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001036 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001037
1038 case OCONVIFACE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001039 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001040
Michel Lespinasse7427f2c2016-03-18 16:20:20 -07001041 // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
1042 if isdirectiface(n.Left.Type) {
1043 var t *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001044 if n.Type.IsEmptyInterface() {
Michel Lespinasse7427f2c2016-03-18 16:20:20 -07001045 t = typename(n.Left.Type)
1046 } else {
1047 t = itabname(n.Left.Type, n.Type)
1048 }
1049 l := Nod(OEFACE, t, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001050 l.Type = n.Type
1051 l.Typecheck = n.Typecheck
1052 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001053 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001054 }
1055
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001056 var ll []*Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001057 if n.Type.IsEmptyInterface() {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001058 if !n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001059 ll = append(ll, typename(n.Left.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001060 }
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001061 } else {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001062 if n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001063 ll = append(ll, typename(n.Type))
1064 } else {
1065 ll = append(ll, itabname(n.Left.Type, n.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001066 }
1067 }
1068
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001069 if n.Left.Type.IsInterface() {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001070 ll = append(ll, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001071 } else {
1072 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001073 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001074 // the conversions it could see. comparison of an interface
1075 // with a non-interface, especially in a switch on interface value
1076 // with non-interface cases, is not visible to orderstmt, so we
1077 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001078 if islvalue(n.Left) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001079 ll = append(ll, Nod(OADDR, n.Left, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001080 } else {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001081 ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001082 }
David Chase22701332015-03-27 11:21:14 -04001083 dowidth(n.Left.Type)
1084 r := nodnil()
1085 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1086 // Allocate stack buffer for value stored in interface.
1087 r = temp(n.Left.Type)
1088 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001089 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001090 init.Append(r)
David Chase22701332015-03-27 11:21:14 -04001091 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001092 r = typecheck(r, Erv)
David Chase22701332015-03-27 11:21:14 -04001093 }
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001094 ll = append(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001095 }
1096
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001097 fn := syslook(convFuncName(n.Left.Type, n.Type))
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001098 if !n.Left.Type.IsInterface() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001099 fn = substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001100 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001101 fn = substArgTypes(fn, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001102 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001103 dowidth(fn.Type)
1104 n = Nod(OCALL, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001105 n.List.Set(ll)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001106 n = typecheck(n, Erv)
1107 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001108
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001109 case OCONV, OCONVNOP:
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07001110 if Thearch.LinkArch.Family == sys.ARM {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001111 if n.Left.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001112 if n.Type.Etype == TINT64 {
1113 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001114 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001115 }
1116
1117 if n.Type.Etype == TUINT64 {
1118 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001119 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001120 }
1121 }
1122
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001123 if n.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001124 if n.Left.Type.Etype == TINT64 {
Cherry Zhang59e11d72016-05-31 11:27:16 -04001125 n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001126 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001127 }
1128
1129 if n.Left.Type.Etype == TUINT64 {
Cherry Zhang59e11d72016-05-31 11:27:16 -04001130 n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001131 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001132 }
1133 }
1134 }
1135
Keith Randalldf2f8132016-07-21 10:37:59 -07001136 if Thearch.LinkArch.Family == sys.I386 {
1137 if n.Left.Type.IsFloat() {
1138 if n.Type.Etype == TINT64 {
1139 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1140 break
1141 }
1142
1143 if n.Type.Etype == TUINT64 {
1144 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1145 break
1146 }
Cherry Zhange6f1a882016-08-16 12:14:54 -04001147 if n.Type.Etype == TUINT32 || n.Type.Etype == TUINT || n.Type.Etype == TUINTPTR {
Keith Randalldf2f8132016-07-21 10:37:59 -07001148 n = mkcall("float64touint32", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1149 break
1150 }
1151 }
1152 if n.Type.IsFloat() {
1153 if n.Left.Type.Etype == TINT64 {
1154 n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
1155 break
1156 }
1157
1158 if n.Left.Type.Etype == TUINT64 {
1159 n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
1160 break
1161 }
Cherry Zhange6f1a882016-08-16 12:14:54 -04001162 if n.Left.Type.Etype == TUINT32 || n.Left.Type.Etype == TUINT || n.Left.Type.Etype == TUINTPTR {
Keith Randalldf2f8132016-07-21 10:37:59 -07001163 n = conv(mkcall("uint32tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT32])), n.Type)
1164 break
1165 }
1166 }
1167 }
1168
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001169 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001170
1171 case OANDNOT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001172 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001173 n.Op = OAND
1174 n.Right = Nod(OCOM, n.Right, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001175 n.Right = typecheck(n.Right, Erv)
1176 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001177
1178 case OMUL:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001179 n.Left = walkexpr(n.Left, init)
1180 n.Right = walkexpr(n.Right, init)
1181 n = walkmul(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001182
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001183 case ODIV, OMOD:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001184 n.Left = walkexpr(n.Left, init)
1185 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001186
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001187 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001188 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001189
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001190 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001191 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001192 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1193 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001194 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001195 }
1196
1197 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001198 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001199 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001200 }
1201
1202 // Try rewriting as shifts or magic multiplies.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001203 n = walkdiv(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001204
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001205 // rewrite 64-bit div and mod into function calls
1206 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001207 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001208 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001209 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001210 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001211 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001212 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001213 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001214 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001215 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001216 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001217 }
1218 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001219 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001220 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001221 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001222 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001223 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001224 }
1225
Russ Cox8c195bd2015-02-13 14:40:36 -05001226 case OINDEX:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001227 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001228
1229 // save the original node for bounds checking elision.
1230 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001231 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001232
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001233 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001234
1235 // if range of type cannot exceed static array bound,
1236 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001237 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001238 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001239 }
Russ Cox382b44e2015-02-23 16:07:24 -05001240 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001241 if t != nil && t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001242 t = t.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05001243 }
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001244 if t.IsArray() {
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001245 n.Bounded = bounded(r, t.NumElem())
Russ Coxdc7b54b2015-02-17 22:13:49 -05001246 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001247 Warn("index bounds check elided")
1248 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001249 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001250 Yyerror("index out of bounds")
1251 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001252 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001253 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001254 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001255 Warn("index bounds check elided")
1256 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001257 if Smallintconst(n.Right) {
1258 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001259 Yyerror("index out of bounds")
1260 } else {
1261 // replace "abc"[1] with 'b'.
1262 // delayed until now because "abc"[1] is not
1263 // an ideal constant.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001264 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05001265
Russ Cox81d58102015-05-27 00:47:05 -04001266 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001267 n.Typecheck = 1
1268 }
1269 }
1270 }
1271
Russ Coxdc7b54b2015-02-17 22:13:49 -05001272 if Isconst(n.Right, CTINT) {
Robert Griesemer07749ae2016-03-21 10:52:03 -07001273 if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || n.Right.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001274 Yyerror("index out of bounds")
1275 }
1276 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001277
1278 case OINDEXMAP:
1279 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001280 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001281 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001282 n.Left = walkexpr(n.Left, init)
1283 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001284
Russ Cox382b44e2015-02-23 16:07:24 -05001285 t := n.Left.Type
1286 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001287 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08001288 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001289 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001290 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001291 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001292 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001293 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001294 p = "mapaccess1_faststr"
1295 }
1296 }
1297
Russ Cox382b44e2015-02-23 16:07:24 -05001298 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001299 if p != "" {
1300 // fast versions take key by value
1301 key = n.Right
1302 } else {
1303 // standard version takes key by reference.
1304 // orderexpr made sure key is addressable.
1305 key = Nod(OADDR, n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001306 p = "mapaccess1"
1307 }
1308
Keith Randall60fd32a2016-04-19 08:31:04 -07001309 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
1310 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
1311 } else {
1312 p = "mapaccess1_fat"
1313 z := zeroaddr(w)
1314 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
1315 }
Keith Randall3c1a4c12016-04-19 21:06:53 -07001316 n.NonNil = true // mapaccess always returns a non-nil pointer
Russ Cox8c195bd2015-02-13 14:40:36 -05001317 n = Nod(OIND, n, nil)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001318 n.Type = t.Val()
Russ Cox8c195bd2015-02-13 14:40:36 -05001319 n.Typecheck = 1
1320
Russ Cox8c195bd2015-02-13 14:40:36 -05001321 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001322 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001323
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001324 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001325 n.Left = walkexpr(n.Left, init)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001326 low, high, max := n.SliceBounds()
1327 low = walkexpr(low, init)
1328 if low != nil && iszero(low) {
1329 // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
1330 low = nil
Russ Coxd4472792015-05-06 12:35:53 -04001331 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001332 high = walkexpr(high, init)
1333 max = walkexpr(max, init)
1334 n.SetSliceBounds(low, high, max)
1335 if n.Op.IsSlice3() {
1336 if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
1337 // Reduce x[i:j:cap(x)] to x[i:j].
1338 if n.Op == OSLICE3 {
1339 n.Op = OSLICE
1340 } else {
1341 n.Op = OSLICEARR
1342 }
1343 n = reduceSlice(n)
Russ Coxd4472792015-05-06 12:35:53 -04001344 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001345 } else {
Russ Coxd4472792015-05-06 12:35:53 -04001346 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001347 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001348
1349 case OADDR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001350 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001351
1352 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001353 if n.Esc == EscNone {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001354 if n.Type.Elem().Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001355 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001356 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001357 r := temp(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001358 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001359 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001360 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001361 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001362 r = typecheck(r, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001363 n = r
1364 } else {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001365 n = callnew(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001366 }
1367
Russ Cox8c195bd2015-02-13 14:40:36 -05001368 // If one argument to the comparison is an empty string,
1369 // comparing the lengths instead will yield the same result
1370 // without the function call.
1371 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001372 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 +02001373 // TODO(marvin): Fix Node.EType type union.
1374 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001375 r = typecheck(r, Erv)
1376 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001377 r.Type = n.Type
1378 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001379 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001380 }
1381
1382 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001383 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 +02001384 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001385 r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001386 r = typecheck(r, Erv)
1387 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001388 r.Type = n.Type
1389 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001390 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001391 }
1392
Russ Cox382b44e2015-02-23 16:07:24 -05001393 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001394 // TODO(marvin): Fix Node.EType type union.
1395 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001396 // prepare for rewrite below
1397 n.Left = cheapexpr(n.Left, init)
1398
1399 n.Right = cheapexpr(n.Right, init)
1400
1401 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1402
1403 // quick check of len before full compare for == or !=
1404 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001405 // TODO(marvin): Fix Node.EType type union.
1406 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001407 // len(left) == len(right) && eqstring(left, right)
1408 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1409 } else {
1410 // len(left) != len(right) || !eqstring(left, right)
1411 r = Nod(ONOT, r, nil)
1412
1413 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1414 }
1415
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001416 r = typecheck(r, Erv)
1417 r = walkexpr(r, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001418 } else {
1419 // sys_cmpstring(s1, s2) :: 0
1420 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1421
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001422 // TODO(marvin): Fix Node.EType type union.
1423 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001424 }
1425
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001426 r = typecheck(r, Erv)
Matthew Dempsky3efefd92016-03-30 14:56:08 -07001427 if !n.Type.IsBoolean() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001428 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001429 }
1430 r.Type = n.Type
1431 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001432
1433 case OADDSTR:
1434 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001435
1436 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001437 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001438 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001439
1440 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001441 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001442
1443 // cannot use chanfn - closechan takes any, not chan any
1444 case OCLOSE:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001445 fn := syslook("closechan")
Russ Cox8c195bd2015-02-13 14:40:36 -05001446
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001447 fn = substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001448 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001449
1450 case OMAKECHAN:
1451 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 -05001452
1453 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001454 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001455
Russ Cox382b44e2015-02-23 16:07:24 -05001456 a := nodnil() // hmap buffer
1457 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001458 if n.Esc == EscNone {
1459 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001460 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001461
1462 a = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001463 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001464 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001465 a = Nod(OADDR, var_, nil)
1466
1467 // Allocate one bucket on stack.
1468 // Maximum key/value size is 128 bytes, larger objects
1469 // are stored with an indirection. So max bucket size is 2048+eps.
1470 var_ = temp(mapbucket(t))
1471
1472 r = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001473 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001474 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001475 r = Nod(OADDR, var_, nil)
1476 }
1477
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001478 fn := syslook("makemap")
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001479 fn = substArgTypes(fn, hmap(t), mapbucket(t), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05001480 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001481
1482 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001483 l := n.Left
1484 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001485 if r == nil {
1486 r = safeexpr(l, init)
1487 l = r
1488 }
Russ Cox382b44e2015-02-23 16:07:24 -05001489 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001490 if n.Esc == EscNone {
1491 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001492 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001493 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001494 // var arr [r]T
1495 // n = arr[:l]
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001496 t = aindex(r, t.Elem()) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001497 var_ := temp(t)
1498 a := Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001499 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001500 init.Append(a)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001501 r := Nod(OSLICE, var_, nil) // arr[:l]
1502 r.SetSliceBounds(nil, l, nil)
1503 r = conv(r, n.Type) // in case n.Type is named.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001504 r = typecheck(r, Erv)
1505 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001506 n = r
1507 } else {
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001508 // makeslice(et *Type, nel int64, max int64) (ary []any)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001509 fn := syslook("makeslice")
Russ Cox8c195bd2015-02-13 14:40:36 -05001510
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001511 fn = substArgTypes(fn, t.Elem()) // any-1
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001512 n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001513 }
1514
Russ Cox8c195bd2015-02-13 14:40:36 -05001515 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001516 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001517 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001518 t := aindex(Nodintconst(4), Types[TUINT8])
1519 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001520 a = Nod(OADDR, var_, nil)
1521 }
1522
1523 // intstring(*[4]byte, rune)
1524 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1525
Russ Cox8c195bd2015-02-13 14:40:36 -05001526 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001527 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001528 if n.Esc == EscNone {
1529 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001530 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001531
1532 a = Nod(OADDR, temp(t), nil)
1533 }
1534
1535 // slicebytetostring(*[32]byte, []byte) string;
1536 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1537
Russ Cox8c195bd2015-02-13 14:40:36 -05001538 // slicebytetostringtmp([]byte) string;
1539 case OARRAYBYTESTRTMP:
1540 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1541
Russ Cox8c195bd2015-02-13 14:40:36 -05001542 // slicerunetostring(*[32]byte, []rune) string;
1543 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001544 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001545
1546 if n.Esc == EscNone {
1547 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001548 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001549
1550 a = Nod(OADDR, temp(t), nil)
1551 }
1552
1553 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001554
1555 // stringtoslicebyte(*32[byte], string) []byte;
1556 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001557 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001558
1559 if n.Esc == EscNone {
1560 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001561 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001562
1563 a = Nod(OADDR, temp(t), nil)
1564 }
1565
1566 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001567
1568 // stringtoslicebytetmp(string) []byte;
1569 case OSTRARRAYBYTETMP:
1570 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1571
Russ Cox8c195bd2015-02-13 14:40:36 -05001572 // stringtoslicerune(*[32]rune, string) []rune
1573 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001574 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001575
1576 if n.Esc == EscNone {
1577 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001578 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001579
1580 a = Nod(OADDR, temp(t), nil)
1581 }
1582
1583 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001584
1585 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1586 case OCMPIFACE:
1587 if !Eqtype(n.Left.Type, n.Right.Type) {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001588 Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001589 }
Russ Cox382b44e2015-02-23 16:07:24 -05001590 var fn *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001591 if n.Left.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001592 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001593 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001594 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001595 }
1596
1597 n.Right = cheapexpr(n.Right, init)
1598 n.Left = cheapexpr(n.Left, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001599 fn = substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001600 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001601 // TODO(marvin): Fix Node.EType type union.
1602 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001603 r = Nod(ONOT, r, nil)
1604 }
1605
1606 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001607 // TODO(marvin): Fix Node.EType type union.
1608 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001609 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1610 } else {
1611 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1612 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001613 r = typecheck(r, Erv)
1614 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001615 r.Type = n.Type
1616 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001617
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001618 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Josh Bleecher Snyder3c6e60c2016-04-19 12:08:33 -07001619 if isStaticCompositeLiteral(n) {
Keith Randallb024ed02016-04-18 11:17:55 -07001620 // n can be directly represented in the read-only data section.
1621 // Make direct reference to the static data. See issue 12841.
1622 vstat := staticname(n.Type, 0)
1623 if n.Op == OSTRUCTLIT {
1624 structlit(0, 1, n, vstat, init)
1625 } else {
1626 arraylit(0, 1, n, vstat, init)
1627 }
1628 n = vstat
1629 n = typecheck(n, Erv)
1630 break
1631 }
Russ Cox382b44e2015-02-23 16:07:24 -05001632 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001633 anylit(0, n, var_, init)
1634 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001635
1636 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001637 n1 := n.Right
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001638 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001639 n1 = walkexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001640 n1 = Nod(OADDR, n1, nil)
1641 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001642
1643 case OCLOSURE:
1644 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001645
1646 case OCALLPART:
1647 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001648 }
1649
Russ Cox8c195bd2015-02-13 14:40:36 -05001650 // Expressions that are constant at run time but not
1651 // considered const by the language spec are not turned into
1652 // constants until walk. For example, if n is y%1 == 0, the
1653 // walk of y%1 may have replaced it by 0.
1654 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001655 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001656
1657 evconst(n)
1658 n.Type = t
1659 if n.Op == OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001660 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001661 }
1662
1663 ullmancalc(n)
1664
1665 if Debug['w'] != 0 && n != nil {
1666 Dump("walk", n)
1667 }
1668
1669 lineno = lno
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001670 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05001671}
1672
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001673// TODO(josharian): combine this with its caller and simplify
Russ Coxd4472792015-05-06 12:35:53 -04001674func reduceSlice(n *Node) *Node {
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001675 low, high, max := n.SliceBounds()
1676 if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
Russ Coxd4472792015-05-06 12:35:53 -04001677 // Reduce x[i:len(x)] to x[i:].
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001678 high = nil
Russ Coxd4472792015-05-06 12:35:53 -04001679 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001680 n.SetSliceBounds(low, high, max)
1681 if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
Russ Coxd4472792015-05-06 12:35:53 -04001682 // Reduce x[:] to x.
1683 if Debug_slice > 0 {
1684 Warn("slice: omit slice operation")
1685 }
1686 return n.Left
1687 }
1688 return n
1689}
1690
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001691func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001692 // convas will turn map assigns into function calls,
1693 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001694 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001695
1696 if l.Op == OINDEXMAP {
1697 return n
1698 }
1699
1700 return convas(n, init)
1701}
1702
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001703func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001704 // check assign expression list to
1705 // a expression list. called in
1706 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001707
1708 // ensure order of evaluation for function calls
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001709 for i := range nl {
1710 nl[i] = safeexpr(nl[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001711 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001712 for i1 := range nr {
1713 nr[i1] = safeexpr(nr[i1], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001714 }
1715
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001716 var nn []*Node
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001717 i := 0
1718 for ; i < len(nl); i++ {
1719 if i >= len(nr) {
1720 break
1721 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001722 // Do not generate 'x = x' during return. See issue 4014.
Russ Coxb6dc3e62016-05-25 01:33:24 -04001723 if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001724 continue
1725 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001726 nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001727 }
1728
1729 // cannot happen: caller checked that lists had same length
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001730 if i < len(nl) || i < len(nr) {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001731 var nln, nrn Nodes
1732 nln.Set(nl)
1733 nrn.Set(nr)
Dave Cheney2da642a2016-04-27 15:15:47 +10001734 Yyerror("error in shape across %v %v %v / %d %d [%s]", hconv(nln, FmtSign), op, hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -05001735 }
1736 return nn
1737}
1738
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001739// l is an lv and rt is the type of an rv
1740// return 1 if this implies a function call
1741// evaluating the lv or a function call
1742// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001743func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001744 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001745 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001746 }
Russ Cox175929b2015-03-02 14:22:05 -05001747 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001748 if needwritebarrier(l, &r) {
1749 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001750 }
1751 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001752 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001753 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001754 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001755}
1756
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001757// check assign type list to
1758// a expression list. called in
1759// expr-list = func()
1760func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
1761 r, saver := IterFields(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001762
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001763 var nn, mm []*Node
1764 var ullmanOverflow bool
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001765 var i int
1766 for i = 0; i < nl.Len(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001767 if r == nil {
1768 break
1769 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001770 l := nl.Index(i)
Russ Cox8c195bd2015-02-13 14:40:36 -05001771 if isblank(l) {
Matthew Dempsky7758a942016-03-08 15:02:40 -08001772 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001773 continue
1774 }
1775
1776 // any lv that causes a fn call must be
1777 // deferred until all the return arguments
1778 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001779 if fncall(l, r.Type) {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001780 tmp := temp(r.Type)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001781 tmp = typecheck(tmp, Erv)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001782 a := Nod(OAS, l, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001783 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001784 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001785 l = tmp
1786 }
1787
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001788 a := Nod(OAS, l, nodarg(r, fp))
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 a = convas(a, init)
1790 ullmancalc(a)
1791 if a.Ullman >= UINF {
1792 Dump("ascompatet ucount", a)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001793 ullmanOverflow = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001794 }
1795
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001796 nn = append(nn, a)
Matthew Dempsky7758a942016-03-08 15:02:40 -08001797 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001798 }
1799
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001800 if i < nl.Len() || r != nil {
Matthew Dempskydbed1c62016-03-17 13:26:08 -07001801 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
Russ Cox8c195bd2015-02-13 14:40:36 -05001802 }
1803
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001804 if ullmanOverflow {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001805 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001807 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001808}
1809
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001810// package all the arguments that match a ... T parameter into a []T.
Matthew Dempsky2e936902016-03-14 01:20:49 -07001811func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001812 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001813 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001814 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001815 }
1816
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001817 tslice := typSlice(l.Type.Elem())
Josh Bleecher Snyderb6b144b2015-05-04 15:01:29 -07001818 tslice.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001819
Russ Cox382b44e2015-02-23 16:07:24 -05001820 var n *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001821 if len(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001822 n = nodnil()
1823 n.Type = tslice
1824 } else {
1825 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001826 if ddd != nil && prealloc[ddd] != nil {
1827 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001828 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001829 n.List.Set(lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001830 n.Esc = esc
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001831 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001833 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001834 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001835 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001836 }
1837
Russ Cox382b44e2015-02-23 16:07:24 -05001838 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001839 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001840 return nn
1841}
1842
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001843// helpers for shape errors
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001844func dumptypes(nl *Type, what string) string {
1845 s := ""
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001846 for _, l := range nl.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001847 if s != "" {
1848 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001849 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07001850 s += Fldconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001851 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001852 if s == "" {
1853 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001854 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001855 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001856}
1857
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001858func dumpnodetypes(l []*Node, what string) string {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001859 s := ""
1860 for _, r := range l {
1861 if s != "" {
1862 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001863 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001864 s += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001865 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001866 if s == "" {
1867 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001868 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001869 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001870}
1871
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001872// check assign expression list to
1873// a type list. called in
1874// return expr-list
1875// func(expr-list)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001876func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05001877 lr0 := lr
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001878 l, savel := IterFields(nl)
Russ Cox175929b2015-03-02 14:22:05 -05001879 var r *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001880 if len(lr) > 0 {
1881 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001882 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001883 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001884
1885 // f(g()) where g has multiple return values
Josh Bleecher Snyderfda831e2016-04-05 16:44:07 -07001886 if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001887 // optimization - can do block copy
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001888 if eqtypenoname(r.Type, nl) {
1889 arg := nodarg(nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001890 r = Nod(OCONVNOP, r, nil)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001891 r.Type = arg.Type
1892 nn = []*Node{convas(Nod(OAS, arg, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001893 goto ret
1894 }
1895
1896 // conversions involved.
1897 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001898 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001899
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001900 for _, l := range r.Type.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001901 tmp := temp(l.Type)
1902 alist = append(alist, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001903 }
1904
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001905 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001906 a.List.Set(alist)
1907 a.Rlist.Set(lr)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001908 a = typecheck(a, Etop)
1909 a = walkstmt(a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001910 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001911 lr = alist
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001912 r = lr[0]
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001913 l, savel = IterFields(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -05001914 }
1915
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001916 for {
1917 if l != nil && l.Isddd {
1918 // the ddd parameter must be last
1919 ll := savel.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001920
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001921 if ll != nil {
1922 Yyerror("... must be last argument")
Russ Cox8c195bd2015-02-13 14:40:36 -05001923 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001924
1925 // special case --
1926 // only if we are assigning a single ddd
1927 // argument to a ddd parameter then it is
Eric Engestrom7a8caf72016-04-03 12:43:27 +01001928 // passed through unencapsulated
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001929 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
1930 a := Nod(OAS, nodarg(l, fp), r)
1931 a = convas(a, init)
1932 nn = append(nn, a)
1933 break
1934 }
1935
1936 // normal case -- make a slice of all
1937 // remaining arguments and pass it to
1938 // the ddd parameter.
1939 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1940
1941 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001942 }
1943
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001944 if l == nil || r == nil {
1945 if l != nil || r != nil {
1946 l1 := dumptypes(nl, "expected")
1947 l2 := dumpnodetypes(lr0, "given")
1948 if l != nil {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001949 Yyerror("not enough arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001950 } else {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001951 Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001952 }
1953 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001954
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001955 break
1956 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001957
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001958 a := Nod(OAS, nodarg(l, fp), r)
1959 a = convas(a, init)
1960 nn = append(nn, a)
1961
1962 l = savel.Next()
1963 r = nil
1964 lr = lr[1:]
1965 if len(lr) > 0 {
1966 r = lr[0]
1967 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001968 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001969
1970ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001971 for _, n := range nn {
1972 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001973 }
1974 return nn
1975}
1976
1977// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001978func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001979 var r *Node
1980 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001981 var on *Node
1982 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001983 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001984
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001985 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001986 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001987 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001988 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001989
1990 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001991 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001992
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001993 calls = append(calls, mkcall("printlock", nil, init))
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001994 for i1, n1 := range all.Slice() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001995 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001996 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001997 }
1998
Russ Coxdc7b54b2015-02-17 22:13:49 -05001999 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05002000
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002001 n = n1
Russ Cox8c195bd2015-02-13 14:40:36 -05002002 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002003 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002004 case CTRUNE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002005 n = defaultlit(n, runetype)
Russ Cox8c195bd2015-02-13 14:40:36 -05002006
2007 case CTINT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002008 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002009
2010 case CTFLT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002011 n = defaultlit(n, Types[TFLOAT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002012 }
2013 }
2014
2015 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002016 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002017 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002018 n = defaultlit(n, nil)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002019 all.SetIndex(i1, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002020 if n.Type == nil || n.Type.Etype == TFORW {
2021 continue
2022 }
2023
2024 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002025 et = n.Type.Etype
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002026 if n.Type.IsInterface() {
Matthew Dempsky00e5a682016-04-01 13:36:24 -07002027 if n.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002028 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002029 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002030 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002031 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002032 on = substArgTypes(on, n.Type) // any-1
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07002033 } else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002034 on = syslook("printpointer")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002035 on = substArgTypes(on, n.Type) // any-1
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002036 } else if n.Type.IsSlice() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002037 on = syslook("printslice")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002038 on = substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002039 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002040 if et == TUINT64 {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002041 if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002042 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002043 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002044 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002045 }
2046 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002047 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002048 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002049 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002050 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002051 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002052 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002053 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002054 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05002055 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002056 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05002057 } else {
2058 badtype(OPRINT, n.Type, nil)
2059 continue
2060 }
2061
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -07002062 t = on.Type.Params().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002063
2064 if !Eqtype(t, n.Type) {
2065 n = Nod(OCONV, n, nil)
2066 n.Type = t
2067 }
2068
2069 r = Nod(OCALL, on, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002070 r.List.Append(n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002071 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002072 }
2073
2074 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002075 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002076 }
2077
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002078 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002079
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002080 typecheckslice(calls, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002081 walkexprlist(calls, init)
2082
2083 r = Nod(OEMPTY, nil, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002084 r = typecheck(r, Etop)
2085 r = walkexpr(r, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002086 r.Ninit.Set(calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002087 return r
2088}
2089
2090func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002091 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002092 fn := syslook("newobject")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002093 fn = substArgTypes(fn, t)
Keith Randall3c1a4c12016-04-19 21:06:53 -07002094 v := mkcall1(fn, Ptrto(t), nil, typename(t))
2095 v.NonNil = true
2096 return v
Russ Cox8c195bd2015-02-13 14:40:36 -05002097}
2098
Russ Cox3b6e86f2015-06-29 15:17:14 -04002099func iscallret(n *Node) bool {
2100 n = outervalue(n)
2101 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2102}
2103
Russ Coxdc7b54b2015-02-17 22:13:49 -05002104func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002105 n = outervalue(n)
2106
2107 // If n is *autotmp and autotmp = &foo, replace n with foo.
2108 // We introduce such temps when initializing struct literals.
2109 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002110 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002111 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2112 n = defn.Right.Left
2113 }
2114 }
2115
2116 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002117 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002118 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002119
2120 case ONAME:
2121 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002122 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002123 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002124 }
2125 }
2126
Russ Coxdc7b54b2015-02-17 22:13:49 -05002127 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002128}
2129
Russ Coxdc7b54b2015-02-17 22:13:49 -05002130func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002131 n = outervalue(n)
2132
2133 switch n.Op {
2134 case ONAME:
2135 switch n.Class {
2136 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002137 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002138 }
2139 }
2140
Russ Coxdc7b54b2015-02-17 22:13:49 -05002141 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002142}
2143
2144// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002145func needwritebarrier(l *Node, r *Node) bool {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002146 if !use_writebarrier {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002147 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002148 }
2149
2150 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002151 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002152 }
2153
2154 // No write barrier for write of non-pointers.
2155 dowidth(l.Type)
2156
2157 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002158 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002159 }
2160
2161 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002162 if isstack(l) {
2163 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002164 }
2165
Russ Cox9f90f312015-06-29 12:49:25 -04002166 // No write barrier for implicit zeroing.
2167 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002168 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002169 }
2170
Russ Cox9f90f312015-06-29 12:49:25 -04002171 // Ignore no-op conversions when making decision.
2172 // Ensures that xp = unsafe.Pointer(&x) is treated
2173 // the same as xp = &x.
2174 for r.Op == OCONVNOP {
2175 r = r.Left
2176 }
2177
2178 // No write barrier for zeroing or initialization to constant.
2179 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002180 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002181 }
2182
2183 // No write barrier for storing static (read-only) data.
2184 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002185 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002186 }
2187
2188 // No write barrier for storing address of stack values,
2189 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002190 if r.Op == OADDR && isstack(r.Left) {
2191 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002192 }
2193
2194 // No write barrier for storing address of global, which
2195 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002196 if r.Op == OADDR && isglobal(r.Left) {
2197 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002198 }
2199
Austin Clements3e54ca92016-03-16 18:22:58 -04002200 // No write barrier for storing global function, which is live
2201 // no matter what.
2202 if r.Op == ONAME && r.Class == PFUNC {
2203 return false
2204 }
2205
Russ Cox8c195bd2015-02-13 14:40:36 -05002206 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002207 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002208}
2209
2210// TODO(rsc): Perhaps componentgen should run before this.
2211
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002212func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002213 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002214 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002215 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002216 }
Russ Cox972a4782015-05-21 15:00:06 -04002217 n.Op = OASWB
2218 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002219 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002220 return n
2221}
2222
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002223func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002224 if n.Op != OAS {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10002225 Fatalf("convas: not OAS %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002226 }
2227
2228 n.Typecheck = 1
2229
Russ Cox382b44e2015-02-23 16:07:24 -05002230 var lt *Type
2231 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002232 if n.Left == nil || n.Right == nil {
2233 goto out
2234 }
2235
2236 lt = n.Left.Type
2237 rt = n.Right.Type
2238 if lt == nil || rt == nil {
2239 goto out
2240 }
2241
2242 if isblank(n.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002243 n.Right = defaultlit(n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002244 goto out
2245 }
2246
2247 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002248 map_ := n.Left.Left
2249 key := n.Left.Right
2250 val := n.Right
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002251 map_ = walkexpr(map_, init)
2252 key = walkexpr(key, init)
2253 val = walkexpr(val, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002254
2255 // orderexpr made sure key and val are addressable.
2256 key = Nod(OADDR, key, nil)
2257
2258 val = Nod(OADDR, val, nil)
2259 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2260 goto out
2261 }
2262
2263 if !Eqtype(lt, rt) {
2264 n.Right = assignconv(n.Right, lt, "assignment")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002265 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002266 }
2267
2268out:
2269 ullmancalc(n)
2270 return n
2271}
2272
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002273// from ascompat[te]
2274// evaluating actual function arguments.
2275// f(a,b)
2276// if there is exactly one function expr,
2277// then it is done first. otherwise must
2278// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002279func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002280 c := 0 // function calls
2281 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002282
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002283 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002284 t++
2285 ullmancalc(n)
2286 if n.Ullman >= UINF {
2287 c++
2288 }
2289 }
2290
2291 if c == 0 || t == 1 {
2292 return all
2293 }
2294
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002295 var g []*Node // fncalls assigned to tempnames
2296 var f *Node // last fncall assigned to stack
2297 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002298 d := 0
2299 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002300 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002301 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002302 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002303 continue
2304 }
2305
2306 d++
2307 if d == c {
2308 f = n
2309 continue
2310 }
2311
2312 // make assignment of fncall to tempname
2313 a = temp(n.Right.Type)
2314
2315 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002316 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002317
2318 // put normal arg assignment on list
2319 // with fncall replaced by tempname
2320 n.Right = a.Left
2321
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002322 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002323 }
2324
2325 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002326 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002327 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002328 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002329}
2330
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002331// from ascompat[ee]
2332// a,b = c,d
2333// simultaneous assignment. there cannot
2334// be later use of an earlier lvalue.
2335//
2336// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002337func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002338 var l *Node
2339
2340 // If a needed expression may be affected by an
2341 // earlier assignment, make an early copy of that
2342 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002343 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002344
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002345 var mapinit Nodes
2346 for i, n := range all {
2347 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002348
2349 // Save subexpressions needed on left side.
2350 // Drill through non-dereferences.
2351 for {
2352 if l.Op == ODOT || l.Op == OPAREN {
2353 l = l.Left
2354 continue
2355 }
2356
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002357 if l.Op == OINDEX && l.Left.Type.IsArray() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002358 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002359 l = l.Left
2360 continue
2361 }
2362
2363 break
2364 }
2365
2366 switch l.Op {
2367 default:
Dave Cheney733f8352016-04-27 19:34:17 +10002368 Fatalf("reorder3 unexpected lvalue %#v", l.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002369
2370 case ONAME:
2371 break
2372
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002373 case OINDEX, OINDEXMAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002374 l.Left = reorder3save(l.Left, all, i, &early)
2375 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002376 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002377 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002378 }
2379
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002380 case OIND, ODOTPTR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002381 l.Left = reorder3save(l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002382 }
2383
2384 // Save expression on right side.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002385 all[i].Right = reorder3save(all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002386 }
2387
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002388 early = append(mapinit.Slice(), early...)
2389 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002390}
2391
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002392// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002393// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002394// copy into a temporary during *early and
2395// replace *np with that temp.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002396// The result of reorder3save MUST be assigned back to n, e.g.
2397// n.Left = reorder3save(n.Left, all, i, early)
2398func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002399 if !aliased(n, all, i) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002400 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002401 }
2402
Russ Cox382b44e2015-02-23 16:07:24 -05002403 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002404 q = Nod(OAS, q, n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002405 q = typecheck(q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002406 *early = append(*early, q)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002407 return q.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002408}
2409
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002410// what's the outer value that a write to n affects?
2411// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002412func outervalue(n *Node) *Node {
2413 for {
2414 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002415 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002416 }
2417 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2418 n = n.Left
2419 continue
2420 }
2421
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002422 if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002423 n = n.Left
2424 continue
2425 }
2426
2427 break
2428 }
2429
2430 return n
2431}
2432
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002433// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002434// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002435func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002436 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002437 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002438 }
2439
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002440 // Treat all fields of a struct as referring to the whole struct.
2441 // We could do better but we would have to keep track of the fields.
2442 for n.Op == ODOT {
2443 n = n.Left
2444 }
2445
Russ Cox8c195bd2015-02-13 14:40:36 -05002446 // Look for obvious aliasing: a variable being assigned
2447 // during the all list and appearing in n.
2448 // Also record whether there are any writes to main memory.
2449 // Also record whether there are any writes to variables
2450 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002451 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002452
Russ Cox382b44e2015-02-23 16:07:24 -05002453 varwrite := 0
2454 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002455 for _, an := range all[:i] {
2456 a = outervalue(an.Left)
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002457
2458 for a.Op == ODOT {
2459 a = a.Left
2460 }
2461
Russ Cox8c195bd2015-02-13 14:40:36 -05002462 if a.Op != ONAME {
2463 memwrite = 1
2464 continue
2465 }
2466
2467 switch n.Class {
2468 default:
2469 varwrite = 1
2470 continue
2471
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002472 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002473 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002474 varwrite = 1
2475 continue
2476 }
2477
Russ Coxdc7b54b2015-02-17 22:13:49 -05002478 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002479 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002480 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002481 }
2482 }
2483 }
2484
2485 // The variables being written do not appear in n.
2486 // However, n might refer to computed addresses
2487 // that are being written.
2488
2489 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002490 if memwrite == 0 && varwrite == 0 {
2491 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002492 }
2493
2494 // If n does not refer to computed addresses
2495 // (that is, if n only refers to variables whose addresses
2496 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002497 if varexpr(n) {
2498 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002499 }
2500
2501 // Otherwise, both the writes and n refer to computed memory addresses.
2502 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002503 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002504}
2505
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002506// does the evaluation of n only refer to variables
2507// whose addresses have not been taken?
2508// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002509func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002510 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002511 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002512 }
2513
2514 switch n.Op {
2515 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002516 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002517
2518 case ONAME:
2519 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002520 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002521 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002522 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002523 }
2524 }
2525
Russ Coxdc7b54b2015-02-17 22:13:49 -05002526 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002527
2528 case OADD,
2529 OSUB,
2530 OOR,
2531 OXOR,
2532 OMUL,
2533 ODIV,
2534 OMOD,
2535 OLSH,
2536 ORSH,
2537 OAND,
2538 OANDNOT,
2539 OPLUS,
2540 OMINUS,
2541 OCOM,
2542 OPAREN,
2543 OANDAND,
2544 OOROR,
Russ Cox8c195bd2015-02-13 14:40:36 -05002545 OCONV,
2546 OCONVNOP,
2547 OCONVIFACE,
2548 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002549 return varexpr(n.Left) && varexpr(n.Right)
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002550
2551 case ODOT: // but not ODOTPTR
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002552 // Should have been handled in aliased.
2553 Fatalf("varexpr unexpected ODOT")
Russ Cox8c195bd2015-02-13 14:40:36 -05002554 }
2555
2556 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002557 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002558}
2559
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002560// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002561func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002562 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002563 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002564 }
2565 switch r.Op {
2566 // match each right given left
2567 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002568 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002569
2570 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002571 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002572 }
2573
Russ Coxdc7b54b2015-02-17 22:13:49 -05002574 if vmatch2(l, r.Left) {
2575 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002576 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002577 if vmatch2(l, r.Right) {
2578 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002579 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002580 for _, n := range r.List.Slice() {
2581 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002582 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002583 }
2584 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002585 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002586}
2587
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002588// is any name mentioned in l also mentioned in r?
2589// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002590func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002591 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002592 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002593 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002594 }
2595 switch l.Op {
2596 case ONAME:
2597 switch l.Class {
Russ Cox20803b82016-05-25 10:29:50 -04002598 case PPARAM, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002599 break
2600
2601 // assignment to non-stack variable
2602 // must be delayed if right has function calls.
2603 default:
2604 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002605 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002606 }
2607 }
2608
2609 return vmatch2(l, r)
2610
2611 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002612 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002613 }
2614
Russ Coxdc7b54b2015-02-17 22:13:49 -05002615 if vmatch1(l.Left, r) {
2616 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002617 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002618 if vmatch1(l.Right, r) {
2619 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002620 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002621 for _, n := range l.List.Slice() {
2622 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002623 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002624 }
2625 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002626 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002627}
2628
Matthew Dempsky2339b132016-03-09 18:54:26 -08002629// paramstoheap returns code to allocate memory for heap-escaped parameters
2630// and to copy non-result prameters' values from the stack.
2631// If out is true, then code is also produced to zero-initialize their
2632// stack memory addresses.
Russ Coxdec1bae2016-05-25 10:01:58 -04002633func paramstoheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002634 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002635 for _, t := range params.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002636 // For precise stacks, the garbage collector assumes results
2637 // are always live, so zero them always.
Russ Coxdec1bae2016-05-25 10:01:58 -04002638 if params.StructType().Funarg == FunargResults {
Russ Cox8c195bd2015-02-13 14:40:36 -05002639 // Defer might stop a panic and show the
2640 // return values as they exist at the time of panic.
2641 // Make sure to zero them on entry to the function.
Russ Coxdec1bae2016-05-25 10:01:58 -04002642 nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002643 }
2644
Russ Coxb6dc3e62016-05-25 01:33:24 -04002645 v := t.Nname
2646 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
2647 v = nil
2648 }
2649 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002650 continue
2651 }
2652
Russ Coxb6dc3e62016-05-25 01:33:24 -04002653 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
2654 nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
2655 if stackcopy.Class == PPARAM {
2656 nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
2657 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002658 }
2659 }
2660
2661 return nn
2662}
2663
Matthew Dempsky2339b132016-03-09 18:54:26 -08002664// returnsfromheap returns code to copy values for heap-escaped parameters
2665// back to the stack.
2666func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002667 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002668 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002669 v := t.Nname
Russ Coxb6dc3e62016-05-25 01:33:24 -04002670 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002671 continue
2672 }
Russ Coxb6dc3e62016-05-25 01:33:24 -04002673 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
2674 nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
2675 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002676 }
2677
2678 return nn
2679}
2680
Matthew Dempsky2339b132016-03-09 18:54:26 -08002681// heapmoves generates code to handle migrating heap-escaped parameters
2682// between the stack and the heap. The generated code is added to Curfn's
2683// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002684func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002685 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002686 lineno = Curfn.Lineno
Russ Coxdec1bae2016-05-25 10:01:58 -04002687 nn := paramstoheap(Curfn.Type.Recvs())
2688 nn = append(nn, paramstoheap(Curfn.Type.Params())...)
2689 nn = append(nn, paramstoheap(Curfn.Type.Results())...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002690 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002691 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002692 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002693 lineno = lno
2694}
2695
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002696func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002697 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002698 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002699 }
2700
Matthew Dempskyc8377612016-03-17 01:47:16 -07002701 n := fn.Type.Params().NumFields()
Russ Cox8c195bd2015-02-13 14:40:36 -05002702
Russ Cox382b44e2015-02-23 16:07:24 -05002703 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002704 r.List.Set(va[:n])
Matthew Dempskyc8377612016-03-17 01:47:16 -07002705 if fn.Type.Results().NumFields() > 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002706 r = typecheck(r, Erv|Efnstruct)
Russ Cox8c195bd2015-02-13 14:40:36 -05002707 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002708 r = typecheck(r, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002709 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002710 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002711 r.Type = t
2712 return r
2713}
2714
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002715func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002716 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002717}
2718
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002719func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002720 return vmkcall(fn, t, init, args)
2721}
2722
2723func conv(n *Node, t *Type) *Node {
2724 if Eqtype(n.Type, t) {
2725 return n
2726 }
2727 n = Nod(OCONV, n, nil)
2728 n.Type = t
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002729 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05002730 return n
2731}
2732
2733func chanfn(name string, n int, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002734 if !t.IsChan() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002735 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002736 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002737 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002738 switch n {
2739 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002740 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002741 case 1:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002742 fn = substArgTypes(fn, t.Elem())
Russ Cox13f9c8b2015-03-08 13:33:49 -04002743 case 2:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002744 fn = substArgTypes(fn, t.Elem(), t.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002745 }
2746 return fn
2747}
2748
2749func mapfn(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002750 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002751 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002752 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002753 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002754 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05002755 return fn
2756}
2757
2758func mapfndel(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002759 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002760 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002761 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002762 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002763 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002764 return fn
2765}
2766
2767func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002768 fn := syslook(name)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002769 fn = substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002770 return fn
2771}
2772
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002773func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002774 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002775 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002776
2777 if c < 2 {
2778 Yyerror("addstr count %d too small", c)
2779 }
2780
Russ Cox382b44e2015-02-23 16:07:24 -05002781 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002782 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002783 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002784 for _, n1 := range n.List.Slice() {
2785 if n1.Op == OLITERAL {
2786 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002787 }
2788 }
2789
2790 // Don't allocate the buffer if the result won't fit.
2791 if sz < tmpstringbufsize {
2792 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002793 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002794
2795 buf = Nod(OADDR, temp(t), nil)
2796 }
2797 }
2798
2799 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002800 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002801 for _, n2 := range n.List.Slice() {
2802 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002803 }
2804
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002805 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002806 if c <= 5 {
2807 // small numbers of strings use direct runtime helpers.
2808 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002809 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002810 } else {
2811 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002812 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002813
Josh Bleecher Snydereb98e512016-03-28 22:57:57 -07002814 t := typSlice(Types[TSTRING])
Russ Cox382b44e2015-02-23 16:07:24 -05002815 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002816 if prealloc[n] != nil {
2817 prealloc[slice] = prealloc[n]
2818 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002819 slice.List.Set(args[1:]) // skip buf arg
Keith Randall934c3592016-04-23 22:59:01 -07002820 args = []*Node{buf, slice}
Russ Cox8c195bd2015-02-13 14:40:36 -05002821 slice.Esc = EscNone
2822 }
2823
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002824 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002825 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002826 r.List.Set(args)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002827 r = typecheck(r, Erv)
2828 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002829 r.Type = n.Type
2830
2831 return r
2832}
2833
2834// expand append(l1, l2...) to
2835// init {
2836// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002837// n := len(s) + len(l2)
2838// // Compare as uint so growslice can panic on overflow.
2839// if uint(n) > uint(cap(s)) {
2840// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002841// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002842// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002843// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2844// }
2845// s
2846//
2847// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002848func appendslice(n *Node, init *Nodes) *Node {
2849 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002850
2851 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2852 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002853 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002854 ls := n.List.Slice()
2855 for i1, n1 := range ls {
2856 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002857 }
2858
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002859 l1 := n.List.First()
2860 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002861
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002862 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002863
2864 // var s []T
2865 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002866 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002867
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002868 // n := len(s) + len(l2)
2869 nn := temp(Types[TINT])
2870 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002871
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002872 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002873 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002874 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2875 nif.Left.Left.Type = Types[TUINT]
2876 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002877
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002878 // instantiate growslice(Type*, []any, int) []any
2879 fn := syslook("growslice")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002880 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002881
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002882 // s = growslice(T, s, n)
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002883 nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn)))
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002884 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002885
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002886 // s = s[:n]
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002887 nt := Nod(OSLICE, s, nil)
2888 nt.SetSliceBounds(nil, nn, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002889 nt.Etype = 1
2890 l = append(l, Nod(OAS, s, nt))
2891
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002892 if haspointers(l1.Type.Elem()) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002893 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002894 nptr1 := Nod(OSLICE, s, nil)
2895 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002896 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002897 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002898 fn := syslook("typedslicecopy")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002899 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002900 var ln Nodes
2901 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002902 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002903 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002904 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002905 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002906 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002907 nptr1 := Nod(OSLICE, s, nil)
2908 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002909 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002910 nptr2 := l2
2911 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002912 if l2.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002913 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002914 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002915 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002916 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002917 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002918 var ln Nodes
2919 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002920 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002921 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002922 } else {
2923 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002924 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002925 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002926
Russ Cox8c195bd2015-02-13 14:40:36 -05002927 nptr1 = Nod(OADDR, nptr1, nil)
2928
Russ Cox382b44e2015-02-23 16:07:24 -05002929 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002930
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002931 fn := syslook("memmove")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002932 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002933
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002934 var ln Nodes
2935 ln.Set(l)
2936 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002937
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002938 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002939 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2940 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002941 }
2942
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002943 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002944 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002945 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002946 return s
2947}
2948
Russ Cox85520472015-05-06 12:34:30 -04002949// Rewrite append(src, x, y, z) so that any side effects in
2950// x, y, z (including runtime panics) are evaluated in
2951// initialization statements before the append.
2952// For normal code generation, stop there and leave the
2953// rest to cgen_append.
2954//
2955// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002956//
2957// init {
2958// s := src
2959// const argc = len(args) - 1
2960// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002961// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002962// }
2963// n := len(s)
2964// s = s[:n+argc]
2965// s[n] = a
2966// s[n+1] = b
2967// ...
2968// }
2969// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002970func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002971 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002972 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002973 n.List.SetIndex(0, walkexpr(n.List.Index(0), init))
Russ Cox85520472015-05-06 12:34:30 -04002974 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002975 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002976
2977 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2978 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002979 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002980 // Using cheapexpr also makes sure that the evaluation
2981 // of all arguments (and especially any panics) happen
2982 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002983 ls := n.List.Slice()[1:]
2984 for i, n := range ls {
2985 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002986 }
2987
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002988 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002989
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002990 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002991 if argc < 1 {
2992 return nsrc
2993 }
2994
Russ Cox85520472015-05-06 12:34:30 -04002995 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002996 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002997 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002998 return n
2999 }
3000
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003001 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003002
Russ Cox382b44e2015-02-23 16:07:24 -05003003 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003004 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05003005
Russ Cox382b44e2015-02-23 16:07:24 -05003006 na := Nodintconst(int64(argc)) // const argc
3007 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04003008 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05003009
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003010 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003011 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05003012
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003013 nx.Nbody.Set1(Nod(OAS, ns,
Keith Randallbfe0cbd2016-04-19 15:38:59 -07003014 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003015 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05003016
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003017 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05003018
Russ Cox382b44e2015-02-23 16:07:24 -05003019 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003020 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05003021
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07003022 nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
3023 nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003024 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003025 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05003026
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003027 ls = n.List.Slice()[1:]
3028 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05003029 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003030 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003031 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
3032 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003033 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003034 }
3035 }
3036
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003037 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003038 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003039 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003040 return ns
3041}
3042
3043// Lower copy(a, b) to a memmove call or a runtime call.
3044//
3045// init {
3046// n := len(a)
3047// if n > len(b) { n = len(b) }
3048// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3049// }
3050// n;
3051//
3052// Also works if b is a string.
3053//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003054func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003055 if haspointers(n.Left.Type.Elem()) {
Russ Cox382b44e2015-02-23 16:07:24 -05003056 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003057 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05003058 }
3059
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003060 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003061 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003062 if n.Right.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003063 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003064 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003065 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003066 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003067 fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003068 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003069 }
3070
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003071 n.Left = walkexpr(n.Left, init)
3072 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003073 nl := temp(n.Left.Type)
3074 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003075 var l []*Node
3076 l = append(l, Nod(OAS, nl, n.Left))
3077 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003078
Russ Cox382b44e2015-02-23 16:07:24 -05003079 nfrm := Nod(OSPTR, nr, nil)
3080 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003081
Russ Cox382b44e2015-02-23 16:07:24 -05003082 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003083
3084 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003085 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003086
3087 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003088 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003089
Russ Cox66be1482015-05-26 21:30:20 -04003090 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003091 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003092 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003093
3094 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003095 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003096
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003097 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
Russ Cox382b44e2015-02-23 16:07:24 -05003098 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003099 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003100 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003101 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003102
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003103 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003104 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003105 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003106 return nlen
3107}
3108
Russ Cox8c195bd2015-02-13 14:40:36 -05003109func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003110 // Should only arrive here with large memory or
3111 // a struct/array containing a non-memory field/element.
3112 // Small memory is handled inline, and single non-memory
3113 // is handled during type check (OCMPSTR etc).
Matthew Dempsky077902d2016-04-01 11:22:03 -07003114 switch a, _ := algtype1(t); a {
3115 case AMEM:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003116 n := syslook("memequal")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003117 n = substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003118 *needsize = 1
3119 return n
Matthew Dempsky077902d2016-04-01 11:22:03 -07003120 case ASPECIAL:
3121 sym := typesymprefix(".eq", t)
3122 n := newname(sym)
3123 n.Class = PFUNC
3124 ntype := Nod(OTFUNC, nil, nil)
3125 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3126 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3127 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3128 ntype = typecheck(ntype, Etype)
3129 n.Type = ntype.Type
3130 *needsize = 0
3131 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003132 }
Matthew Dempsky077902d2016-04-01 11:22:03 -07003133 Fatalf("eqfor %v", t)
3134 return nil
Russ Cox8c195bd2015-02-13 14:40:36 -05003135}
3136
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003137// The result of walkcompare MUST be assigned back to n, e.g.
3138// n.Left = walkcompare(n.Left, init)
3139func walkcompare(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003140 // Given interface value l and concrete value r, rewrite
3141 // l == r
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003142 // into types-equal && data-equal.
3143 // This is efficient, avoids allocations, and avoids runtime calls.
3144 var l, r *Node
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003145 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003146 l = n.Left
3147 r = n.Right
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003148 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003149 l = n.Right
3150 r = n.Left
3151 }
3152
3153 if l != nil {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003154 // Handle both == and !=.
3155 eq := n.Op
3156 var andor Op
3157 if eq == OEQ {
3158 andor = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003159 } else {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003160 andor = OOROR
Russ Cox8c195bd2015-02-13 14:40:36 -05003161 }
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003162 // Check for types equal.
3163 // For empty interface, this is:
3164 // l.tab == type(r)
3165 // For non-empty interface, this is:
3166 // l.tab != nil && l.tab._type == type(r)
3167 var eqtype *Node
3168 tab := Nod(OITAB, l, nil)
3169 rtyp := typename(r.Type)
3170 if l.Type.IsEmptyInterface() {
3171 tab.Type = Ptrto(Types[TUINT8])
3172 tab.Typecheck = 1
3173 eqtype = Nod(eq, tab, rtyp)
3174 } else {
3175 nonnil := Nod(Brcom(eq), nodnil(), tab)
3176 match := Nod(eq, itabType(tab), rtyp)
3177 eqtype = Nod(andor, nonnil, match)
3178 }
3179 // Check for data equal.
3180 eqdata := Nod(eq, ifaceData(l, r.Type), r)
3181 // Put it all together.
3182 expr := Nod(andor, eqtype, eqdata)
3183 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003184 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003185 }
3186
3187 // Must be comparison of array or struct.
3188 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003189 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003190
3191 switch t.Etype {
3192 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003193 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003194
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07003195 case TARRAY, TSTRUCT:
Russ Cox8c195bd2015-02-13 14:40:36 -05003196 break
3197 }
3198
Russ Cox44928112015-03-02 20:34:22 -05003199 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003200 for cmpl != nil && cmpl.Op == OCONVNOP {
3201 cmpl = cmpl.Left
3202 }
Russ Cox44928112015-03-02 20:34:22 -05003203 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003204 for cmpr != nil && cmpr.Op == OCONVNOP {
3205 cmpr = cmpr.Left
3206 }
3207
Russ Coxdc7b54b2015-02-17 22:13:49 -05003208 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003209 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003210 }
3211
3212 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003213 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003214 a.Right.Etype = 1 // addr does not escape
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003215 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003216 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003217
3218 r = temp(Ptrto(t))
3219 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3220 a.Right.Etype = 1 // addr does not escape
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003221 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003222 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003223
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003224 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003225 if n.Op == ONE {
3226 andor = OOROR
3227 }
3228
Russ Cox44928112015-03-02 20:34:22 -05003229 var expr *Node
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003230 if t.Etype == TARRAY && t.NumElem() <= 4 && issimple[t.Elem().Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003231 // Four or fewer elements of a basic type.
3232 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003233 var li *Node
3234 var ri *Node
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003235 for i := 0; int64(i) < t.NumElem(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003236 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3237 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003238 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003239 if expr == nil {
3240 expr = a
3241 } else {
3242 expr = Nod(andor, expr, a)
3243 }
3244 }
3245
3246 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003247 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003248 }
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003249 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003250 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003251 }
3252
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003253 if t.Etype == TARRAY {
3254 // Zero- or single-element array, of any type.
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003255 switch t.NumElem() {
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003256 case 0:
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003257 n = finishcompare(n, Nodbool(n.Op == OEQ), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003258 return n
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003259 case 1:
3260 l0 := Nod(OINDEX, l, Nodintconst(0))
3261 r0 := Nod(OINDEX, r, Nodintconst(0))
3262 a := Nod(n.Op, l0, r0)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003263 n = finishcompare(n, a, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003264 return n
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003265 }
3266 }
3267
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003268 if t.IsStruct() && t.NumFields() <= 4 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003269 // Struct of four or fewer fields.
3270 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003271 var li *Node
3272 var ri *Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07003273 for _, t1 := range t.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003274 if isblanksym(t1.Sym) {
3275 continue
3276 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003277 li = NodSym(OXDOT, l, t1.Sym)
3278 ri = NodSym(OXDOT, r, t1.Sym)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003279 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003280 if expr == nil {
3281 expr = a
3282 } else {
3283 expr = Nod(andor, expr, a)
3284 }
3285 }
3286
3287 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003288 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003289 }
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003290 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003291 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003292 }
3293
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003294 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003295 var needsize int
3296 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003297
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003298 call.List.Append(l)
3299 call.List.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003300 if needsize != 0 {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003301 call.List.Append(Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003302 }
3303 r = call
3304 if n.Op != OEQ {
3305 r = Nod(ONOT, r, nil)
3306 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003307
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003308 n = finishcompare(n, r, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003309 return n
Russ Cox44928112015-03-02 20:34:22 -05003310}
3311
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003312// The result of finishcompare MUST be assigned back to n, e.g.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003313// n.Left = finishcompare(n.Left, x, r, init)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003314func finishcompare(n, r *Node, init *Nodes) *Node {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003315 // Use nn here to avoid passing r to typecheck.
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003316 nn := r
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003317 nn = typecheck(nn, Erv)
3318 nn = walkexpr(nn, init)
3319 r = nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003320 if r.Type != n.Type {
3321 r = Nod(OCONVNOP, r, nil)
3322 r.Type = n.Type
3323 r.Typecheck = 1
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003324 nn = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003325 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003326 return nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003327}
3328
Russ Coxdc7b54b2015-02-17 22:13:49 -05003329func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003330 var ar *Node
3331 var br *Node
3332 for a != nil && b != nil && a.Op == b.Op {
3333 switch a.Op {
3334 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003335 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003336
3337 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003338 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003339
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003340 case ODOT, ODOTPTR:
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003341 if a.Sym != b.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003342 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003343 }
3344
3345 case OINDEX:
3346 ar = a.Right
3347 br = b.Right
Matthew Dempskyd3253872016-03-20 13:55:42 -07003348 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003349 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003350 }
3351 }
3352
3353 a = a.Left
3354 b = b.Left
3355 }
3356
Russ Coxdc7b54b2015-02-17 22:13:49 -05003357 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003358}
3359
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003360// The result of walkrotate MUST be assigned back to n, e.g.
3361// n.Left = walkrotate(n.Left)
3362func walkrotate(n *Node) *Node {
Cherry Zhangd99cee72016-08-10 13:24:03 -04003363 //TODO: enable LROT on ARM64 once the old backend is gone
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07003364 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003365 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003366 }
3367
Russ Cox8c195bd2015-02-13 14:40:36 -05003368 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003369 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003370
Russ Cox382b44e2015-02-23 16:07:24 -05003371 r := n.Right
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003372 if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || n.Type.IsSigned() || l.Op == r.Op {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003373 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003374 }
3375
3376 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003377 if !samecheap(l.Left, r.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003378 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003379 }
3380
3381 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003382 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003383
Michael Munday613ba6c2016-04-12 12:26:17 -04003384 if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
3385 // only supports 32-bit and 64-bit rotates
3386 return n
3387 }
3388
Russ Coxdc7b54b2015-02-17 22:13:49 -05003389 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003390 sl := int(l.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003391 if sl >= 0 {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003392 sr := int(r.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003393 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003394 // Rewrite left shift half to left rotate.
3395 if l.Op == OLSH {
3396 n = l
3397 } else {
3398 n = r
3399 }
3400 n.Op = OLROT
3401
3402 // Remove rotate 0 and rotate w.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003403 s := int(n.Right.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003404
3405 if s == 0 || s == w {
3406 n = n.Left
3407 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003408 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003409 }
3410 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003411 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003412 }
3413
3414 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003415 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003416}
3417
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003418// walkmul rewrites integer multiplication by powers of two as shifts.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003419// The result of walkmul MUST be assigned back to n, e.g.
3420// n.Left = walkmul(n.Left, init)
3421func walkmul(n *Node, init *Nodes) *Node {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003422 if !n.Type.IsInteger() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003423 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003424 }
3425
Russ Cox382b44e2015-02-23 16:07:24 -05003426 var nr *Node
3427 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003428 if n.Right.Op == OLITERAL {
3429 nl = n.Left
3430 nr = n.Right
3431 } else if n.Left.Op == OLITERAL {
3432 nl = n.Right
3433 nr = n.Left
3434 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003435 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003436 }
3437
Russ Cox382b44e2015-02-23 16:07:24 -05003438 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003439
3440 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003441 var pow int
3442 var w int
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003443 if nr.Int64() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003444 cheapexpr(nl, init)
3445 Nodconst(n, n.Type, 0)
3446 goto ret
3447 }
3448
3449 // nr is a constant.
3450 pow = powtwo(nr)
3451
3452 if pow < 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003453 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003454 }
3455 if pow >= 1000 {
3456 // negative power of 2, like -16
3457 neg = 1
3458
3459 pow -= 1000
3460 }
3461
3462 w = int(nl.Type.Width * 8)
3463 if pow+1 >= w { // too big, shouldn't happen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003464 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003465 }
3466
3467 nl = cheapexpr(nl, init)
3468
3469 if pow == 0 {
3470 // x*1 is x
3471 n = nl
3472
3473 goto ret
3474 }
3475
3476 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3477
3478ret:
3479 if neg != 0 {
3480 n = Nod(OMINUS, n, nil)
3481 }
3482
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003483 n = typecheck(n, Erv)
3484 n = walkexpr(n, init)
3485 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003486}
3487
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003488// walkdiv rewrites division by a constant as less expensive
3489// operations.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003490// The result of walkdiv MUST be assigned back to n, e.g.
3491// n.Left = walkdiv(n.Left, init)
3492func walkdiv(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003493 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003494
3495 // TODO(minux)
Zhongwei Yao74a9bad2016-04-25 11:08:38 +08003496 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003497 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003498 }
3499
Russ Cox8c195bd2015-02-13 14:40:36 -05003500 if n.Right.Op != OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003501 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003502 }
3503
3504 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003505 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003506
Russ Cox382b44e2015-02-23 16:07:24 -05003507 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003508
3509 // special cases of mod/div
3510 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003511 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003512
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003513 s := 0 // 1 if nr is negative.
3514 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003515 if pow >= 1000 {
3516 // negative power of 2
3517 s = 1
3518
3519 pow -= 1000
3520 }
3521
3522 if pow+1 >= w {
3523 // divisor too large.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003524 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003525 }
3526
3527 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003528 // try to do division by multiply by (2^w)/d
3529 // see hacker's delight chapter 10
3530 // TODO: support 64-bit magic multiply here.
3531 var m Magic
3532 m.W = w
3533
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003534 if nl.Type.IsSigned() {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003535 m.Sd = nr.Int64()
Russ Cox79f727a2015-03-02 12:35:15 -05003536 Smagic(&m)
3537 } else {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003538 m.Ud = uint64(nr.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003539 Umagic(&m)
3540 }
3541
3542 if m.Bad != 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003543 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003544 }
3545
3546 // We have a quick division method so use it
3547 // for modulo too.
3548 if n.Op == OMOD {
3549 // rewrite as A%B = A - (A/B*B).
3550 n1 := Nod(ODIV, nl, nr)
3551
3552 n2 := Nod(OMUL, n1, nr)
3553 n = Nod(OSUB, nl, n2)
3554 goto ret
3555 }
3556
3557 switch Simtype[nl.Type.Etype] {
3558 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003559 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003560
3561 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003562 case TUINT8, TUINT16, TUINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003563 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003564
Dave Cheneya4be24c2016-03-23 13:27:49 +11003565 Nodconst(&nc, nl.Type, int64(m.Um))
3566 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003567 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003568 if m.Ua != 0 {
3569 // Select a Go type with (at least) twice the width.
3570 var twide *Type
3571 switch Simtype[nl.Type.Etype] {
3572 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003573 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003574
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003575 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003576 twide = Types[TUINT32]
3577
3578 case TUINT32:
3579 twide = Types[TUINT64]
3580
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003581 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003582 twide = Types[TINT32]
3583
3584 case TINT32:
3585 twide = Types[TINT64]
3586 }
3587
3588 // add numerator (might overflow).
3589 // n2 = (n1 + nl)
3590 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3591
3592 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003593 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003594
Dave Cheneya4be24c2016-03-23 13:27:49 +11003595 Nodconst(&nc, Types[TUINT], int64(m.S))
3596 n = conv(Nod(ORSH, n2, &nc), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003597 } else {
3598 // n = n1 >> m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003599 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003600
Dave Cheneya4be24c2016-03-23 13:27:49 +11003601 Nodconst(&nc, Types[TUINT], int64(m.S))
3602 n = Nod(ORSH, n1, &nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003603 }
3604
3605 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003606 case TINT8, TINT16, TINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003607 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003608
Dave Cheneya4be24c2016-03-23 13:27:49 +11003609 Nodconst(&nc, nl.Type, m.Sm)
3610 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003611 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003612 if m.Sm < 0 {
3613 // add the numerator.
3614 n1 = Nod(OADD, n1, nl)
3615 }
3616
3617 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003618 var ns Node
Russ Cox79f727a2015-03-02 12:35:15 -05003619
Dave Cheneya4be24c2016-03-23 13:27:49 +11003620 Nodconst(&ns, Types[TUINT], int64(m.S))
3621 n2 := conv(Nod(ORSH, n1, &ns), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003622
3623 // add 1 iff n1 is negative.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003624 var nneg Node
Russ Cox79f727a2015-03-02 12:35:15 -05003625
Dave Cheneya4be24c2016-03-23 13:27:49 +11003626 Nodconst(&nneg, Types[TUINT], int64(w)-1)
3627 n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative.
Russ Cox79f727a2015-03-02 12:35:15 -05003628 n = Nod(OSUB, n2, n3)
3629
3630 // apply sign.
3631 if m.Sd < 0 {
3632 n = Nod(OMINUS, n, nil)
3633 }
3634 }
3635
3636 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003637 }
3638
3639 switch pow {
3640 case 0:
3641 if n.Op == OMOD {
3642 // nl % 1 is zero.
3643 Nodconst(n, n.Type, 0)
3644 } else if s != 0 {
3645 // divide by -1
3646 n.Op = OMINUS
3647
3648 n.Right = nil
3649 } else {
3650 // divide by 1
3651 n = nl
3652 }
3653
3654 default:
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003655 if n.Type.IsSigned() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003656 if n.Op == OMOD {
3657 // signed modulo 2^pow is like ANDing
3658 // with the last pow bits, but if nl < 0,
3659 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003660 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003661
Dave Cheneya4be24c2016-03-23 13:27:49 +11003662 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3663 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003664 if pow == 1 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003665 n1 = typecheck(n1, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003666 n1 = cheapexpr(n1, init)
3667
3668 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003669 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003670
Dave Cheneya4be24c2016-03-23 13:27:49 +11003671 var nc Node
3672 Nodconst(&nc, nl.Type, 1)
3673 n3 := Nod(OAND, n2, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003674 n = Nod(OADD, n3, n1)
3675 } else {
3676 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003677 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003678
Dave Cheneya4be24c2016-03-23 13:27:49 +11003679 Nodconst(&nc, nl.Type, (1<<uint(pow))-1)
3680 n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003681 n2 = typecheck(n2, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003682 n2 = cheapexpr(n2, init)
3683
Russ Cox382b44e2015-02-23 16:07:24 -05003684 n3 := Nod(OADD, nl, n2)
Dave Cheneya4be24c2016-03-23 13:27:49 +11003685 n4 := Nod(OAND, n3, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003686 n = Nod(OSUB, n4, n2)
3687 }
3688
3689 break
3690 } else {
3691 // arithmetic right shift does not give the correct rounding.
3692 // if nl >= 0, nl >> n == nl / nr
3693 // if nl < 0, we want to add 2^n-1 first.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003694 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003695
Dave Cheneya4be24c2016-03-23 13:27:49 +11003696 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3697 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003698 if pow == 1 {
3699 // nl+1 is nl-(-1)
3700 n.Left = Nod(OSUB, nl, n1)
3701 } else {
3702 // Do a logical right right on -1 to keep pow bits.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003703 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003704
Dave Cheneya4be24c2016-03-23 13:27:49 +11003705 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
3706 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003707 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3708 }
3709
3710 // n = (nl + 2^pow-1) >> pow
3711 n.Op = ORSH
3712
Dave Cheneya4be24c2016-03-23 13:27:49 +11003713 var n2 Node
3714 Nodconst(&n2, Types[Simtype[TUINT]], int64(pow))
3715 n.Right = &n2
Russ Cox8c195bd2015-02-13 14:40:36 -05003716 n.Typecheck = 0
3717 }
3718
3719 if s != 0 {
3720 n = Nod(OMINUS, n, nil)
3721 }
3722 break
3723 }
3724
Dave Cheneya4be24c2016-03-23 13:27:49 +11003725 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003726 if n.Op == OMOD {
3727 // n = nl & (nr-1)
3728 n.Op = OAND
3729
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003730 Nodconst(&nc, nl.Type, nr.Int64()-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003731 } else {
3732 // n = nl >> pow
3733 n.Op = ORSH
3734
Dave Cheneya4be24c2016-03-23 13:27:49 +11003735 Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
Russ Cox8c195bd2015-02-13 14:40:36 -05003736 }
3737
3738 n.Typecheck = 0
Dave Cheneya4be24c2016-03-23 13:27:49 +11003739 n.Right = &nc
Russ Cox8c195bd2015-02-13 14:40:36 -05003740 }
3741
3742 goto ret
3743
Russ Cox8c195bd2015-02-13 14:40:36 -05003744ret:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003745 n = typecheck(n, Erv)
3746 n = walkexpr(n, init)
3747 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003748}
3749
3750// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003751func bounded(n *Node, max int64) bool {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003752 if n.Type == nil || !n.Type.IsInteger() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003753 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003754 }
3755
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003756 sign := n.Type.IsSigned()
Russ Cox382b44e2015-02-23 16:07:24 -05003757 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003758
Russ Coxdc7b54b2015-02-17 22:13:49 -05003759 if Smallintconst(n) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003760 v := n.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003761 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003762 }
3763
3764 switch n.Op {
3765 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003766 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003767 if Smallintconst(n.Left) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003768 v = n.Left.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003769 } else if Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003770 v = n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003771 }
3772
3773 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003774 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003775 }
3776
3777 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003778 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003779 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003780 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003781 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003782 }
3783 }
3784
3785 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003786 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003787 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003788 for bits > 0 && v >= 2 {
3789 bits--
3790 v >>= 1
3791 }
3792 }
3793
3794 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003795 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003796 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003797 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003798 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003799 }
3800 bits -= int32(v)
3801 }
3802 }
3803
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003804 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003805 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003806 }
3807
Russ Coxdc7b54b2015-02-17 22:13:49 -05003808 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003809}
3810
David Crawshawcc158402016-03-10 16:15:26 -05003811// usemethod check interface method calls for uses of reflect.Type.Method.
3812func usemethod(n *Node) {
3813 t := n.Left.Type
3814
3815 // Looking for either of:
3816 // Method(int) reflect.Method
3817 // MethodByName(string) (reflect.Method, bool)
3818 //
3819 // TODO(crawshaw): improve precision of match by working out
3820 // how to check the method name.
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003821 if n := t.Params().NumFields(); n != 1 {
David Crawshawcc158402016-03-10 16:15:26 -05003822 return
3823 }
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003824 if n := t.Results().NumFields(); n != 1 && n != 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003825 return
3826 }
3827 p0 := t.Params().Field(0)
3828 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003829 var res1 *Field
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003830 if t.Results().NumFields() == 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003831 res1 = t.Results().Field(1)
3832 }
3833
3834 if res1 == nil {
3835 if p0.Type.Etype != TINT {
3836 return
3837 }
3838 } else {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003839 if !p0.Type.IsString() {
David Crawshawcc158402016-03-10 16:15:26 -05003840 return
3841 }
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003842 if !res1.Type.IsBoolean() {
David Crawshawcc158402016-03-10 16:15:26 -05003843 return
3844 }
3845 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003846 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003847 return
3848 }
3849
3850 Curfn.Func.ReflectMethod = true
3851}
3852
Russ Cox8c195bd2015-02-13 14:40:36 -05003853func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003854 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003855 return
3856 }
3857
3858 switch n.Op {
3859 default:
Dave Cheneyd3c79d32016-04-27 15:10:10 +10003860 Fatalf("usefield %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05003861
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003862 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003863 break
3864 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003865 if n.Sym == nil {
Keith Randall71d13a82016-03-02 20:54:41 -08003866 // No field name. This DOTPTR was built by the compiler for access
3867 // to runtime data structures. Ignore.
3868 return
3869 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003870
Russ Cox496ad0a2015-05-26 21:49:31 -04003871 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003872 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003873 t = t.Elem()
Russ Cox496ad0a2015-05-26 21:49:31 -04003874 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003875 field := dotField[typeSym{t.Orig, n.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003876 if field == nil {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003877 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003878 }
Matthew Dempskye48a2952016-04-25 13:24:48 -07003879 if !strings.Contains(field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003880 return
3881 }
3882
Matthew Dempskya2a48062016-03-10 16:15:44 -08003883 outer := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003884 if outer.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003885 outer = outer.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05003886 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003887 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003888 Yyerror("tracked field must be in named struct type")
3889 }
3890 if !exportname(field.Sym.Name) {
3891 Yyerror("tracked field must be exported (upper case)")
3892 }
3893
Matthew Dempskya2a48062016-03-10 16:15:44 -08003894 sym := tracksym(outer, field)
3895 if Curfn.Func.FieldTrack == nil {
3896 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
3897 }
3898 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05003899}
3900
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003901func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003902 for _, n := range l.Slice() {
3903 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003904 return false
3905 }
3906 }
3907 return true
3908}
3909
Russ Coxdc7b54b2015-02-17 22:13:49 -05003910func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003911 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003912 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003913 }
3914
3915 switch n.Op {
3916 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003917 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003918
3919 // Discardable as long as the subpieces are.
3920 case ONAME,
3921 ONONAME,
3922 OTYPE,
3923 OPACK,
3924 OLITERAL,
3925 OADD,
3926 OSUB,
3927 OOR,
3928 OXOR,
3929 OADDSTR,
3930 OADDR,
3931 OANDAND,
3932 OARRAYBYTESTR,
3933 OARRAYRUNESTR,
3934 OSTRARRAYBYTE,
3935 OSTRARRAYRUNE,
3936 OCAP,
3937 OCMPIFACE,
3938 OCMPSTR,
3939 OCOMPLIT,
3940 OMAPLIT,
3941 OSTRUCTLIT,
3942 OARRAYLIT,
3943 OPTRLIT,
3944 OCONV,
3945 OCONVIFACE,
3946 OCONVNOP,
3947 ODOT,
3948 OEQ,
3949 ONE,
3950 OLT,
3951 OLE,
3952 OGT,
3953 OGE,
3954 OKEY,
3955 OLEN,
3956 OMUL,
3957 OLSH,
3958 ORSH,
3959 OAND,
3960 OANDNOT,
3961 ONEW,
3962 ONOT,
3963 OCOM,
3964 OPLUS,
3965 OMINUS,
3966 OOROR,
3967 OPAREN,
3968 ORUNESTR,
3969 OREAL,
3970 OIMAG,
3971 OCOMPLEX:
3972 break
3973
3974 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003975 case ODIV, OMOD:
Matthew Dempskyd3253872016-03-20 13:55:42 -07003976 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003977 break
3978 }
Matthew Dempskyd3253872016-03-20 13:55:42 -07003979 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003980 break
3981 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003982 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003983
3984 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003985 case OMAKECHAN, OMAKEMAP:
Matthew Dempskyd3253872016-03-20 13:55:42 -07003986 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003987 break
3988 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003989 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003990
3991 // Difficult to tell what sizes are okay.
3992 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003993 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003994 }
3995
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003996 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 -05003997 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003998 }
3999
Russ Coxdc7b54b2015-02-17 22:13:49 -05004000 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004001}
4002
4003// rewrite
4004// print(x, y, z)
4005// into
4006// func(a1, a2, a3) {
4007// print(a1, a2, a3)
4008// }(x, y, z)
4009// and same for println.
4010
4011var walkprintfunc_prgen int
4012
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004013// The result of walkprintfunc MUST be assigned back to n, e.g.
4014// n.Left = walkprintfunc(n.Left, init)
4015func walkprintfunc(n *Node, init *Nodes) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004016 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08004017 walkstmtlist(n.Ninit.Slice())
4018 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05004019 }
4020
Russ Cox382b44e2015-02-23 16:07:24 -05004021 t := Nod(OTFUNC, nil, nil)
4022 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004023 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05004024 var a *Node
4025 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004026 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05004027 buf = fmt.Sprintf("a%d", num)
4028 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004029 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
4030 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004031 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05004032 }
4033
Russ Cox382b44e2015-02-23 16:07:24 -05004034 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004035 walkprintfunc_prgen++
4036 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04004037 fn.Func.Nname = newname(Lookup(buf))
4038 fn.Func.Nname.Name.Defn = fn
4039 fn.Func.Nname.Name.Param.Ntype = t
4040 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05004041
Russ Cox382b44e2015-02-23 16:07:24 -05004042 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004043 Curfn = nil
4044 funchdr(fn)
4045
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02004046 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004047 a.List.Set(printargs)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004048 a = typecheck(a, Etop)
4049 a = walkstmt(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004050
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08004051 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004052
4053 funcbody(fn)
4054
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004055 fn = typecheck(fn, Etop)
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07004056 typecheckslice(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08004057 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05004058 Curfn = oldfn
4059
4060 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004061 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004062 a.List.Set(n.List.Slice())
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004063 a = typecheck(a, Etop)
4064 a = walkexpr(a, init)
4065 return a
Russ Cox8c195bd2015-02-13 14:40:36 -05004066}