blob: 91895dd8afba41fcccc4380bc28d34bc208d2e43 [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 }
Josh Bleecher Snyder67bcee82016-05-16 14:23:12 -0700148 if n.IsStatic { // 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())
Josh Bleecher Snyder62861882016-05-26 18:08:24 -0700634 n = walkinrange(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500635
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700636 case OPRINT, OPRINTN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800637 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500638 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500639
640 case OPANIC:
641 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500642
643 case ORECOVER:
644 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500645
646 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700647 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500648
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700649 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700650 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500651
652 case ONAME:
Russ Cox20803b82016-05-25 10:29:50 -0400653 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500654
655 case OCALLINTER:
David Crawshawcc158402016-03-10 16:15:26 -0500656 usemethod(n)
Russ Cox382b44e2015-02-23 16:07:24 -0500657 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800658 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200659 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500660 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700661 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800662 walkexprlist(n.List.Slice(), init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800663 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800664 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500665
666 case OCALLFUNC:
667 if n.Left.Op == OCLOSURE {
668 // Transform direct call of a closure to call of a normal function.
669 // transformclosure already did all preparation work.
670
David Chase731dcda2015-07-23 14:17:07 -0400671 // Prepend captured variables to argument list.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800672 n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500673
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800674 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500675
676 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400677 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500678
679 // Update type of OCALLFUNC node.
680 // Output arguments had not changed, but their offsets could.
Matthew Dempskyc8377612016-03-17 01:47:16 -0700681 if n.Left.Type.Results().NumFields() == 1 {
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -0700682 n.Type = n.Left.Type.Results().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500683 } else {
Matthew Dempskydb506fe2016-03-08 16:31:28 -0800684 n.Type = n.Left.Type.Results()
Russ Cox8c195bd2015-02-13 14:40:36 -0500685 }
686 }
687
Russ Cox382b44e2015-02-23 16:07:24 -0500688 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800689 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200690 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500691 }
692
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700693 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800694 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500695
Russ Cox92dba0d2015-04-01 16:02:34 -0400696 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
Michael Munday613ba6c2016-04-12 12:26:17 -0400697 if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
Russ Cox92dba0d2015-04-01 16:02:34 -0400698 n.Op = OSQRT
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800699 n.Left = n.List.First()
700 n.List.Set(nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200701 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400702 }
703 }
704
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800705 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800706 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500707
708 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500709 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800710 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200711 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500712 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700713 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800714 walkexprlist(n.List.Slice(), init)
Matthew Dempskyf91b8322016-03-09 20:54:59 -0800715 ll := ascompatte(n.Op, n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800716 lr := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800717 ll = append(ll, lr...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500718 n.Left.Left = nil
719 ullmancalc(n.Left)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800720 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500721
722 case OAS:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800723 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500724
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700725 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500726 n.Left = safeexpr(n.Left, init)
727
Russ Coxdc7b54b2015-02-17 22:13:49 -0500728 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200729 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500730 }
731
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700732 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200733 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500734 }
735
736 switch n.Right.Op {
737 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700738 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500739
Russ Cox8c195bd2015-02-13 14:40:36 -0500740 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400741 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
742 // It needs to be removed in all three places.
743 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700744 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400745 // handled directly during cgen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700746 n.Right = walkexpr(n.Right, init)
Russ Cox4224d812015-03-20 00:06:10 -0400747 break
748 }
749
David Chaseffe7fbf2015-03-27 12:34:45 -0400750 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400751 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700752 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500753
Russ Cox382b44e2015-02-23 16:07:24 -0500754 n1 := Nod(OADDR, n.Left, nil)
755 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500756
Russ Cox4224d812015-03-20 00:06:10 -0400757 if Debug_typeassert > 0 {
758 Warn("type assertion not inlined")
759 }
760
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800761 fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700762 fn = substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500763
764 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700765 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200766 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500767
Russ Cox8c195bd2015-02-13 14:40:36 -0500768 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400769 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400770 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700771 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500772
Russ Cox382b44e2015-02-23 16:07:24 -0500773 n1 := Nod(OADDR, n.Left, nil)
774 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500775 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700776 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200777 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400778
779 case OAPPEND:
780 // x = append(...)
781 r := n.Right
782 if r.Isddd {
783 r = appendslice(r, init) // also works for append(slice, string).
784 } else {
785 r = walkappend(r, init, n)
786 }
787 n.Right = r
788 if r.Op == OAPPEND {
789 // Left in place for back end.
790 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200791 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400792 }
793 // Otherwise, lowered for race detector.
794 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 }
796
797 if n.Left != nil && n.Right != nil {
Josh Bleecher Snyder67bcee82016-05-16 14:23:12 -0700798 static := n.IsStatic
Josh Bleecher Snyder68884052016-03-26 08:17:43 -0700799 n = convas(n, init)
Josh Bleecher Snyder67bcee82016-05-16 14:23:12 -0700800 n.IsStatic = static
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800801 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500802 }
803
Russ Cox8c195bd2015-02-13 14:40:36 -0500804 case OAS2:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800805 init.AppendNodes(&n.Ninit)
806 walkexprlistsafe(n.List.Slice(), init)
807 walkexprlistsafe(n.Rlist.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800808 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500809 ll = reorder3(ll)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800810 for i, n := range ll {
811 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500812 }
813 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500814
815 // a,b,... = fn()
816 case OAS2FUNC:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800817 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500818
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800819 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800820 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700821 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500822
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800823 ll := ascompatet(n.Op, n.List, r.Type, 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800824 for i, n := range ll {
825 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500826 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800827 n = liststmt(append([]*Node{r}, ll...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500828
829 // x, y = <-c
830 // orderstmt made sure x is addressable.
831 case OAS2RECV:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800832 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500833
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800834 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800835 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700836 r.Left = walkexpr(r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500837 var n1 *Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800838 if isblank(n.List.First()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500839 n1 = nodnil()
840 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800841 n1 = Nod(OADDR, n.List.First(), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500842 }
843 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500844 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800845 r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
846 n = Nod(OAS, n.List.Second(), r)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700847 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500848
849 // a,b = m[i];
850 case OAS2MAPR:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800851 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500852
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800853 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800854 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700855 r.Left = walkexpr(r.Left, init)
856 r.Right = walkexpr(r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500857 t := r.Left.Type
858 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700859 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800860 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800861 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500862 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800863 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500864 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800865 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500866 p = "mapaccess2_faststr"
867 }
868 }
869
Russ Cox382b44e2015-02-23 16:07:24 -0500870 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500871 if p != "" {
872 // fast versions take key by value
873 key = r.Right
874 } else {
875 // standard version takes key by reference
876 // orderexpr made sure key is addressable.
877 key = Nod(OADDR, r.Right, nil)
878
879 p = "mapaccess2"
880 }
881
882 // from:
883 // a,b = m[i]
884 // to:
885 // var,b = mapaccess2*(t, m, i)
886 // a = *var
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800887 a := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -0500888
Keith Randall60fd32a2016-04-19 08:31:04 -0700889 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
890 fn := mapfn(p, t)
891 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
892 } else {
893 fn := mapfn("mapaccess2_fat", t)
894 z := zeroaddr(w)
895 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
896 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500897
898 // mapaccess2* returns a typed bool, but due to spec changes,
899 // the boolean result of i.(T) is now untyped so we make it the
900 // same type as the variable on the lhs.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800901 if !isblank(n.List.Second()) {
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800902 r.Type.Field(1).Type = n.List.Second().Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500903 }
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800904 n.Rlist.Set1(r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500905 n.Op = OAS2FUNC
906
907 // don't generate a = *var if a is _
908 if !isblank(a) {
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700909 var_ := temp(Ptrto(t.Val()))
Russ Cox8c195bd2015-02-13 14:40:36 -0500910 var_.Typecheck = 1
Keith Randall3c1a4c12016-04-19 21:06:53 -0700911 var_.NonNil = true // mapaccess always returns a non-nil pointer
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800912 n.List.SetIndex(0, var_)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700913 n = walkexpr(n, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800914 init.Append(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500915 n = Nod(OAS, a, Nod(OIND, var_, nil))
916 }
917
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700918 n = typecheck(n, Etop)
919 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500920
Russ Cox8c195bd2015-02-13 14:40:36 -0500921 case ODELETE:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800922 init.AppendNodes(&n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800923 map_ := n.List.First()
924 key := n.List.Second()
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700925 map_ = walkexpr(map_, init)
926 key = walkexpr(key, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500927
928 // orderstmt made sure key is addressable.
929 key = Nod(OADDR, key, nil)
930
Russ Cox382b44e2015-02-23 16:07:24 -0500931 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500932 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500933
Russ Cox8c195bd2015-02-13 14:40:36 -0500934 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800935 e := n.Rlist.First() // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400936 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
937 // It needs to be removed in all three places.
938 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700939 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400940 // handled directly during gen.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800941 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700942 e.Left = walkexpr(e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200943 break
Russ Cox4224d812015-03-20 00:06:10 -0400944 }
945
946 // res, ok = i.(T)
947 // orderstmt made sure a is addressable.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800948 init.AppendNodes(&n.Ninit)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700949
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800950 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700951 e.Left = walkexpr(e.Left, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700952 t := e.Type // T
953 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500954
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700955 oktype := Types[TBOOL]
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800956 ok := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500957 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700958 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500959 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700960
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000961 fromKind := from.Type.iet()
962 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700963
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700964 res := n.List.First()
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700965 scalar := !haspointers(res.Type)
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700966
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700967 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
968 // This is faster and shorter and allows the corresponding assertX2X2
969 // routines to skip nil checks on their last argument.
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700970 // Also avoid runtime calls for converting interfaces to scalar concrete types.
971 if isblank(res) || (scalar && toKind == 'T') {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700972 var fast *Node
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -0700973 switch toKind {
974 case 'T':
975 tab := Nod(OITAB, from, nil)
976 if fromKind == 'E' {
977 typ := Nod(OCONVNOP, typename(t), nil)
978 typ.Type = Ptrto(Types[TUINTPTR])
979 fast = Nod(OEQ, tab, typ)
980 break
981 }
982 fast = Nod(OANDAND,
983 Nod(ONE, nodnil(), tab),
984 Nod(OEQ, itabType(tab), typename(t)),
985 )
986 case 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700987 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700988 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700989 }
990 if fast != nil {
Josh Bleecher Snyder615a52b2016-06-06 12:38:19 -0700991 if isblank(res) {
992 if Debug_typeassert > 0 {
993 Warn("type assertion (ok only) inlined")
994 }
995 n = Nod(OAS, ok, fast)
996 n = typecheck(n, Etop)
997 } else {
998 if Debug_typeassert > 0 {
999 Warn("type assertion (scalar result) inlined")
1000 }
1001 n = Nod(OIF, ok, nil)
1002 n.Likely = 1
1003 if isblank(ok) {
1004 n.Left = fast
1005 } else {
1006 n.Ninit.Set1(Nod(OAS, ok, fast))
1007 }
1008 n.Nbody.Set1(Nod(OAS, res, ifaceData(from, res.Type)))
1009 n.Rlist.Set1(Nod(OAS, res, nil))
1010 n = typecheck(n, Etop)
Russ Cox4224d812015-03-20 00:06:10 -04001011 }
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001012 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -07001013 }
1014 }
1015
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001016 var resptr *Node // &res
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -07001017 if isblank(res) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001018 resptr = nodnil()
1019 } else {
Josh Bleecher Snyder562d06f2016-06-06 08:29:52 -07001020 resptr = Nod(OADDR, res, nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001021 }
1022 resptr.Etype = 1 // addr does not escape
1023
Russ Cox4224d812015-03-20 00:06:10 -04001024 if Debug_typeassert > 0 {
1025 Warn("type assertion not inlined")
1026 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001027 fn := syslook(assertFuncName(from.Type, t, true))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001028 fn = substArgTypes(fn, from.Type, t)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -07001029 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
1030 n = Nod(OAS, ok, call)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001031 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05001032
Russ Cox4224d812015-03-20 00:06:10 -04001033 case ODOTTYPE, ODOTTYPE2:
1034 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001035 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -04001036 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001037 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001038
1039 case OCONVIFACE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001040 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001041
Michel Lespinasse7427f2c2016-03-18 16:20:20 -07001042 // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
1043 if isdirectiface(n.Left.Type) {
1044 var t *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001045 if n.Type.IsEmptyInterface() {
Michel Lespinasse7427f2c2016-03-18 16:20:20 -07001046 t = typename(n.Left.Type)
1047 } else {
1048 t = itabname(n.Left.Type, n.Type)
1049 }
1050 l := Nod(OEFACE, t, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001051 l.Type = n.Type
1052 l.Typecheck = n.Typecheck
1053 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001054 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001055 }
1056
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001057 var ll []*Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001058 if n.Type.IsEmptyInterface() {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001059 if !n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001060 ll = append(ll, typename(n.Left.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001061 }
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001062 } else {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001063 if n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001064 ll = append(ll, typename(n.Type))
1065 } else {
1066 ll = append(ll, itabname(n.Left.Type, n.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001067 }
1068 }
1069
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001070 if n.Left.Type.IsInterface() {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001071 ll = append(ll, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001072 } else {
1073 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001074 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001075 // the conversions it could see. comparison of an interface
1076 // with a non-interface, especially in a switch on interface value
1077 // with non-interface cases, is not visible to orderstmt, so we
1078 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001079 if islvalue(n.Left) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001080 ll = append(ll, Nod(OADDR, n.Left, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001081 } else {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001082 ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001083 }
David Chase22701332015-03-27 11:21:14 -04001084 dowidth(n.Left.Type)
1085 r := nodnil()
1086 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1087 // Allocate stack buffer for value stored in interface.
1088 r = temp(n.Left.Type)
1089 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001090 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001091 init.Append(r)
David Chase22701332015-03-27 11:21:14 -04001092 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001093 r = typecheck(r, Erv)
David Chase22701332015-03-27 11:21:14 -04001094 }
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001095 ll = append(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001096 }
1097
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001098 fn := syslook(convFuncName(n.Left.Type, n.Type))
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001099 if !n.Left.Type.IsInterface() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001100 fn = substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001101 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001102 fn = substArgTypes(fn, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001103 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001104 dowidth(fn.Type)
1105 n = Nod(OCALL, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001106 n.List.Set(ll)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001107 n = typecheck(n, Erv)
1108 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001109
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001110 case OCONV, OCONVNOP:
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07001111 if Thearch.LinkArch.Family == sys.ARM {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001112 if n.Left.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001113 if n.Type.Etype == TINT64 {
1114 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001115 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001116 }
1117
1118 if n.Type.Etype == TUINT64 {
1119 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001120 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001121 }
1122 }
1123
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001124 if n.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001125 if n.Left.Type.Etype == TINT64 {
Cherry Zhang59e11d72016-05-31 11:27:16 -04001126 n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001127 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001128 }
1129
1130 if n.Left.Type.Etype == TUINT64 {
Cherry Zhang59e11d72016-05-31 11:27:16 -04001131 n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001132 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001133 }
1134 }
1135 }
1136
Keith Randalldf2f8132016-07-21 10:37:59 -07001137 if Thearch.LinkArch.Family == sys.I386 {
1138 if n.Left.Type.IsFloat() {
1139 if n.Type.Etype == TINT64 {
1140 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1141 break
1142 }
1143
1144 if n.Type.Etype == TUINT64 {
1145 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1146 break
1147 }
Cherry Zhange6f1a882016-08-16 12:14:54 -04001148 if n.Type.Etype == TUINT32 || n.Type.Etype == TUINT || n.Type.Etype == TUINTPTR {
Keith Randalldf2f8132016-07-21 10:37:59 -07001149 n = mkcall("float64touint32", n.Type, init, conv(n.Left, Types[TFLOAT64]))
1150 break
1151 }
1152 }
1153 if n.Type.IsFloat() {
1154 if n.Left.Type.Etype == TINT64 {
1155 n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
1156 break
1157 }
1158
1159 if n.Left.Type.Etype == TUINT64 {
1160 n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
1161 break
1162 }
Cherry Zhange6f1a882016-08-16 12:14:54 -04001163 if n.Left.Type.Etype == TUINT32 || n.Left.Type.Etype == TUINT || n.Left.Type.Etype == TUINTPTR {
Keith Randalldf2f8132016-07-21 10:37:59 -07001164 n = conv(mkcall("uint32tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT32])), n.Type)
1165 break
1166 }
1167 }
1168 }
1169
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001170 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001171
1172 case OANDNOT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001173 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001174 n.Op = OAND
1175 n.Right = Nod(OCOM, n.Right, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001176 n.Right = typecheck(n.Right, Erv)
1177 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001178
1179 case OMUL:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001180 n.Left = walkexpr(n.Left, init)
1181 n.Right = walkexpr(n.Right, init)
1182 n = walkmul(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001183
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001184 case ODIV, OMOD:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001185 n.Left = walkexpr(n.Left, init)
1186 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001187
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001188 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001189 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001190
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001191 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001192 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001193 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1194 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001195 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001196 }
1197
1198 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001199 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001200 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001201 }
1202
1203 // Try rewriting as shifts or magic multiplies.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001204 n = walkdiv(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001205
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001206 // rewrite 64-bit div and mod into function calls
1207 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001208 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001209 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001210 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001211 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001212 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001213 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001214 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001215 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001216 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001217 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001218 }
1219 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001220 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001221 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001222 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001223 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001224 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001225 }
1226
Russ Cox8c195bd2015-02-13 14:40:36 -05001227 case OINDEX:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001228 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001229
1230 // save the original node for bounds checking elision.
1231 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001232 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001233
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001234 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001235
1236 // if range of type cannot exceed static array bound,
1237 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001238 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001239 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001240 }
Russ Cox382b44e2015-02-23 16:07:24 -05001241 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001242 if t != nil && t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001243 t = t.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05001244 }
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001245 if t.IsArray() {
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001246 n.Bounded = bounded(r, t.NumElem())
Russ Coxdc7b54b2015-02-17 22:13:49 -05001247 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001248 Warn("index bounds check elided")
1249 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001250 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001251 Yyerror("index out of bounds")
1252 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001253 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001254 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001255 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001256 Warn("index bounds check elided")
1257 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001258 if Smallintconst(n.Right) {
1259 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001260 Yyerror("index out of bounds")
1261 } else {
1262 // replace "abc"[1] with 'b'.
1263 // delayed until now because "abc"[1] is not
1264 // an ideal constant.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001265 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05001266
Russ Cox81d58102015-05-27 00:47:05 -04001267 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001268 n.Typecheck = 1
1269 }
1270 }
1271 }
1272
Russ Coxdc7b54b2015-02-17 22:13:49 -05001273 if Isconst(n.Right, CTINT) {
Robert Griesemer07749ae2016-03-21 10:52:03 -07001274 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 -05001275 Yyerror("index out of bounds")
1276 }
1277 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001278
1279 case OINDEXMAP:
1280 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001281 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001282 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001283 n.Left = walkexpr(n.Left, init)
1284 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001285
Russ Cox382b44e2015-02-23 16:07:24 -05001286 t := n.Left.Type
1287 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001288 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08001289 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001290 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001291 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001292 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001293 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001294 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001295 p = "mapaccess1_faststr"
1296 }
1297 }
1298
Russ Cox382b44e2015-02-23 16:07:24 -05001299 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001300 if p != "" {
1301 // fast versions take key by value
1302 key = n.Right
1303 } else {
1304 // standard version takes key by reference.
1305 // orderexpr made sure key is addressable.
1306 key = Nod(OADDR, n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001307 p = "mapaccess1"
1308 }
1309
Keith Randall60fd32a2016-04-19 08:31:04 -07001310 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
1311 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
1312 } else {
1313 p = "mapaccess1_fat"
1314 z := zeroaddr(w)
1315 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
1316 }
Keith Randall3c1a4c12016-04-19 21:06:53 -07001317 n.NonNil = true // mapaccess always returns a non-nil pointer
Russ Cox8c195bd2015-02-13 14:40:36 -05001318 n = Nod(OIND, n, nil)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001319 n.Type = t.Val()
Russ Cox8c195bd2015-02-13 14:40:36 -05001320 n.Typecheck = 1
1321
Russ Cox8c195bd2015-02-13 14:40:36 -05001322 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001323 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001324
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001325 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001326 n.Left = walkexpr(n.Left, init)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001327 low, high, max := n.SliceBounds()
1328 low = walkexpr(low, init)
1329 if low != nil && iszero(low) {
1330 // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
1331 low = nil
Russ Coxd4472792015-05-06 12:35:53 -04001332 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001333 high = walkexpr(high, init)
1334 max = walkexpr(max, init)
1335 n.SetSliceBounds(low, high, max)
1336 if n.Op.IsSlice3() {
1337 if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
1338 // Reduce x[i:j:cap(x)] to x[i:j].
1339 if n.Op == OSLICE3 {
1340 n.Op = OSLICE
1341 } else {
1342 n.Op = OSLICEARR
1343 }
1344 n = reduceSlice(n)
Russ Coxd4472792015-05-06 12:35:53 -04001345 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001346 } else {
Russ Coxd4472792015-05-06 12:35:53 -04001347 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001348 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001349
1350 case OADDR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001351 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001352
1353 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001354 if n.Esc == EscNone {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001355 if n.Type.Elem().Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001356 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001357 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001358 r := temp(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001359 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001360 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001361 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001362 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001363 r = typecheck(r, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001364 n = r
1365 } else {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001366 n = callnew(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001367 }
1368
Russ Cox8c195bd2015-02-13 14:40:36 -05001369 // If one argument to the comparison is an empty string,
1370 // comparing the lengths instead will yield the same result
1371 // without the function call.
1372 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001373 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 +02001374 // TODO(marvin): Fix Node.EType type union.
1375 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001376 r = typecheck(r, Erv)
1377 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001378 r.Type = n.Type
1379 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001380 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001381 }
1382
1383 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001384 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 +02001385 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001386 r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001387 r = typecheck(r, Erv)
1388 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001389 r.Type = n.Type
1390 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001391 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001392 }
1393
Russ Cox382b44e2015-02-23 16:07:24 -05001394 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001395 // TODO(marvin): Fix Node.EType type union.
1396 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001397 // prepare for rewrite below
1398 n.Left = cheapexpr(n.Left, init)
1399
1400 n.Right = cheapexpr(n.Right, init)
1401
1402 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1403
1404 // quick check of len before full compare for == or !=
1405 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001406 // TODO(marvin): Fix Node.EType type union.
1407 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001408 // len(left) == len(right) && eqstring(left, right)
1409 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1410 } else {
1411 // len(left) != len(right) || !eqstring(left, right)
1412 r = Nod(ONOT, r, nil)
1413
1414 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1415 }
1416
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001417 r = typecheck(r, Erv)
1418 r = walkexpr(r, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001419 } else {
1420 // sys_cmpstring(s1, s2) :: 0
1421 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1422
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001423 // TODO(marvin): Fix Node.EType type union.
1424 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001425 }
1426
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001427 r = typecheck(r, Erv)
Matthew Dempsky3efefd92016-03-30 14:56:08 -07001428 if !n.Type.IsBoolean() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001429 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001430 }
1431 r.Type = n.Type
1432 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001433
1434 case OADDSTR:
1435 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001436
1437 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001438 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001439 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001440
1441 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001442 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001443
1444 // cannot use chanfn - closechan takes any, not chan any
1445 case OCLOSE:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001446 fn := syslook("closechan")
Russ Cox8c195bd2015-02-13 14:40:36 -05001447
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001448 fn = substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001449 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001450
1451 case OMAKECHAN:
1452 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 -05001453
1454 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001455 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001456
Russ Cox382b44e2015-02-23 16:07:24 -05001457 a := nodnil() // hmap buffer
1458 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001459 if n.Esc == EscNone {
1460 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001461 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001462
1463 a = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001464 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001465 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001466 a = Nod(OADDR, var_, nil)
1467
1468 // Allocate one bucket on stack.
1469 // Maximum key/value size is 128 bytes, larger objects
1470 // are stored with an indirection. So max bucket size is 2048+eps.
1471 var_ = temp(mapbucket(t))
1472
1473 r = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001474 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001475 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001476 r = Nod(OADDR, var_, nil)
1477 }
1478
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001479 fn := syslook("makemap")
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001480 fn = substArgTypes(fn, hmap(t), mapbucket(t), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05001481 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001482
1483 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001484 l := n.Left
1485 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001486 if r == nil {
1487 r = safeexpr(l, init)
1488 l = r
1489 }
Russ Cox382b44e2015-02-23 16:07:24 -05001490 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001491 if n.Esc == EscNone {
1492 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001493 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001494 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001495 // var arr [r]T
1496 // n = arr[:l]
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001497 t = aindex(r, t.Elem()) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001498 var_ := temp(t)
1499 a := Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001500 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001501 init.Append(a)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001502 r := Nod(OSLICE, var_, nil) // arr[:l]
1503 r.SetSliceBounds(nil, l, nil)
1504 r = conv(r, n.Type) // in case n.Type is named.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001505 r = typecheck(r, Erv)
1506 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001507 n = r
1508 } else {
Martin Mòˆhrmanne6f9f392016-08-25 14:17:52 +02001509 // n escapes; set up a call to makeslice.
1510 // When len and cap can fit into int, use makeslice instead of
1511 // makeslice64, which is faster and shorter on 32 bit platforms.
Russ Cox8c195bd2015-02-13 14:40:36 -05001512
Martin Mòˆhrmanne6f9f392016-08-25 14:17:52 +02001513 len, cap := l, r
1514
1515 fnname := "makeslice64"
1516 argtype := Types[TINT64]
1517
1518 // typechecking guarantees that TIDEAL len/cap are positive and fit in an int.
1519 // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
1520 // will be handled by the negative range checks in makeslice during runtime.
1521 if (len.Type.IsKind(TIDEAL) || Maxintval[len.Type.Etype].Cmp(Maxintval[TUINT]) <= 0) &&
1522 (cap.Type.IsKind(TIDEAL) || Maxintval[cap.Type.Etype].Cmp(Maxintval[TUINT]) <= 0) {
1523 fnname = "makeslice"
1524 argtype = Types[TINT]
1525 }
1526
1527 fn := syslook(fnname)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001528 fn = substArgTypes(fn, t.Elem()) // any-1
Martin Mòˆhrmanne6f9f392016-08-25 14:17:52 +02001529 n = mkcall1(fn, t, init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
Russ Cox8c195bd2015-02-13 14:40:36 -05001530 }
1531
Russ Cox8c195bd2015-02-13 14:40:36 -05001532 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001533 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001534 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001535 t := aindex(Nodintconst(4), Types[TUINT8])
1536 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001537 a = Nod(OADDR, var_, nil)
1538 }
1539
1540 // intstring(*[4]byte, rune)
1541 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1542
Russ Cox8c195bd2015-02-13 14:40:36 -05001543 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001544 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001545 if n.Esc == EscNone {
1546 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001547 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001548
1549 a = Nod(OADDR, temp(t), nil)
1550 }
1551
1552 // slicebytetostring(*[32]byte, []byte) string;
1553 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1554
Russ Cox8c195bd2015-02-13 14:40:36 -05001555 // slicebytetostringtmp([]byte) string;
1556 case OARRAYBYTESTRTMP:
1557 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1558
Russ Cox8c195bd2015-02-13 14:40:36 -05001559 // slicerunetostring(*[32]byte, []rune) string;
1560 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001561 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001562
1563 if n.Esc == EscNone {
1564 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001565 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001566
1567 a = Nod(OADDR, temp(t), nil)
1568 }
1569
1570 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001571
1572 // stringtoslicebyte(*32[byte], string) []byte;
1573 case OSTRARRAYBYTE:
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[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001579
1580 a = Nod(OADDR, temp(t), nil)
1581 }
1582
1583 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001584
1585 // stringtoslicebytetmp(string) []byte;
1586 case OSTRARRAYBYTETMP:
1587 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1588
Russ Cox8c195bd2015-02-13 14:40:36 -05001589 // stringtoslicerune(*[32]rune, string) []rune
1590 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001591 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001592
1593 if n.Esc == EscNone {
1594 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001595 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001596
1597 a = Nod(OADDR, temp(t), nil)
1598 }
1599
1600 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001601
1602 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1603 case OCMPIFACE:
1604 if !Eqtype(n.Left.Type, n.Right.Type) {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001605 Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001606 }
Russ Cox382b44e2015-02-23 16:07:24 -05001607 var fn *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001608 if n.Left.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001609 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001610 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001611 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001612 }
1613
1614 n.Right = cheapexpr(n.Right, init)
1615 n.Left = cheapexpr(n.Left, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001616 fn = substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001617 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001618 // TODO(marvin): Fix Node.EType type union.
1619 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001620 r = Nod(ONOT, r, nil)
1621 }
1622
1623 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001624 // TODO(marvin): Fix Node.EType type union.
1625 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001626 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1627 } else {
1628 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1629 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001630 r = typecheck(r, Erv)
1631 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001632 r.Type = n.Type
1633 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001634
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001635 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Josh Bleecher Snyder3c6e60c2016-04-19 12:08:33 -07001636 if isStaticCompositeLiteral(n) {
Keith Randallb024ed02016-04-18 11:17:55 -07001637 // n can be directly represented in the read-only data section.
1638 // Make direct reference to the static data. See issue 12841.
1639 vstat := staticname(n.Type, 0)
1640 if n.Op == OSTRUCTLIT {
1641 structlit(0, 1, n, vstat, init)
1642 } else {
1643 arraylit(0, 1, n, vstat, init)
1644 }
1645 n = vstat
1646 n = typecheck(n, Erv)
1647 break
1648 }
Russ Cox382b44e2015-02-23 16:07:24 -05001649 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001650 anylit(0, n, var_, init)
1651 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001652
1653 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001654 n1 := n.Right
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001655 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001656 n1 = walkexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001657 n1 = Nod(OADDR, n1, nil)
1658 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001659
1660 case OCLOSURE:
1661 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001662
1663 case OCALLPART:
1664 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001665 }
1666
Russ Cox8c195bd2015-02-13 14:40:36 -05001667 // Expressions that are constant at run time but not
1668 // considered const by the language spec are not turned into
1669 // constants until walk. For example, if n is y%1 == 0, the
1670 // walk of y%1 may have replaced it by 0.
1671 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001672 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001673
1674 evconst(n)
1675 n.Type = t
1676 if n.Op == OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001677 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001678 }
1679
1680 ullmancalc(n)
1681
1682 if Debug['w'] != 0 && n != nil {
1683 Dump("walk", n)
1684 }
1685
1686 lineno = lno
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001687 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05001688}
1689
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001690// TODO(josharian): combine this with its caller and simplify
Russ Coxd4472792015-05-06 12:35:53 -04001691func reduceSlice(n *Node) *Node {
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001692 low, high, max := n.SliceBounds()
1693 if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
Russ Coxd4472792015-05-06 12:35:53 -04001694 // Reduce x[i:len(x)] to x[i:].
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001695 high = nil
Russ Coxd4472792015-05-06 12:35:53 -04001696 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001697 n.SetSliceBounds(low, high, max)
1698 if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
Russ Coxd4472792015-05-06 12:35:53 -04001699 // Reduce x[:] to x.
1700 if Debug_slice > 0 {
1701 Warn("slice: omit slice operation")
1702 }
1703 return n.Left
1704 }
1705 return n
1706}
1707
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001708func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001709 // convas will turn map assigns into function calls,
1710 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001711 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001712
1713 if l.Op == OINDEXMAP {
1714 return n
1715 }
1716
1717 return convas(n, init)
1718}
1719
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001720func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001721 // check assign expression list to
1722 // a expression list. called in
1723 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001724
1725 // ensure order of evaluation for function calls
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001726 for i := range nl {
1727 nl[i] = safeexpr(nl[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001728 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001729 for i1 := range nr {
1730 nr[i1] = safeexpr(nr[i1], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001731 }
1732
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001733 var nn []*Node
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001734 i := 0
1735 for ; i < len(nl); i++ {
1736 if i >= len(nr) {
1737 break
1738 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001739 // Do not generate 'x = x' during return. See issue 4014.
Russ Coxb6dc3e62016-05-25 01:33:24 -04001740 if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001741 continue
1742 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001743 nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001744 }
1745
1746 // cannot happen: caller checked that lists had same length
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001747 if i < len(nl) || i < len(nr) {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001748 var nln, nrn Nodes
1749 nln.Set(nl)
1750 nrn.Set(nr)
Dave Cheney2da642a2016-04-27 15:15:47 +10001751 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 -05001752 }
1753 return nn
1754}
1755
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001756// l is an lv and rt is the type of an rv
1757// return 1 if this implies a function call
1758// evaluating the lv or a function call
1759// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001760func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001761 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001762 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001763 }
Russ Cox175929b2015-03-02 14:22:05 -05001764 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001765 if needwritebarrier(l, &r) {
1766 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001767 }
1768 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001769 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001770 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001771 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001772}
1773
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001774// check assign type list to
1775// a expression list. called in
1776// expr-list = func()
1777func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
1778 r, saver := IterFields(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001779
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001780 var nn, mm []*Node
1781 var ullmanOverflow bool
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001782 var i int
1783 for i = 0; i < nl.Len(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001784 if r == nil {
1785 break
1786 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001787 l := nl.Index(i)
Russ Cox8c195bd2015-02-13 14:40:36 -05001788 if isblank(l) {
Matthew Dempsky7758a942016-03-08 15:02:40 -08001789 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001790 continue
1791 }
1792
1793 // any lv that causes a fn call must be
1794 // deferred until all the return arguments
1795 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001796 if fncall(l, r.Type) {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001797 tmp := temp(r.Type)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001798 tmp = typecheck(tmp, Erv)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001799 a := Nod(OAS, l, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001800 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001801 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001802 l = tmp
1803 }
1804
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001805 a := Nod(OAS, l, nodarg(r, fp))
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 a = convas(a, init)
1807 ullmancalc(a)
1808 if a.Ullman >= UINF {
1809 Dump("ascompatet ucount", a)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001810 ullmanOverflow = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001811 }
1812
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001813 nn = append(nn, a)
Matthew Dempsky7758a942016-03-08 15:02:40 -08001814 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001815 }
1816
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001817 if i < nl.Len() || r != nil {
Matthew Dempskydbed1c62016-03-17 13:26:08 -07001818 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
Russ Cox8c195bd2015-02-13 14:40:36 -05001819 }
1820
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001821 if ullmanOverflow {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001822 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001823 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001824 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001825}
1826
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001827// package all the arguments that match a ... T parameter into a []T.
Matthew Dempsky2e936902016-03-14 01:20:49 -07001828func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001829 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001830 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001831 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001832 }
1833
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001834 tslice := typSlice(l.Type.Elem())
Josh Bleecher Snyderb6b144b2015-05-04 15:01:29 -07001835 tslice.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001836
Russ Cox382b44e2015-02-23 16:07:24 -05001837 var n *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001838 if len(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001839 n = nodnil()
1840 n.Type = tslice
1841 } else {
1842 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001843 if ddd != nil && prealloc[ddd] != nil {
1844 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001845 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001846 n.List.Set(lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001847 n.Esc = esc
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001848 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001849 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001850 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001851 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001852 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001853 }
1854
Russ Cox382b44e2015-02-23 16:07:24 -05001855 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001856 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001857 return nn
1858}
1859
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001860// helpers for shape errors
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001861func dumptypes(nl *Type, what string) string {
1862 s := ""
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001863 for _, l := range nl.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001864 if s != "" {
1865 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001866 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07001867 s += Fldconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001868 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001869 if s == "" {
1870 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001871 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001872 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001873}
1874
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001875func dumpnodetypes(l []*Node, what string) string {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001876 s := ""
1877 for _, r := range l {
1878 if s != "" {
1879 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001880 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001881 s += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001882 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001883 if s == "" {
1884 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001885 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001886 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001887}
1888
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001889// check assign expression list to
1890// a type list. called in
1891// return expr-list
1892// func(expr-list)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001893func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05001894 lr0 := lr
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001895 l, savel := IterFields(nl)
Russ Cox175929b2015-03-02 14:22:05 -05001896 var r *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001897 if len(lr) > 0 {
1898 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001899 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001900 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001901
1902 // f(g()) where g has multiple return values
Josh Bleecher Snyderfda831e2016-04-05 16:44:07 -07001903 if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001904 // optimization - can do block copy
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001905 if eqtypenoname(r.Type, nl) {
1906 arg := nodarg(nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001907 r = Nod(OCONVNOP, r, nil)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001908 r.Type = arg.Type
1909 nn = []*Node{convas(Nod(OAS, arg, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001910 goto ret
1911 }
1912
1913 // conversions involved.
1914 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001915 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001916
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001917 for _, l := range r.Type.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001918 tmp := temp(l.Type)
1919 alist = append(alist, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001920 }
1921
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001922 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001923 a.List.Set(alist)
1924 a.Rlist.Set(lr)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001925 a = typecheck(a, Etop)
1926 a = walkstmt(a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001927 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001928 lr = alist
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001929 r = lr[0]
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001930 l, savel = IterFields(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -05001931 }
1932
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001933 for {
1934 if l != nil && l.Isddd {
1935 // the ddd parameter must be last
1936 ll := savel.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001937
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001938 if ll != nil {
1939 Yyerror("... must be last argument")
Russ Cox8c195bd2015-02-13 14:40:36 -05001940 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001941
1942 // special case --
1943 // only if we are assigning a single ddd
1944 // argument to a ddd parameter then it is
Eric Engestrom7a8caf72016-04-03 12:43:27 +01001945 // passed through unencapsulated
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001946 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
1947 a := Nod(OAS, nodarg(l, fp), r)
1948 a = convas(a, init)
1949 nn = append(nn, a)
1950 break
1951 }
1952
1953 // normal case -- make a slice of all
1954 // remaining arguments and pass it to
1955 // the ddd parameter.
1956 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1957
1958 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001959 }
1960
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001961 if l == nil || r == nil {
1962 if l != nil || r != nil {
1963 l1 := dumptypes(nl, "expected")
1964 l2 := dumpnodetypes(lr0, "given")
1965 if l != nil {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001966 Yyerror("not enough arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001967 } else {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001968 Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001969 }
1970 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001971
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001972 break
1973 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001974
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001975 a := Nod(OAS, nodarg(l, fp), r)
1976 a = convas(a, init)
1977 nn = append(nn, a)
1978
1979 l = savel.Next()
1980 r = nil
1981 lr = lr[1:]
1982 if len(lr) > 0 {
1983 r = lr[0]
1984 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001985 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001986
1987ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001988 for _, n := range nn {
1989 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001990 }
1991 return nn
1992}
1993
1994// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001995func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001996 var r *Node
1997 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001998 var on *Node
1999 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002000 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05002001
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002002 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05002003 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002004 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05002005 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05002006
2007 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002008 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002009
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002010 calls = append(calls, mkcall("printlock", nil, init))
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002011 for i1, n1 := range all.Slice() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002012 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002013 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002014 }
2015
Russ Coxdc7b54b2015-02-17 22:13:49 -05002016 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05002017
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002018 n = n1
Russ Cox8c195bd2015-02-13 14:40:36 -05002019 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002020 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002021 case CTRUNE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002022 n = defaultlit(n, runetype)
Russ Cox8c195bd2015-02-13 14:40:36 -05002023
2024 case CTINT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002025 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002026
2027 case CTFLT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002028 n = defaultlit(n, Types[TFLOAT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002029 }
2030 }
2031
2032 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002033 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002034 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002035 n = defaultlit(n, nil)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002036 all.SetIndex(i1, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002037 if n.Type == nil || n.Type.Etype == TFORW {
2038 continue
2039 }
2040
2041 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002042 et = n.Type.Etype
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002043 if n.Type.IsInterface() {
Matthew Dempsky00e5a682016-04-01 13:36:24 -07002044 if n.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002045 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002046 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002047 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002048 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002049 on = substArgTypes(on, n.Type) // any-1
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07002050 } else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002051 on = syslook("printpointer")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002052 on = substArgTypes(on, n.Type) // any-1
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002053 } else if n.Type.IsSlice() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002054 on = syslook("printslice")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002055 on = substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002056 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002057 if et == TUINT64 {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002058 if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002059 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002060 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002061 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002062 }
2063 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002064 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002065 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002066 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002067 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002068 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002069 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002070 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002071 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05002072 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002073 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05002074 } else {
2075 badtype(OPRINT, n.Type, nil)
2076 continue
2077 }
2078
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -07002079 t = on.Type.Params().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002080
2081 if !Eqtype(t, n.Type) {
2082 n = Nod(OCONV, n, nil)
2083 n.Type = t
2084 }
2085
2086 r = Nod(OCALL, on, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002087 r.List.Append(n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002088 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002089 }
2090
2091 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002092 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002093 }
2094
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002095 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002096
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002097 typecheckslice(calls, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002098 walkexprlist(calls, init)
2099
2100 r = Nod(OEMPTY, nil, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002101 r = typecheck(r, Etop)
2102 r = walkexpr(r, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002103 r.Ninit.Set(calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002104 return r
2105}
2106
2107func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002108 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002109 fn := syslook("newobject")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002110 fn = substArgTypes(fn, t)
Keith Randall3c1a4c12016-04-19 21:06:53 -07002111 v := mkcall1(fn, Ptrto(t), nil, typename(t))
2112 v.NonNil = true
2113 return v
Russ Cox8c195bd2015-02-13 14:40:36 -05002114}
2115
Russ Cox3b6e86f2015-06-29 15:17:14 -04002116func iscallret(n *Node) bool {
2117 n = outervalue(n)
2118 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2119}
2120
Russ Coxdc7b54b2015-02-17 22:13:49 -05002121func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002122 n = outervalue(n)
2123
2124 // If n is *autotmp and autotmp = &foo, replace n with foo.
2125 // We introduce such temps when initializing struct literals.
2126 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002127 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002128 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2129 n = defn.Right.Left
2130 }
2131 }
2132
2133 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002134 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002135 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002136
2137 case ONAME:
2138 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002139 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002140 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002141 }
2142 }
2143
Russ Coxdc7b54b2015-02-17 22:13:49 -05002144 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002145}
2146
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002147func (n *Node) isGlobal() bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002148 n = outervalue(n)
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002149 return n.Op == ONAME && n.Class == PEXTERN
Russ Cox8c195bd2015-02-13 14:40:36 -05002150}
2151
2152// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002153func needwritebarrier(l *Node, r *Node) bool {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002154 if !use_writebarrier {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002155 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 }
2157
2158 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002159 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002160 }
2161
2162 // No write barrier for write of non-pointers.
2163 dowidth(l.Type)
2164
2165 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002166 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002167 }
2168
2169 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002170 if isstack(l) {
2171 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002172 }
2173
Russ Cox9f90f312015-06-29 12:49:25 -04002174 // No write barrier for implicit zeroing.
2175 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002176 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002177 }
2178
Russ Cox9f90f312015-06-29 12:49:25 -04002179 // Ignore no-op conversions when making decision.
2180 // Ensures that xp = unsafe.Pointer(&x) is treated
2181 // the same as xp = &x.
2182 for r.Op == OCONVNOP {
2183 r = r.Left
2184 }
2185
2186 // No write barrier for zeroing or initialization to constant.
2187 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002188 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002189 }
2190
2191 // No write barrier for storing static (read-only) data.
2192 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002193 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002194 }
2195
2196 // No write barrier for storing address of stack values,
2197 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002198 if r.Op == OADDR && isstack(r.Left) {
2199 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002200 }
2201
2202 // No write barrier for storing address of global, which
2203 // is live no matter what.
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002204 if r.Op == OADDR && r.Left.isGlobal() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002205 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002206 }
2207
Austin Clements3e54ca92016-03-16 18:22:58 -04002208 // No write barrier for storing global function, which is live
2209 // no matter what.
2210 if r.Op == ONAME && r.Class == PFUNC {
2211 return false
2212 }
2213
Russ Cox8c195bd2015-02-13 14:40:36 -05002214 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002215 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002216}
2217
2218// TODO(rsc): Perhaps componentgen should run before this.
2219
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002220func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002221 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002222 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002223 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002224 }
Russ Cox972a4782015-05-21 15:00:06 -04002225 n.Op = OASWB
2226 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002227 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002228 return n
2229}
2230
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002231func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002232 if n.Op != OAS {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10002233 Fatalf("convas: not OAS %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002234 }
2235
2236 n.Typecheck = 1
2237
Russ Cox382b44e2015-02-23 16:07:24 -05002238 var lt *Type
2239 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002240 if n.Left == nil || n.Right == nil {
2241 goto out
2242 }
2243
2244 lt = n.Left.Type
2245 rt = n.Right.Type
2246 if lt == nil || rt == nil {
2247 goto out
2248 }
2249
2250 if isblank(n.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002251 n.Right = defaultlit(n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002252 goto out
2253 }
2254
2255 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002256 map_ := n.Left.Left
2257 key := n.Left.Right
2258 val := n.Right
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002259 map_ = walkexpr(map_, init)
2260 key = walkexpr(key, init)
2261 val = walkexpr(val, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002262
2263 // orderexpr made sure key and val are addressable.
2264 key = Nod(OADDR, key, nil)
2265
2266 val = Nod(OADDR, val, nil)
2267 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2268 goto out
2269 }
2270
2271 if !Eqtype(lt, rt) {
2272 n.Right = assignconv(n.Right, lt, "assignment")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002273 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002274 }
2275
2276out:
2277 ullmancalc(n)
2278 return n
2279}
2280
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002281// from ascompat[te]
2282// evaluating actual function arguments.
2283// f(a,b)
2284// if there is exactly one function expr,
2285// then it is done first. otherwise must
2286// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002287func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002288 c := 0 // function calls
2289 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002290
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002291 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002292 t++
2293 ullmancalc(n)
2294 if n.Ullman >= UINF {
2295 c++
2296 }
2297 }
2298
2299 if c == 0 || t == 1 {
2300 return all
2301 }
2302
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002303 var g []*Node // fncalls assigned to tempnames
2304 var f *Node // last fncall assigned to stack
2305 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002306 d := 0
2307 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002308 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002309 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002310 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002311 continue
2312 }
2313
2314 d++
2315 if d == c {
2316 f = n
2317 continue
2318 }
2319
2320 // make assignment of fncall to tempname
2321 a = temp(n.Right.Type)
2322
2323 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002324 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002325
2326 // put normal arg assignment on list
2327 // with fncall replaced by tempname
2328 n.Right = a.Left
2329
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002330 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002331 }
2332
2333 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002334 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002335 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002336 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002337}
2338
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002339// from ascompat[ee]
2340// a,b = c,d
2341// simultaneous assignment. there cannot
2342// be later use of an earlier lvalue.
2343//
2344// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002345func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002346 var l *Node
2347
2348 // If a needed expression may be affected by an
2349 // earlier assignment, make an early copy of that
2350 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002351 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002352
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002353 var mapinit Nodes
2354 for i, n := range all {
2355 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002356
2357 // Save subexpressions needed on left side.
2358 // Drill through non-dereferences.
2359 for {
2360 if l.Op == ODOT || l.Op == OPAREN {
2361 l = l.Left
2362 continue
2363 }
2364
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002365 if l.Op == OINDEX && l.Left.Type.IsArray() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002366 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002367 l = l.Left
2368 continue
2369 }
2370
2371 break
2372 }
2373
2374 switch l.Op {
2375 default:
Dave Cheney733f8352016-04-27 19:34:17 +10002376 Fatalf("reorder3 unexpected lvalue %#v", l.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002377
2378 case ONAME:
2379 break
2380
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002381 case OINDEX, OINDEXMAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002382 l.Left = reorder3save(l.Left, all, i, &early)
2383 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002384 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002385 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002386 }
2387
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002388 case OIND, ODOTPTR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002389 l.Left = reorder3save(l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002390 }
2391
2392 // Save expression on right side.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002393 all[i].Right = reorder3save(all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002394 }
2395
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002396 early = append(mapinit.Slice(), early...)
2397 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002398}
2399
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002400// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002401// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002402// copy into a temporary during *early and
2403// replace *np with that temp.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002404// The result of reorder3save MUST be assigned back to n, e.g.
2405// n.Left = reorder3save(n.Left, all, i, early)
2406func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002407 if !aliased(n, all, i) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002408 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002409 }
2410
Russ Cox382b44e2015-02-23 16:07:24 -05002411 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002412 q = Nod(OAS, q, n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002413 q = typecheck(q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002414 *early = append(*early, q)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002415 return q.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002416}
2417
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002418// what's the outer value that a write to n affects?
2419// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002420func outervalue(n *Node) *Node {
2421 for {
2422 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002423 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002424 }
2425 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2426 n = n.Left
2427 continue
2428 }
2429
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002430 if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002431 n = n.Left
2432 continue
2433 }
2434
2435 break
2436 }
2437
2438 return n
2439}
2440
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002441// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002442// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002443func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002444 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002445 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002446 }
2447
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002448 // Treat all fields of a struct as referring to the whole struct.
2449 // We could do better but we would have to keep track of the fields.
2450 for n.Op == ODOT {
2451 n = n.Left
2452 }
2453
Russ Cox8c195bd2015-02-13 14:40:36 -05002454 // Look for obvious aliasing: a variable being assigned
2455 // during the all list and appearing in n.
2456 // Also record whether there are any writes to main memory.
2457 // Also record whether there are any writes to variables
2458 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002459 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002460
Russ Cox382b44e2015-02-23 16:07:24 -05002461 varwrite := 0
2462 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002463 for _, an := range all[:i] {
2464 a = outervalue(an.Left)
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002465
2466 for a.Op == ODOT {
2467 a = a.Left
2468 }
2469
Russ Cox8c195bd2015-02-13 14:40:36 -05002470 if a.Op != ONAME {
2471 memwrite = 1
2472 continue
2473 }
2474
2475 switch n.Class {
2476 default:
2477 varwrite = 1
2478 continue
2479
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002480 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002481 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002482 varwrite = 1
2483 continue
2484 }
2485
Russ Coxdc7b54b2015-02-17 22:13:49 -05002486 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002487 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002488 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002489 }
2490 }
2491 }
2492
2493 // The variables being written do not appear in n.
2494 // However, n might refer to computed addresses
2495 // that are being written.
2496
2497 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002498 if memwrite == 0 && varwrite == 0 {
2499 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002500 }
2501
2502 // If n does not refer to computed addresses
2503 // (that is, if n only refers to variables whose addresses
2504 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002505 if varexpr(n) {
2506 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002507 }
2508
2509 // Otherwise, both the writes and n refer to computed memory addresses.
2510 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002511 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002512}
2513
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002514// does the evaluation of n only refer to variables
2515// whose addresses have not been taken?
2516// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002517func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002518 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002519 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002520 }
2521
2522 switch n.Op {
2523 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002524 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002525
2526 case ONAME:
2527 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002528 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002529 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002530 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002531 }
2532 }
2533
Russ Coxdc7b54b2015-02-17 22:13:49 -05002534 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002535
2536 case OADD,
2537 OSUB,
2538 OOR,
2539 OXOR,
2540 OMUL,
2541 ODIV,
2542 OMOD,
2543 OLSH,
2544 ORSH,
2545 OAND,
2546 OANDNOT,
2547 OPLUS,
2548 OMINUS,
2549 OCOM,
2550 OPAREN,
2551 OANDAND,
2552 OOROR,
Russ Cox8c195bd2015-02-13 14:40:36 -05002553 OCONV,
2554 OCONVNOP,
2555 OCONVIFACE,
2556 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002557 return varexpr(n.Left) && varexpr(n.Right)
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002558
2559 case ODOT: // but not ODOTPTR
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002560 // Should have been handled in aliased.
2561 Fatalf("varexpr unexpected ODOT")
Russ Cox8c195bd2015-02-13 14:40:36 -05002562 }
2563
2564 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002565 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002566}
2567
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002568// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002569func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002570 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002571 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002572 }
2573 switch r.Op {
2574 // match each right given left
2575 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002576 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002577
2578 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002579 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002580 }
2581
Russ Coxdc7b54b2015-02-17 22:13:49 -05002582 if vmatch2(l, r.Left) {
2583 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002585 if vmatch2(l, r.Right) {
2586 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002587 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002588 for _, n := range r.List.Slice() {
2589 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002590 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002591 }
2592 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002593 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002594}
2595
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002596// is any name mentioned in l also mentioned in r?
2597// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002598func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002599 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002600 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002601 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002602 }
2603 switch l.Op {
2604 case ONAME:
2605 switch l.Class {
Russ Cox20803b82016-05-25 10:29:50 -04002606 case PPARAM, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002607 break
2608
2609 // assignment to non-stack variable
2610 // must be delayed if right has function calls.
2611 default:
2612 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002613 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002614 }
2615 }
2616
2617 return vmatch2(l, r)
2618
2619 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002620 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002621 }
2622
Russ Coxdc7b54b2015-02-17 22:13:49 -05002623 if vmatch1(l.Left, r) {
2624 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002625 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002626 if vmatch1(l.Right, r) {
2627 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002628 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002629 for _, n := range l.List.Slice() {
2630 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002631 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002632 }
2633 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002634 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002635}
2636
Matthew Dempsky2339b132016-03-09 18:54:26 -08002637// paramstoheap returns code to allocate memory for heap-escaped parameters
2638// and to copy non-result prameters' values from the stack.
2639// If out is true, then code is also produced to zero-initialize their
2640// stack memory addresses.
Russ Coxdec1bae2016-05-25 10:01:58 -04002641func paramstoheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002642 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002643 for _, t := range params.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002644 // For precise stacks, the garbage collector assumes results
2645 // are always live, so zero them always.
Russ Coxdec1bae2016-05-25 10:01:58 -04002646 if params.StructType().Funarg == FunargResults {
Russ Cox8c195bd2015-02-13 14:40:36 -05002647 // Defer might stop a panic and show the
2648 // return values as they exist at the time of panic.
2649 // Make sure to zero them on entry to the function.
Russ Coxdec1bae2016-05-25 10:01:58 -04002650 nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002651 }
2652
Russ Coxb6dc3e62016-05-25 01:33:24 -04002653 v := t.Nname
2654 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
2655 v = nil
2656 }
2657 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002658 continue
2659 }
2660
Russ Coxb6dc3e62016-05-25 01:33:24 -04002661 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
2662 nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
2663 if stackcopy.Class == PPARAM {
2664 nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
2665 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002666 }
2667 }
2668
2669 return nn
2670}
2671
Matthew Dempsky2339b132016-03-09 18:54:26 -08002672// returnsfromheap returns code to copy values for heap-escaped parameters
2673// back to the stack.
2674func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002675 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002676 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002677 v := t.Nname
Russ Coxb6dc3e62016-05-25 01:33:24 -04002678 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002679 continue
2680 }
Russ Coxb6dc3e62016-05-25 01:33:24 -04002681 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
2682 nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
2683 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002684 }
2685
2686 return nn
2687}
2688
Matthew Dempsky2339b132016-03-09 18:54:26 -08002689// heapmoves generates code to handle migrating heap-escaped parameters
2690// between the stack and the heap. The generated code is added to Curfn's
2691// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002692func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002693 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002694 lineno = Curfn.Lineno
Russ Coxdec1bae2016-05-25 10:01:58 -04002695 nn := paramstoheap(Curfn.Type.Recvs())
2696 nn = append(nn, paramstoheap(Curfn.Type.Params())...)
2697 nn = append(nn, paramstoheap(Curfn.Type.Results())...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002698 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002699 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002700 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002701 lineno = lno
2702}
2703
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002704func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002705 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002706 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002707 }
2708
Matthew Dempskyc8377612016-03-17 01:47:16 -07002709 n := fn.Type.Params().NumFields()
Russ Cox8c195bd2015-02-13 14:40:36 -05002710
Russ Cox382b44e2015-02-23 16:07:24 -05002711 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002712 r.List.Set(va[:n])
Matthew Dempskyc8377612016-03-17 01:47:16 -07002713 if fn.Type.Results().NumFields() > 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002714 r = typecheck(r, Erv|Efnstruct)
Russ Cox8c195bd2015-02-13 14:40:36 -05002715 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002716 r = typecheck(r, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002717 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002718 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002719 r.Type = t
2720 return r
2721}
2722
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002723func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002724 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002725}
2726
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002727func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002728 return vmkcall(fn, t, init, args)
2729}
2730
2731func conv(n *Node, t *Type) *Node {
2732 if Eqtype(n.Type, t) {
2733 return n
2734 }
2735 n = Nod(OCONV, n, nil)
2736 n.Type = t
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002737 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05002738 return n
2739}
2740
2741func chanfn(name string, n int, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002742 if !t.IsChan() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002743 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002744 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002745 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002746 switch n {
2747 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002748 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002749 case 1:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002750 fn = substArgTypes(fn, t.Elem())
Russ Cox13f9c8b2015-03-08 13:33:49 -04002751 case 2:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002752 fn = substArgTypes(fn, t.Elem(), t.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002753 }
2754 return fn
2755}
2756
2757func mapfn(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002758 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002759 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002760 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002761 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002762 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05002763 return fn
2764}
2765
2766func mapfndel(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002767 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002768 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002769 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002770 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002771 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002772 return fn
2773}
2774
2775func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002776 fn := syslook(name)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002777 fn = substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002778 return fn
2779}
2780
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002781func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002782 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002783 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002784
2785 if c < 2 {
2786 Yyerror("addstr count %d too small", c)
2787 }
2788
Russ Cox382b44e2015-02-23 16:07:24 -05002789 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002790 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002791 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002792 for _, n1 := range n.List.Slice() {
2793 if n1.Op == OLITERAL {
2794 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002795 }
2796 }
2797
2798 // Don't allocate the buffer if the result won't fit.
2799 if sz < tmpstringbufsize {
2800 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002801 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002802
2803 buf = Nod(OADDR, temp(t), nil)
2804 }
2805 }
2806
2807 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002808 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002809 for _, n2 := range n.List.Slice() {
2810 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002811 }
2812
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002813 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002814 if c <= 5 {
2815 // small numbers of strings use direct runtime helpers.
2816 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002817 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002818 } else {
2819 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002820 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002821
Josh Bleecher Snydereb98e512016-03-28 22:57:57 -07002822 t := typSlice(Types[TSTRING])
Russ Cox382b44e2015-02-23 16:07:24 -05002823 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002824 if prealloc[n] != nil {
2825 prealloc[slice] = prealloc[n]
2826 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002827 slice.List.Set(args[1:]) // skip buf arg
Keith Randall934c3592016-04-23 22:59:01 -07002828 args = []*Node{buf, slice}
Russ Cox8c195bd2015-02-13 14:40:36 -05002829 slice.Esc = EscNone
2830 }
2831
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002832 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002833 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002834 r.List.Set(args)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002835 r = typecheck(r, Erv)
2836 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002837 r.Type = n.Type
2838
2839 return r
2840}
2841
2842// expand append(l1, l2...) to
2843// init {
2844// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002845// n := len(s) + len(l2)
2846// // Compare as uint so growslice can panic on overflow.
2847// if uint(n) > uint(cap(s)) {
2848// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002849// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002850// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002851// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2852// }
2853// s
2854//
2855// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002856func appendslice(n *Node, init *Nodes) *Node {
2857 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002858
2859 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2860 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002861 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002862 ls := n.List.Slice()
2863 for i1, n1 := range ls {
2864 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002865 }
2866
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002867 l1 := n.List.First()
2868 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002869
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002870 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002871
2872 // var s []T
2873 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002874 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002875
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002876 // n := len(s) + len(l2)
2877 nn := temp(Types[TINT])
2878 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002879
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002880 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002881 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002882 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2883 nif.Left.Left.Type = Types[TUINT]
2884 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002885
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002886 // instantiate growslice(Type*, []any, int) []any
2887 fn := syslook("growslice")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002888 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002889
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002890 // s = growslice(T, s, n)
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002891 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 -08002892 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002893
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002894 // s = s[:n]
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002895 nt := Nod(OSLICE, s, nil)
2896 nt.SetSliceBounds(nil, nn, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002897 nt.Etype = 1
2898 l = append(l, Nod(OAS, s, nt))
2899
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002900 if haspointers(l1.Type.Elem()) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002901 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002902 nptr1 := Nod(OSLICE, s, nil)
2903 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002904 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002905 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002906 fn := syslook("typedslicecopy")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002907 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002908 var ln Nodes
2909 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002910 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002911 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002912 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002913 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002914 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002915 nptr1 := Nod(OSLICE, s, nil)
2916 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002917 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002918 nptr2 := l2
2919 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002920 if l2.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002921 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002922 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002923 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002924 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002925 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002926 var ln Nodes
2927 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002928 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002929 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002930 } else {
2931 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002932 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002933 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002934
Russ Cox8c195bd2015-02-13 14:40:36 -05002935 nptr1 = Nod(OADDR, nptr1, nil)
2936
Russ Cox382b44e2015-02-23 16:07:24 -05002937 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002938
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002939 fn := syslook("memmove")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002940 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002941
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002942 var ln Nodes
2943 ln.Set(l)
2944 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002945
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002946 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002947 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2948 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002949 }
2950
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002951 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002952 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002953 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002954 return s
2955}
2956
Russ Cox85520472015-05-06 12:34:30 -04002957// Rewrite append(src, x, y, z) so that any side effects in
2958// x, y, z (including runtime panics) are evaluated in
2959// initialization statements before the append.
2960// For normal code generation, stop there and leave the
2961// rest to cgen_append.
2962//
2963// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002964//
2965// init {
2966// s := src
2967// const argc = len(args) - 1
2968// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002969// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002970// }
2971// n := len(s)
2972// s = s[:n+argc]
2973// s[n] = a
2974// s[n+1] = b
2975// ...
2976// }
2977// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002978func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002979 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002980 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002981 n.List.SetIndex(0, walkexpr(n.List.Index(0), init))
Russ Cox85520472015-05-06 12:34:30 -04002982 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002983 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002984
2985 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2986 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002987 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002988 // Using cheapexpr also makes sure that the evaluation
2989 // of all arguments (and especially any panics) happen
2990 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002991 ls := n.List.Slice()[1:]
2992 for i, n := range ls {
2993 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002994 }
2995
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002996 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002997
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002998 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002999 if argc < 1 {
3000 return nsrc
3001 }
3002
Russ Cox85520472015-05-06 12:34:30 -04003003 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07003004 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003005 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04003006 return n
3007 }
3008
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003009 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003010
Russ Cox382b44e2015-02-23 16:07:24 -05003011 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003012 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05003013
Russ Cox382b44e2015-02-23 16:07:24 -05003014 na := Nodintconst(int64(argc)) // const argc
3015 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04003016 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05003017
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003018 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003019 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05003020
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003021 nx.Nbody.Set1(Nod(OAS, ns,
Keith Randallbfe0cbd2016-04-19 15:38:59 -07003022 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003023 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05003024
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003025 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05003026
Russ Cox382b44e2015-02-23 16:07:24 -05003027 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003028 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05003029
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07003030 nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
3031 nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003032 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003033 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05003034
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003035 ls = n.List.Slice()[1:]
3036 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05003037 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003038 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003039 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
3040 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003041 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003042 }
3043 }
3044
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003045 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003046 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003047 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003048 return ns
3049}
3050
3051// Lower copy(a, b) to a memmove call or a runtime call.
3052//
3053// init {
3054// n := len(a)
3055// if n > len(b) { n = len(b) }
3056// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3057// }
3058// n;
3059//
3060// Also works if b is a string.
3061//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003062func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003063 if haspointers(n.Left.Type.Elem()) {
Russ Cox382b44e2015-02-23 16:07:24 -05003064 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003065 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05003066 }
3067
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003068 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003069 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003070 if n.Right.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003071 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003072 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003073 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003074 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003075 fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003076 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003077 }
3078
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003079 n.Left = walkexpr(n.Left, init)
3080 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003081 nl := temp(n.Left.Type)
3082 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003083 var l []*Node
3084 l = append(l, Nod(OAS, nl, n.Left))
3085 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003086
Russ Cox382b44e2015-02-23 16:07:24 -05003087 nfrm := Nod(OSPTR, nr, nil)
3088 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003089
Russ Cox382b44e2015-02-23 16:07:24 -05003090 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003091
3092 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003093 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003094
3095 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003096 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003097
Russ Cox66be1482015-05-26 21:30:20 -04003098 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003099 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003100 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003101
3102 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003103 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003104
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003105 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
Russ Cox382b44e2015-02-23 16:07:24 -05003106 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003107 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003108 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003109 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003110
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003111 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003112 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003113 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003114 return nlen
3115}
3116
Russ Cox8c195bd2015-02-13 14:40:36 -05003117func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003118 // Should only arrive here with large memory or
3119 // a struct/array containing a non-memory field/element.
3120 // Small memory is handled inline, and single non-memory
3121 // is handled during type check (OCMPSTR etc).
Matthew Dempsky077902d2016-04-01 11:22:03 -07003122 switch a, _ := algtype1(t); a {
3123 case AMEM:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003124 n := syslook("memequal")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003125 n = substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003126 *needsize = 1
3127 return n
Matthew Dempsky077902d2016-04-01 11:22:03 -07003128 case ASPECIAL:
3129 sym := typesymprefix(".eq", t)
3130 n := newname(sym)
3131 n.Class = PFUNC
3132 ntype := Nod(OTFUNC, nil, nil)
3133 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3134 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3135 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3136 ntype = typecheck(ntype, Etype)
3137 n.Type = ntype.Type
3138 *needsize = 0
3139 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003140 }
Matthew Dempsky077902d2016-04-01 11:22:03 -07003141 Fatalf("eqfor %v", t)
3142 return nil
Russ Cox8c195bd2015-02-13 14:40:36 -05003143}
3144
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003145// The result of walkcompare MUST be assigned back to n, e.g.
3146// n.Left = walkcompare(n.Left, init)
3147func walkcompare(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003148 // Given interface value l and concrete value r, rewrite
3149 // l == r
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003150 // into types-equal && data-equal.
3151 // This is efficient, avoids allocations, and avoids runtime calls.
3152 var l, r *Node
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003153 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003154 l = n.Left
3155 r = n.Right
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003156 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003157 l = n.Right
3158 r = n.Left
3159 }
3160
3161 if l != nil {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003162 // Handle both == and !=.
3163 eq := n.Op
3164 var andor Op
3165 if eq == OEQ {
3166 andor = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003167 } else {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003168 andor = OOROR
Russ Cox8c195bd2015-02-13 14:40:36 -05003169 }
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003170 // Check for types equal.
3171 // For empty interface, this is:
3172 // l.tab == type(r)
3173 // For non-empty interface, this is:
3174 // l.tab != nil && l.tab._type == type(r)
3175 var eqtype *Node
3176 tab := Nod(OITAB, l, nil)
3177 rtyp := typename(r.Type)
3178 if l.Type.IsEmptyInterface() {
3179 tab.Type = Ptrto(Types[TUINT8])
3180 tab.Typecheck = 1
3181 eqtype = Nod(eq, tab, rtyp)
3182 } else {
3183 nonnil := Nod(Brcom(eq), nodnil(), tab)
3184 match := Nod(eq, itabType(tab), rtyp)
3185 eqtype = Nod(andor, nonnil, match)
3186 }
3187 // Check for data equal.
3188 eqdata := Nod(eq, ifaceData(l, r.Type), r)
3189 // Put it all together.
3190 expr := Nod(andor, eqtype, eqdata)
3191 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003192 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003193 }
3194
3195 // Must be comparison of array or struct.
3196 // Otherwise back end handles it.
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003197 // While we're here, decide whether to
3198 // inline or call an eq alg.
Russ Cox44928112015-03-02 20:34:22 -05003199 t := n.Left.Type
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003200 var inline bool
Russ Cox8c195bd2015-02-13 14:40:36 -05003201 switch t.Etype {
3202 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003203 return n
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003204 case TARRAY:
3205 inline = t.NumElem() <= 1 || (t.NumElem() <= 4 && issimple[t.Elem().Etype])
3206 case TSTRUCT:
3207 inline = t.NumFields() <= 4
Russ Cox8c195bd2015-02-13 14:40:36 -05003208 }
3209
Russ Cox44928112015-03-02 20:34:22 -05003210 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003211 for cmpl != nil && cmpl.Op == OCONVNOP {
3212 cmpl = cmpl.Left
3213 }
Russ Cox44928112015-03-02 20:34:22 -05003214 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003215 for cmpr != nil && cmpr.Op == OCONVNOP {
3216 cmpr = cmpr.Left
3217 }
3218
Russ Coxdc7b54b2015-02-17 22:13:49 -05003219 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003220 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003221 }
3222
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003223 // Chose not to inline. Call equality function directly.
3224 if !inline {
3225 // eq algs take pointers
3226 pl := temp(Ptrto(t))
3227 al := Nod(OAS, pl, Nod(OADDR, cmpl, nil))
3228 al.Right.Etype = 1 // addr does not escape
3229 al = typecheck(al, Etop)
3230 init.Append(al)
Russ Cox8c195bd2015-02-13 14:40:36 -05003231
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003232 pr := temp(Ptrto(t))
3233 ar := Nod(OAS, pr, Nod(OADDR, cmpr, nil))
3234 ar.Right.Etype = 1 // addr does not escape
3235 ar = typecheck(ar, Etop)
3236 init.Append(ar)
Russ Cox8c195bd2015-02-13 14:40:36 -05003237
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003238 var needsize int
3239 call := Nod(OCALL, eqfor(t, &needsize), nil)
3240 call.List.Append(pl)
3241 call.List.Append(pr)
3242 if needsize != 0 {
3243 call.List.Append(Nodintconst(t.Width))
3244 }
3245 res := call
3246 if n.Op != OEQ {
3247 res = Nod(ONOT, res, nil)
3248 }
3249 n = finishcompare(n, res, init)
3250 return n
3251 }
3252
3253 // inline: build boolean expression comparing element by element
3254 andor := OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003255 if n.Op == ONE {
3256 andor = OOROR
3257 }
Russ Cox44928112015-03-02 20:34:22 -05003258 var expr *Node
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003259 compare := func(el, er *Node) {
3260 a := Nod(n.Op, el, er)
Russ Cox8c195bd2015-02-13 14:40:36 -05003261 if expr == nil {
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003262 expr = a
3263 } else {
3264 expr = Nod(andor, expr, a)
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003265 }
3266 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003267 cmpl = safeexpr(cmpl, init)
3268 cmpr = safeexpr(cmpr, init)
3269 if t.IsStruct() {
3270 for _, f := range t.Fields().Slice() {
3271 sym := f.Sym
3272 if isblanksym(sym) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003273 continue
3274 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003275 compare(
3276 NodSym(OXDOT, cmpl, sym),
3277 NodSym(OXDOT, cmpr, sym),
3278 )
Russ Cox8c195bd2015-02-13 14:40:36 -05003279 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003280 } else {
3281 for i := 0; int64(i) < t.NumElem(); i++ {
3282 compare(
3283 Nod(OINDEX, cmpl, Nodintconst(int64(i))),
3284 Nod(OINDEX, cmpr, Nodintconst(int64(i))),
3285 )
Russ Cox8c195bd2015-02-13 14:40:36 -05003286 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003287 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003288 if expr == nil {
3289 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003290 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003291 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003292 return n
Russ Cox44928112015-03-02 20:34:22 -05003293}
3294
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003295// The result of finishcompare MUST be assigned back to n, e.g.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003296// n.Left = finishcompare(n.Left, x, r, init)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003297func finishcompare(n, r *Node, init *Nodes) *Node {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003298 // Use nn here to avoid passing r to typecheck.
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003299 nn := r
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003300 nn = typecheck(nn, Erv)
3301 nn = walkexpr(nn, init)
3302 r = nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003303 if r.Type != n.Type {
3304 r = Nod(OCONVNOP, r, nil)
3305 r.Type = n.Type
3306 r.Typecheck = 1
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003307 nn = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003308 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003309 return nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003310}
3311
Russ Coxdc7b54b2015-02-17 22:13:49 -05003312func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003313 var ar *Node
3314 var br *Node
3315 for a != nil && b != nil && a.Op == b.Op {
3316 switch a.Op {
3317 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003318 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003319
3320 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003321 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003322
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003323 case ODOT, ODOTPTR:
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003324 if a.Sym != b.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003325 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003326 }
3327
3328 case OINDEX:
3329 ar = a.Right
3330 br = b.Right
Matthew Dempskyd3253872016-03-20 13:55:42 -07003331 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003332 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003333 }
3334 }
3335
3336 a = a.Left
3337 b = b.Left
3338 }
3339
Russ Coxdc7b54b2015-02-17 22:13:49 -05003340 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003341}
3342
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003343// The result of walkrotate MUST be assigned back to n, e.g.
3344// n.Left = walkrotate(n.Left)
3345func walkrotate(n *Node) *Node {
Cherry Zhangd99cee72016-08-10 13:24:03 -04003346 //TODO: enable LROT on ARM64 once the old backend is gone
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07003347 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003348 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003349 }
3350
Russ Cox8c195bd2015-02-13 14:40:36 -05003351 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003352 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003353
Russ Cox382b44e2015-02-23 16:07:24 -05003354 r := n.Right
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003355 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 -07003356 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003357 }
3358
3359 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003360 if !samecheap(l.Left, r.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003361 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003362 }
3363
3364 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003365 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003366
Michael Munday613ba6c2016-04-12 12:26:17 -04003367 if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
3368 // only supports 32-bit and 64-bit rotates
3369 return n
3370 }
3371
Russ Coxdc7b54b2015-02-17 22:13:49 -05003372 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003373 sl := int(l.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003374 if sl >= 0 {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003375 sr := int(r.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003376 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003377 // Rewrite left shift half to left rotate.
3378 if l.Op == OLSH {
3379 n = l
3380 } else {
3381 n = r
3382 }
3383 n.Op = OLROT
3384
3385 // Remove rotate 0 and rotate w.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003386 s := int(n.Right.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003387
3388 if s == 0 || s == w {
3389 n = n.Left
3390 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003391 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003392 }
3393 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003394 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003395 }
3396
3397 // 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 -07003398 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003399}
3400
Josh Bleecher Snyder62861882016-05-26 18:08:24 -07003401// isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers.
3402func (n *Node) isIntOrdering() bool {
3403 switch n.Op {
3404 case OLE, OLT, OGE, OGT:
3405 default:
3406 return false
3407 }
3408 return n.Left.Type.IsInteger() && n.Right.Type.IsInteger()
3409}
3410
3411// walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10.
3412// n must be an OANDAND or OOROR node.
3413// The result of walkinrange MUST be assigned back to n, e.g.
3414// n.Left = walkinrange(n.Left)
3415func walkinrange(n *Node, init *Nodes) *Node {
3416 // We are looking for something equivalent to a opl b OP b opr c, where:
3417 // * a, b, and c have integer type
3418 // * b is side-effect-free
3419 // * opl and opr are each < or ≤
3420 // * OP is &&
3421 l := n.Left
3422 r := n.Right
3423 if !l.isIntOrdering() || !r.isIntOrdering() {
3424 return n
3425 }
3426
3427 // Find b, if it exists, and rename appropriately.
3428 // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right
3429 // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c
3430 a, opl, b := l.Left, l.Op, l.Right
3431 x, opr, c := r.Left, r.Op, r.Right
3432 for i := 0; ; i++ {
3433 if samesafeexpr(b, x) {
3434 break
3435 }
3436 if i == 3 {
3437 // Tried all permutations and couldn't find an appropriate b == x.
3438 return n
3439 }
3440 if i&1 == 0 {
3441 a, opl, b = b, Brrev(opl), a
3442 } else {
3443 x, opr, c = c, Brrev(opr), x
3444 }
3445 }
3446
3447 // If n.Op is ||, apply de Morgan.
3448 // Negate the internal ops now; we'll negate the top level op at the end.
3449 // Henceforth assume &&.
3450 negateResult := n.Op == OOROR
3451 if negateResult {
3452 opl = Brcom(opl)
3453 opr = Brcom(opr)
3454 }
3455
3456 cmpdir := func(o Op) int {
3457 switch o {
3458 case OLE, OLT:
3459 return -1
3460 case OGE, OGT:
3461 return +1
3462 }
3463 Fatalf("walkinrange cmpdir %v", o)
3464 return 0
3465 }
3466 if cmpdir(opl) != cmpdir(opr) {
3467 // Not a range check; something like b < a && b < c.
3468 return n
3469 }
3470
3471 switch opl {
3472 case OGE, OGT:
3473 // We have something like a > b && b ≥ c.
3474 // Switch and reverse ops and rename constants,
3475 // to make it look like a ≤ b && b < c.
3476 a, c = c, a
3477 opl, opr = Brrev(opr), Brrev(opl)
3478 }
3479
3480 // We must ensure that c-a is non-negative.
3481 // For now, require a and c to be constants.
3482 // In the future, we could also support a == 0 and c == len/cap(...).
3483 // Unfortunately, by this point, most len/cap expressions have been
3484 // stored into temporary variables.
3485 if !Isconst(a, CTINT) || !Isconst(c, CTINT) {
3486 return n
3487 }
3488
3489 if opl == OLT {
3490 // We have a < b && ...
3491 // We need a ≤ b && ... to safely use unsigned comparison tricks.
3492 // If a is not the maximum constant for b's type,
3493 // we can increment a and switch to ≤.
3494 if a.Int64() >= Maxintval[b.Type.Etype].Int64() {
3495 return n
3496 }
3497 a = Nodintconst(a.Int64() + 1)
3498 opl = OLE
3499 }
3500
3501 bound := c.Int64() - a.Int64()
3502 if bound < 0 {
3503 // Bad news. Something like 5 <= x && x < 3.
3504 // Rare in practice, and we still need to generate side-effects,
3505 // so just leave it alone.
3506 return n
3507 }
3508
3509 // We have a ≤ b && b < c (or a ≤ b && b ≤ c).
3510 // This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a),
3511 // which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a),
3512 // which is equivalent to uint(b-a) < uint(c-a).
3513 ut := b.Type.toUnsigned()
3514 lhs := conv(Nod(OSUB, b, a), ut)
3515 rhs := Nodintconst(bound)
3516 if negateResult {
3517 // Negate top level.
3518 opr = Brcom(opr)
3519 }
3520 cmp := Nod(opr, lhs, rhs)
3521 cmp.Lineno = n.Lineno
3522 cmp = addinit(cmp, l.Ninit.Slice())
3523 cmp = addinit(cmp, r.Ninit.Slice())
3524 cmp = typecheck(cmp, Erv)
3525 cmp = walkexpr(cmp, init)
3526 return cmp
3527}
3528
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003529// walkmul rewrites integer multiplication by powers of two as shifts.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003530// The result of walkmul MUST be assigned back to n, e.g.
3531// n.Left = walkmul(n.Left, init)
3532func walkmul(n *Node, init *Nodes) *Node {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003533 if !n.Type.IsInteger() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003534 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003535 }
3536
Russ Cox382b44e2015-02-23 16:07:24 -05003537 var nr *Node
3538 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003539 if n.Right.Op == OLITERAL {
3540 nl = n.Left
3541 nr = n.Right
3542 } else if n.Left.Op == OLITERAL {
3543 nl = n.Right
3544 nr = n.Left
3545 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003546 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003547 }
3548
Russ Cox382b44e2015-02-23 16:07:24 -05003549 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003550
3551 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003552 var pow int
3553 var w int
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003554 if nr.Int64() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003555 cheapexpr(nl, init)
3556 Nodconst(n, n.Type, 0)
3557 goto ret
3558 }
3559
3560 // nr is a constant.
3561 pow = powtwo(nr)
3562
3563 if pow < 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003564 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003565 }
3566 if pow >= 1000 {
3567 // negative power of 2, like -16
3568 neg = 1
3569
3570 pow -= 1000
3571 }
3572
3573 w = int(nl.Type.Width * 8)
3574 if pow+1 >= w { // too big, shouldn't happen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003575 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003576 }
3577
3578 nl = cheapexpr(nl, init)
3579
3580 if pow == 0 {
3581 // x*1 is x
3582 n = nl
3583
3584 goto ret
3585 }
3586
3587 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3588
3589ret:
3590 if neg != 0 {
3591 n = Nod(OMINUS, n, nil)
3592 }
3593
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003594 n = typecheck(n, Erv)
3595 n = walkexpr(n, init)
3596 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003597}
3598
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003599// walkdiv rewrites division by a constant as less expensive
3600// operations.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003601// The result of walkdiv MUST be assigned back to n, e.g.
3602// n.Left = walkdiv(n.Left, init)
3603func walkdiv(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003604 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003605
3606 // TODO(minux)
Zhongwei Yao74a9bad2016-04-25 11:08:38 +08003607 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003608 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003609 }
3610
Russ Cox8c195bd2015-02-13 14:40:36 -05003611 if n.Right.Op != OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003612 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003613 }
3614
3615 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003616 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003617
Russ Cox382b44e2015-02-23 16:07:24 -05003618 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003619
3620 // special cases of mod/div
3621 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003622 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003623
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003624 s := 0 // 1 if nr is negative.
3625 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003626 if pow >= 1000 {
3627 // negative power of 2
3628 s = 1
3629
3630 pow -= 1000
3631 }
3632
3633 if pow+1 >= w {
3634 // divisor too large.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003635 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003636 }
3637
3638 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003639 // try to do division by multiply by (2^w)/d
3640 // see hacker's delight chapter 10
3641 // TODO: support 64-bit magic multiply here.
3642 var m Magic
3643 m.W = w
3644
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003645 if nl.Type.IsSigned() {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003646 m.Sd = nr.Int64()
Russ Cox79f727a2015-03-02 12:35:15 -05003647 Smagic(&m)
3648 } else {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003649 m.Ud = uint64(nr.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003650 Umagic(&m)
3651 }
3652
3653 if m.Bad != 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003654 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003655 }
3656
3657 // We have a quick division method so use it
3658 // for modulo too.
3659 if n.Op == OMOD {
3660 // rewrite as A%B = A - (A/B*B).
3661 n1 := Nod(ODIV, nl, nr)
3662
3663 n2 := Nod(OMUL, n1, nr)
3664 n = Nod(OSUB, nl, n2)
3665 goto ret
3666 }
3667
3668 switch Simtype[nl.Type.Etype] {
3669 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003670 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003671
3672 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003673 case TUINT8, TUINT16, TUINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003674 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003675
Dave Cheneya4be24c2016-03-23 13:27:49 +11003676 Nodconst(&nc, nl.Type, int64(m.Um))
3677 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003678 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003679 if m.Ua != 0 {
3680 // Select a Go type with (at least) twice the width.
3681 var twide *Type
3682 switch Simtype[nl.Type.Etype] {
3683 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003684 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003685
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003686 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003687 twide = Types[TUINT32]
3688
3689 case TUINT32:
3690 twide = Types[TUINT64]
3691
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003692 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003693 twide = Types[TINT32]
3694
3695 case TINT32:
3696 twide = Types[TINT64]
3697 }
3698
3699 // add numerator (might overflow).
3700 // n2 = (n1 + nl)
3701 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3702
3703 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003704 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003705
Dave Cheneya4be24c2016-03-23 13:27:49 +11003706 Nodconst(&nc, Types[TUINT], int64(m.S))
3707 n = conv(Nod(ORSH, n2, &nc), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003708 } else {
3709 // n = n1 >> m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003710 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003711
Dave Cheneya4be24c2016-03-23 13:27:49 +11003712 Nodconst(&nc, Types[TUINT], int64(m.S))
3713 n = Nod(ORSH, n1, &nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003714 }
3715
3716 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003717 case TINT8, TINT16, TINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003718 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003719
Dave Cheneya4be24c2016-03-23 13:27:49 +11003720 Nodconst(&nc, nl.Type, m.Sm)
3721 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003722 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003723 if m.Sm < 0 {
3724 // add the numerator.
3725 n1 = Nod(OADD, n1, nl)
3726 }
3727
3728 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003729 var ns Node
Russ Cox79f727a2015-03-02 12:35:15 -05003730
Dave Cheneya4be24c2016-03-23 13:27:49 +11003731 Nodconst(&ns, Types[TUINT], int64(m.S))
3732 n2 := conv(Nod(ORSH, n1, &ns), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003733
3734 // add 1 iff n1 is negative.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003735 var nneg Node
Russ Cox79f727a2015-03-02 12:35:15 -05003736
Dave Cheneya4be24c2016-03-23 13:27:49 +11003737 Nodconst(&nneg, Types[TUINT], int64(w)-1)
3738 n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative.
Russ Cox79f727a2015-03-02 12:35:15 -05003739 n = Nod(OSUB, n2, n3)
3740
3741 // apply sign.
3742 if m.Sd < 0 {
3743 n = Nod(OMINUS, n, nil)
3744 }
3745 }
3746
3747 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003748 }
3749
3750 switch pow {
3751 case 0:
3752 if n.Op == OMOD {
3753 // nl % 1 is zero.
3754 Nodconst(n, n.Type, 0)
3755 } else if s != 0 {
3756 // divide by -1
3757 n.Op = OMINUS
3758
3759 n.Right = nil
3760 } else {
3761 // divide by 1
3762 n = nl
3763 }
3764
3765 default:
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003766 if n.Type.IsSigned() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003767 if n.Op == OMOD {
3768 // signed modulo 2^pow is like ANDing
3769 // with the last pow bits, but if nl < 0,
3770 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003771 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003772
Dave Cheneya4be24c2016-03-23 13:27:49 +11003773 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3774 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003775 if pow == 1 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003776 n1 = typecheck(n1, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003777 n1 = cheapexpr(n1, init)
3778
3779 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003780 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003781
Dave Cheneya4be24c2016-03-23 13:27:49 +11003782 var nc Node
3783 Nodconst(&nc, nl.Type, 1)
3784 n3 := Nod(OAND, n2, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003785 n = Nod(OADD, n3, n1)
3786 } else {
3787 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003788 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003789
Dave Cheneya4be24c2016-03-23 13:27:49 +11003790 Nodconst(&nc, nl.Type, (1<<uint(pow))-1)
3791 n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003792 n2 = typecheck(n2, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003793 n2 = cheapexpr(n2, init)
3794
Russ Cox382b44e2015-02-23 16:07:24 -05003795 n3 := Nod(OADD, nl, n2)
Dave Cheneya4be24c2016-03-23 13:27:49 +11003796 n4 := Nod(OAND, n3, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003797 n = Nod(OSUB, n4, n2)
3798 }
3799
3800 break
3801 } else {
3802 // arithmetic right shift does not give the correct rounding.
3803 // if nl >= 0, nl >> n == nl / nr
3804 // if nl < 0, we want to add 2^n-1 first.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003805 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003806
Dave Cheneya4be24c2016-03-23 13:27:49 +11003807 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3808 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003809 if pow == 1 {
3810 // nl+1 is nl-(-1)
3811 n.Left = Nod(OSUB, nl, n1)
3812 } else {
3813 // Do a logical right right on -1 to keep pow bits.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003814 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003815
Dave Cheneya4be24c2016-03-23 13:27:49 +11003816 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Josh Bleecher Snyder62861882016-05-26 18:08:24 -07003817 n2 := Nod(ORSH, conv(n1, nl.Type.toUnsigned()), &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003818 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3819 }
3820
3821 // n = (nl + 2^pow-1) >> pow
3822 n.Op = ORSH
3823
Dave Cheneya4be24c2016-03-23 13:27:49 +11003824 var n2 Node
3825 Nodconst(&n2, Types[Simtype[TUINT]], int64(pow))
3826 n.Right = &n2
Russ Cox8c195bd2015-02-13 14:40:36 -05003827 n.Typecheck = 0
3828 }
3829
3830 if s != 0 {
3831 n = Nod(OMINUS, n, nil)
3832 }
3833 break
3834 }
3835
Dave Cheneya4be24c2016-03-23 13:27:49 +11003836 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003837 if n.Op == OMOD {
3838 // n = nl & (nr-1)
3839 n.Op = OAND
3840
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003841 Nodconst(&nc, nl.Type, nr.Int64()-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003842 } else {
3843 // n = nl >> pow
3844 n.Op = ORSH
3845
Dave Cheneya4be24c2016-03-23 13:27:49 +11003846 Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
Russ Cox8c195bd2015-02-13 14:40:36 -05003847 }
3848
3849 n.Typecheck = 0
Dave Cheneya4be24c2016-03-23 13:27:49 +11003850 n.Right = &nc
Russ Cox8c195bd2015-02-13 14:40:36 -05003851 }
3852
3853 goto ret
3854
Russ Cox8c195bd2015-02-13 14:40:36 -05003855ret:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003856 n = typecheck(n, Erv)
3857 n = walkexpr(n, init)
3858 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003859}
3860
3861// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003862func bounded(n *Node, max int64) bool {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003863 if n.Type == nil || !n.Type.IsInteger() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003864 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003865 }
3866
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003867 sign := n.Type.IsSigned()
Russ Cox382b44e2015-02-23 16:07:24 -05003868 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003869
Russ Coxdc7b54b2015-02-17 22:13:49 -05003870 if Smallintconst(n) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003871 v := n.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003872 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003873 }
3874
3875 switch n.Op {
3876 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003877 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003878 if Smallintconst(n.Left) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003879 v = n.Left.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003880 } else if Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003881 v = n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003882 }
3883
3884 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003885 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003886 }
3887
3888 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003889 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003890 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003891 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003892 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003893 }
3894 }
3895
3896 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003897 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003898 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003899 for bits > 0 && v >= 2 {
3900 bits--
3901 v >>= 1
3902 }
3903 }
3904
3905 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003906 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003907 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003908 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003909 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003910 }
3911 bits -= int32(v)
3912 }
3913 }
3914
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003915 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003916 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003917 }
3918
Russ Coxdc7b54b2015-02-17 22:13:49 -05003919 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003920}
3921
David Crawshawcc158402016-03-10 16:15:26 -05003922// usemethod check interface method calls for uses of reflect.Type.Method.
3923func usemethod(n *Node) {
3924 t := n.Left.Type
3925
3926 // Looking for either of:
3927 // Method(int) reflect.Method
3928 // MethodByName(string) (reflect.Method, bool)
3929 //
3930 // TODO(crawshaw): improve precision of match by working out
3931 // how to check the method name.
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003932 if n := t.Params().NumFields(); n != 1 {
David Crawshawcc158402016-03-10 16:15:26 -05003933 return
3934 }
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003935 if n := t.Results().NumFields(); n != 1 && n != 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003936 return
3937 }
3938 p0 := t.Params().Field(0)
3939 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003940 var res1 *Field
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003941 if t.Results().NumFields() == 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003942 res1 = t.Results().Field(1)
3943 }
3944
3945 if res1 == nil {
3946 if p0.Type.Etype != TINT {
3947 return
3948 }
3949 } else {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003950 if !p0.Type.IsString() {
David Crawshawcc158402016-03-10 16:15:26 -05003951 return
3952 }
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003953 if !res1.Type.IsBoolean() {
David Crawshawcc158402016-03-10 16:15:26 -05003954 return
3955 }
3956 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003957 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003958 return
3959 }
3960
3961 Curfn.Func.ReflectMethod = true
3962}
3963
Russ Cox8c195bd2015-02-13 14:40:36 -05003964func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003965 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003966 return
3967 }
3968
3969 switch n.Op {
3970 default:
Dave Cheneyd3c79d32016-04-27 15:10:10 +10003971 Fatalf("usefield %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05003972
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003973 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003974 break
3975 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003976 if n.Sym == nil {
Keith Randall71d13a82016-03-02 20:54:41 -08003977 // No field name. This DOTPTR was built by the compiler for access
3978 // to runtime data structures. Ignore.
3979 return
3980 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003981
Russ Cox496ad0a2015-05-26 21:49:31 -04003982 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003983 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003984 t = t.Elem()
Russ Cox496ad0a2015-05-26 21:49:31 -04003985 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003986 field := dotField[typeSym{t.Orig, n.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003987 if field == nil {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003988 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003989 }
Matthew Dempskye48a2952016-04-25 13:24:48 -07003990 if !strings.Contains(field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003991 return
3992 }
3993
Matthew Dempskya2a48062016-03-10 16:15:44 -08003994 outer := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003995 if outer.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003996 outer = outer.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05003997 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003998 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003999 Yyerror("tracked field must be in named struct type")
4000 }
4001 if !exportname(field.Sym.Name) {
4002 Yyerror("tracked field must be exported (upper case)")
4003 }
4004
Matthew Dempskya2a48062016-03-10 16:15:44 -08004005 sym := tracksym(outer, field)
4006 if Curfn.Func.FieldTrack == nil {
4007 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
4008 }
4009 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05004010}
4011
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08004012func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004013 for _, n := range l.Slice() {
4014 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08004015 return false
4016 }
4017 }
4018 return true
4019}
4020
Russ Coxdc7b54b2015-02-17 22:13:49 -05004021func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004022 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004023 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004024 }
4025
4026 switch n.Op {
4027 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004028 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004029
4030 // Discardable as long as the subpieces are.
4031 case ONAME,
4032 ONONAME,
4033 OTYPE,
4034 OPACK,
4035 OLITERAL,
4036 OADD,
4037 OSUB,
4038 OOR,
4039 OXOR,
4040 OADDSTR,
4041 OADDR,
4042 OANDAND,
4043 OARRAYBYTESTR,
4044 OARRAYRUNESTR,
4045 OSTRARRAYBYTE,
4046 OSTRARRAYRUNE,
4047 OCAP,
4048 OCMPIFACE,
4049 OCMPSTR,
4050 OCOMPLIT,
4051 OMAPLIT,
4052 OSTRUCTLIT,
4053 OARRAYLIT,
4054 OPTRLIT,
4055 OCONV,
4056 OCONVIFACE,
4057 OCONVNOP,
4058 ODOT,
4059 OEQ,
4060 ONE,
4061 OLT,
4062 OLE,
4063 OGT,
4064 OGE,
4065 OKEY,
4066 OLEN,
4067 OMUL,
4068 OLSH,
4069 ORSH,
4070 OAND,
4071 OANDNOT,
4072 ONEW,
4073 ONOT,
4074 OCOM,
4075 OPLUS,
4076 OMINUS,
4077 OOROR,
4078 OPAREN,
4079 ORUNESTR,
4080 OREAL,
4081 OIMAG,
4082 OCOMPLEX:
4083 break
4084
4085 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004086 case ODIV, OMOD:
Matthew Dempskyd3253872016-03-20 13:55:42 -07004087 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004088 break
4089 }
Matthew Dempskyd3253872016-03-20 13:55:42 -07004090 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004091 break
4092 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004093 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004094
4095 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004096 case OMAKECHAN, OMAKEMAP:
Matthew Dempskyd3253872016-03-20 13:55:42 -07004097 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004098 break
4099 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004100 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004101
4102 // Difficult to tell what sizes are okay.
4103 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004105 }
4106
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004107 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 -05004108 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004109 }
4110
Russ Coxdc7b54b2015-02-17 22:13:49 -05004111 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004112}
4113
4114// rewrite
4115// print(x, y, z)
4116// into
4117// func(a1, a2, a3) {
4118// print(a1, a2, a3)
4119// }(x, y, z)
4120// and same for println.
4121
4122var walkprintfunc_prgen int
4123
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004124// The result of walkprintfunc MUST be assigned back to n, e.g.
4125// n.Left = walkprintfunc(n.Left, init)
4126func walkprintfunc(n *Node, init *Nodes) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004127 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08004128 walkstmtlist(n.Ninit.Slice())
4129 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05004130 }
4131
Russ Cox382b44e2015-02-23 16:07:24 -05004132 t := Nod(OTFUNC, nil, nil)
4133 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004134 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05004135 var a *Node
4136 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004137 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05004138 buf = fmt.Sprintf("a%d", num)
4139 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004140 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
4141 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004142 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05004143 }
4144
Russ Cox382b44e2015-02-23 16:07:24 -05004145 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004146 walkprintfunc_prgen++
4147 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04004148 fn.Func.Nname = newname(Lookup(buf))
4149 fn.Func.Nname.Name.Defn = fn
4150 fn.Func.Nname.Name.Param.Ntype = t
4151 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05004152
Russ Cox382b44e2015-02-23 16:07:24 -05004153 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004154 Curfn = nil
4155 funchdr(fn)
4156
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02004157 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004158 a.List.Set(printargs)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004159 a = typecheck(a, Etop)
4160 a = walkstmt(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004161
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08004162 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004163
4164 funcbody(fn)
4165
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004166 fn = typecheck(fn, Etop)
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07004167 typecheckslice(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08004168 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05004169 Curfn = oldfn
4170
4171 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004172 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004173 a.List.Set(n.List.Slice())
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004174 a = typecheck(a, Etop)
4175 a = walkexpr(a, init)
4176 return a
Russ Cox8c195bd2015-02-13 14:40:36 -05004177}