blob: 8173a2e0cba396b6650ea820ebf7cd849d7747d7 [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 {
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001509 // makeslice(et *Type, nel int64, max int64) (ary []any)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001510 fn := syslook("makeslice")
Russ Cox8c195bd2015-02-13 14:40:36 -05001511
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001512 fn = substArgTypes(fn, t.Elem()) // any-1
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001513 n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001514 }
1515
Russ Cox8c195bd2015-02-13 14:40:36 -05001516 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001517 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001518 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001519 t := aindex(Nodintconst(4), Types[TUINT8])
1520 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001521 a = Nod(OADDR, var_, nil)
1522 }
1523
1524 // intstring(*[4]byte, rune)
1525 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1526
Russ Cox8c195bd2015-02-13 14:40:36 -05001527 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001528 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001529 if n.Esc == EscNone {
1530 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001531 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001532
1533 a = Nod(OADDR, temp(t), nil)
1534 }
1535
1536 // slicebytetostring(*[32]byte, []byte) string;
1537 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1538
Russ Cox8c195bd2015-02-13 14:40:36 -05001539 // slicebytetostringtmp([]byte) string;
1540 case OARRAYBYTESTRTMP:
1541 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1542
Russ Cox8c195bd2015-02-13 14:40:36 -05001543 // slicerunetostring(*[32]byte, []rune) string;
1544 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001545 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001546
1547 if n.Esc == EscNone {
1548 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001549 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001550
1551 a = Nod(OADDR, temp(t), nil)
1552 }
1553
1554 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001555
1556 // stringtoslicebyte(*32[byte], string) []byte;
1557 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001558 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001559
1560 if n.Esc == EscNone {
1561 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001562 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001563
1564 a = Nod(OADDR, temp(t), nil)
1565 }
1566
1567 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001568
1569 // stringtoslicebytetmp(string) []byte;
1570 case OSTRARRAYBYTETMP:
1571 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1572
Russ Cox8c195bd2015-02-13 14:40:36 -05001573 // stringtoslicerune(*[32]rune, string) []rune
1574 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001575 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001576
1577 if n.Esc == EscNone {
1578 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001579 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001580
1581 a = Nod(OADDR, temp(t), nil)
1582 }
1583
1584 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001585
1586 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1587 case OCMPIFACE:
1588 if !Eqtype(n.Left.Type, n.Right.Type) {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001589 Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001590 }
Russ Cox382b44e2015-02-23 16:07:24 -05001591 var fn *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001592 if n.Left.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001593 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001594 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001595 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001596 }
1597
1598 n.Right = cheapexpr(n.Right, init)
1599 n.Left = cheapexpr(n.Left, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001600 fn = substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001601 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001602 // TODO(marvin): Fix Node.EType type union.
1603 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001604 r = Nod(ONOT, r, nil)
1605 }
1606
1607 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001608 // TODO(marvin): Fix Node.EType type union.
1609 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001610 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1611 } else {
1612 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1613 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001614 r = typecheck(r, Erv)
1615 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001616 r.Type = n.Type
1617 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001618
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001619 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Josh Bleecher Snyder3c6e60c2016-04-19 12:08:33 -07001620 if isStaticCompositeLiteral(n) {
Keith Randallb024ed02016-04-18 11:17:55 -07001621 // n can be directly represented in the read-only data section.
1622 // Make direct reference to the static data. See issue 12841.
1623 vstat := staticname(n.Type, 0)
1624 if n.Op == OSTRUCTLIT {
1625 structlit(0, 1, n, vstat, init)
1626 } else {
1627 arraylit(0, 1, n, vstat, init)
1628 }
1629 n = vstat
1630 n = typecheck(n, Erv)
1631 break
1632 }
Russ Cox382b44e2015-02-23 16:07:24 -05001633 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001634 anylit(0, n, var_, init)
1635 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001636
1637 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001638 n1 := n.Right
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001639 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001640 n1 = walkexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001641 n1 = Nod(OADDR, n1, nil)
1642 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001643
1644 case OCLOSURE:
1645 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001646
1647 case OCALLPART:
1648 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001649 }
1650
Russ Cox8c195bd2015-02-13 14:40:36 -05001651 // Expressions that are constant at run time but not
1652 // considered const by the language spec are not turned into
1653 // constants until walk. For example, if n is y%1 == 0, the
1654 // walk of y%1 may have replaced it by 0.
1655 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001656 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001657
1658 evconst(n)
1659 n.Type = t
1660 if n.Op == OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001661 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001662 }
1663
1664 ullmancalc(n)
1665
1666 if Debug['w'] != 0 && n != nil {
1667 Dump("walk", n)
1668 }
1669
1670 lineno = lno
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001671 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05001672}
1673
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001674// TODO(josharian): combine this with its caller and simplify
Russ Coxd4472792015-05-06 12:35:53 -04001675func reduceSlice(n *Node) *Node {
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001676 low, high, max := n.SliceBounds()
1677 if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
Russ Coxd4472792015-05-06 12:35:53 -04001678 // Reduce x[i:len(x)] to x[i:].
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001679 high = nil
Russ Coxd4472792015-05-06 12:35:53 -04001680 }
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07001681 n.SetSliceBounds(low, high, max)
1682 if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
Russ Coxd4472792015-05-06 12:35:53 -04001683 // Reduce x[:] to x.
1684 if Debug_slice > 0 {
1685 Warn("slice: omit slice operation")
1686 }
1687 return n.Left
1688 }
1689 return n
1690}
1691
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001692func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001693 // convas will turn map assigns into function calls,
1694 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001695 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001696
1697 if l.Op == OINDEXMAP {
1698 return n
1699 }
1700
1701 return convas(n, init)
1702}
1703
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001704func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001705 // check assign expression list to
1706 // a expression list. called in
1707 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001708
1709 // ensure order of evaluation for function calls
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001710 for i := range nl {
1711 nl[i] = safeexpr(nl[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001712 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001713 for i1 := range nr {
1714 nr[i1] = safeexpr(nr[i1], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001715 }
1716
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001717 var nn []*Node
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001718 i := 0
1719 for ; i < len(nl); i++ {
1720 if i >= len(nr) {
1721 break
1722 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001723 // Do not generate 'x = x' during return. See issue 4014.
Russ Coxb6dc3e62016-05-25 01:33:24 -04001724 if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001725 continue
1726 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001727 nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001728 }
1729
1730 // cannot happen: caller checked that lists had same length
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001731 if i < len(nl) || i < len(nr) {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001732 var nln, nrn Nodes
1733 nln.Set(nl)
1734 nrn.Set(nr)
Dave Cheney2da642a2016-04-27 15:15:47 +10001735 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 -05001736 }
1737 return nn
1738}
1739
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001740// l is an lv and rt is the type of an rv
1741// return 1 if this implies a function call
1742// evaluating the lv or a function call
1743// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001744func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001745 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001746 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001747 }
Russ Cox175929b2015-03-02 14:22:05 -05001748 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001749 if needwritebarrier(l, &r) {
1750 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001751 }
1752 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001753 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001754 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001755 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001756}
1757
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001758// check assign type list to
1759// a expression list. called in
1760// expr-list = func()
1761func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
1762 r, saver := IterFields(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001763
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001764 var nn, mm []*Node
1765 var ullmanOverflow bool
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001766 var i int
1767 for i = 0; i < nl.Len(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001768 if r == nil {
1769 break
1770 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001771 l := nl.Index(i)
Russ Cox8c195bd2015-02-13 14:40:36 -05001772 if isblank(l) {
Matthew Dempsky7758a942016-03-08 15:02:40 -08001773 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001774 continue
1775 }
1776
1777 // any lv that causes a fn call must be
1778 // deferred until all the return arguments
1779 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001780 if fncall(l, r.Type) {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001781 tmp := temp(r.Type)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001782 tmp = typecheck(tmp, Erv)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001783 a := Nod(OAS, l, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001784 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001785 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001786 l = tmp
1787 }
1788
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001789 a := Nod(OAS, l, nodarg(r, fp))
Russ Cox8c195bd2015-02-13 14:40:36 -05001790 a = convas(a, init)
1791 ullmancalc(a)
1792 if a.Ullman >= UINF {
1793 Dump("ascompatet ucount", a)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001794 ullmanOverflow = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001795 }
1796
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001797 nn = append(nn, a)
Matthew Dempsky7758a942016-03-08 15:02:40 -08001798 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001799 }
1800
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001801 if i < nl.Len() || r != nil {
Matthew Dempskydbed1c62016-03-17 13:26:08 -07001802 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
Russ Cox8c195bd2015-02-13 14:40:36 -05001803 }
1804
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001805 if ullmanOverflow {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001806 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001807 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001808 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001809}
1810
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001811// package all the arguments that match a ... T parameter into a []T.
Matthew Dempsky2e936902016-03-14 01:20:49 -07001812func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001813 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001814 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001815 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001816 }
1817
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001818 tslice := typSlice(l.Type.Elem())
Josh Bleecher Snyderb6b144b2015-05-04 15:01:29 -07001819 tslice.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001820
Russ Cox382b44e2015-02-23 16:07:24 -05001821 var n *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001822 if len(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001823 n = nodnil()
1824 n.Type = tslice
1825 } else {
1826 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001827 if ddd != nil && prealloc[ddd] != nil {
1828 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001829 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001830 n.List.Set(lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001831 n.Esc = esc
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001832 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001833 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001834 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001835 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001836 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001837 }
1838
Russ Cox382b44e2015-02-23 16:07:24 -05001839 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001840 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001841 return nn
1842}
1843
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001844// helpers for shape errors
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001845func dumptypes(nl *Type, what string) string {
1846 s := ""
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001847 for _, l := range nl.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001848 if s != "" {
1849 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001850 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07001851 s += Fldconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001852 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001853 if s == "" {
1854 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001855 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001856 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001857}
1858
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001859func dumpnodetypes(l []*Node, what string) string {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001860 s := ""
1861 for _, r := range l {
1862 if s != "" {
1863 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001864 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001865 s += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001866 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001867 if s == "" {
1868 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001869 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001870 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001871}
1872
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001873// check assign expression list to
1874// a type list. called in
1875// return expr-list
1876// func(expr-list)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001877func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05001878 lr0 := lr
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001879 l, savel := IterFields(nl)
Russ Cox175929b2015-03-02 14:22:05 -05001880 var r *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001881 if len(lr) > 0 {
1882 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001883 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001884 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001885
1886 // f(g()) where g has multiple return values
Josh Bleecher Snyderfda831e2016-04-05 16:44:07 -07001887 if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001888 // optimization - can do block copy
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001889 if eqtypenoname(r.Type, nl) {
1890 arg := nodarg(nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001891 r = Nod(OCONVNOP, r, nil)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001892 r.Type = arg.Type
1893 nn = []*Node{convas(Nod(OAS, arg, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001894 goto ret
1895 }
1896
1897 // conversions involved.
1898 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001899 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001900
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001901 for _, l := range r.Type.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001902 tmp := temp(l.Type)
1903 alist = append(alist, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001904 }
1905
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001906 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001907 a.List.Set(alist)
1908 a.Rlist.Set(lr)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001909 a = typecheck(a, Etop)
1910 a = walkstmt(a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001911 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001912 lr = alist
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001913 r = lr[0]
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001914 l, savel = IterFields(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -05001915 }
1916
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001917 for {
1918 if l != nil && l.Isddd {
1919 // the ddd parameter must be last
1920 ll := savel.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001921
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001922 if ll != nil {
1923 Yyerror("... must be last argument")
Russ Cox8c195bd2015-02-13 14:40:36 -05001924 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001925
1926 // special case --
1927 // only if we are assigning a single ddd
1928 // argument to a ddd parameter then it is
Eric Engestrom7a8caf72016-04-03 12:43:27 +01001929 // passed through unencapsulated
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001930 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
1931 a := Nod(OAS, nodarg(l, fp), r)
1932 a = convas(a, init)
1933 nn = append(nn, a)
1934 break
1935 }
1936
1937 // normal case -- make a slice of all
1938 // remaining arguments and pass it to
1939 // the ddd parameter.
1940 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1941
1942 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001943 }
1944
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001945 if l == nil || r == nil {
1946 if l != nil || r != nil {
1947 l1 := dumptypes(nl, "expected")
1948 l2 := dumpnodetypes(lr0, "given")
1949 if l != nil {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001950 Yyerror("not enough arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001951 } else {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10001952 Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001953 }
1954 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001955
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001956 break
1957 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001958
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001959 a := Nod(OAS, nodarg(l, fp), r)
1960 a = convas(a, init)
1961 nn = append(nn, a)
1962
1963 l = savel.Next()
1964 r = nil
1965 lr = lr[1:]
1966 if len(lr) > 0 {
1967 r = lr[0]
1968 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001969 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001970
1971ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001972 for _, n := range nn {
1973 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001974 }
1975 return nn
1976}
1977
1978// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001979func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001980 var r *Node
1981 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001982 var on *Node
1983 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001984 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001985
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001986 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001987 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001988 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001989 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001990
1991 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001992 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001993
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001994 calls = append(calls, mkcall("printlock", nil, init))
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001995 for i1, n1 := range all.Slice() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001996 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001997 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001998 }
1999
Russ Coxdc7b54b2015-02-17 22:13:49 -05002000 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05002001
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002002 n = n1
Russ Cox8c195bd2015-02-13 14:40:36 -05002003 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04002004 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002005 case CTRUNE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002006 n = defaultlit(n, runetype)
Russ Cox8c195bd2015-02-13 14:40:36 -05002007
2008 case CTINT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002009 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002010
2011 case CTFLT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002012 n = defaultlit(n, Types[TFLOAT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002013 }
2014 }
2015
2016 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002017 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05002018 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002019 n = defaultlit(n, nil)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002020 all.SetIndex(i1, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002021 if n.Type == nil || n.Type.Etype == TFORW {
2022 continue
2023 }
2024
2025 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02002026 et = n.Type.Etype
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002027 if n.Type.IsInterface() {
Matthew Dempsky00e5a682016-04-01 13:36:24 -07002028 if n.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002029 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002030 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002031 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05002032 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002033 on = substArgTypes(on, n.Type) // any-1
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07002034 } else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002035 on = syslook("printpointer")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002036 on = substArgTypes(on, n.Type) // any-1
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002037 } else if n.Type.IsSlice() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002038 on = syslook("printslice")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002039 on = substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002040 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05002041 if et == TUINT64 {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002042 if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002043 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002044 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002045 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002046 }
2047 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002048 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05002049 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002050 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002051 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00002052 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002053 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05002054 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002055 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05002056 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002057 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05002058 } else {
2059 badtype(OPRINT, n.Type, nil)
2060 continue
2061 }
2062
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -07002063 t = on.Type.Params().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002064
2065 if !Eqtype(t, n.Type) {
2066 n = Nod(OCONV, n, nil)
2067 n.Type = t
2068 }
2069
2070 r = Nod(OCALL, on, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002071 r.List.Append(n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002072 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002073 }
2074
2075 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002076 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002077 }
2078
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002079 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002080
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002081 typecheckslice(calls, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002082 walkexprlist(calls, init)
2083
2084 r = Nod(OEMPTY, nil, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002085 r = typecheck(r, Etop)
2086 r = walkexpr(r, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002087 r.Ninit.Set(calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002088 return r
2089}
2090
2091func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002092 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002093 fn := syslook("newobject")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002094 fn = substArgTypes(fn, t)
Keith Randall3c1a4c12016-04-19 21:06:53 -07002095 v := mkcall1(fn, Ptrto(t), nil, typename(t))
2096 v.NonNil = true
2097 return v
Russ Cox8c195bd2015-02-13 14:40:36 -05002098}
2099
Russ Cox3b6e86f2015-06-29 15:17:14 -04002100func iscallret(n *Node) bool {
2101 n = outervalue(n)
2102 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2103}
2104
Russ Coxdc7b54b2015-02-17 22:13:49 -05002105func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002106 n = outervalue(n)
2107
2108 // If n is *autotmp and autotmp = &foo, replace n with foo.
2109 // We introduce such temps when initializing struct literals.
2110 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002111 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002112 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2113 n = defn.Right.Left
2114 }
2115 }
2116
2117 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002118 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002119 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002120
2121 case ONAME:
2122 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002123 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002124 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002125 }
2126 }
2127
Russ Coxdc7b54b2015-02-17 22:13:49 -05002128 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002129}
2130
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002131func (n *Node) isGlobal() bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002132 n = outervalue(n)
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002133 return n.Op == ONAME && n.Class == PEXTERN
Russ Cox8c195bd2015-02-13 14:40:36 -05002134}
2135
2136// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002137func needwritebarrier(l *Node, r *Node) bool {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002138 if !use_writebarrier {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002139 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002140 }
2141
2142 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002143 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002144 }
2145
2146 // No write barrier for write of non-pointers.
2147 dowidth(l.Type)
2148
2149 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002150 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002151 }
2152
2153 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002154 if isstack(l) {
2155 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 }
2157
Russ Cox9f90f312015-06-29 12:49:25 -04002158 // No write barrier for implicit zeroing.
2159 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002160 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002161 }
2162
Russ Cox9f90f312015-06-29 12:49:25 -04002163 // Ignore no-op conversions when making decision.
2164 // Ensures that xp = unsafe.Pointer(&x) is treated
2165 // the same as xp = &x.
2166 for r.Op == OCONVNOP {
2167 r = r.Left
2168 }
2169
2170 // No write barrier for zeroing or initialization to constant.
2171 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002172 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002173 }
2174
2175 // No write barrier for storing static (read-only) data.
2176 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002177 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002178 }
2179
2180 // No write barrier for storing address of stack values,
2181 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002182 if r.Op == OADDR && isstack(r.Left) {
2183 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002184 }
2185
2186 // No write barrier for storing address of global, which
2187 // is live no matter what.
Josh Bleecher Snydera301b322016-05-16 14:14:16 -07002188 if r.Op == OADDR && r.Left.isGlobal() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002189 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002190 }
2191
Austin Clements3e54ca92016-03-16 18:22:58 -04002192 // No write barrier for storing global function, which is live
2193 // no matter what.
2194 if r.Op == ONAME && r.Class == PFUNC {
2195 return false
2196 }
2197
Russ Cox8c195bd2015-02-13 14:40:36 -05002198 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002199 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002200}
2201
2202// TODO(rsc): Perhaps componentgen should run before this.
2203
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002204func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002205 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002206 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002207 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002208 }
Russ Cox972a4782015-05-21 15:00:06 -04002209 n.Op = OASWB
2210 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002211 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002212 return n
2213}
2214
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002215func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002216 if n.Op != OAS {
Dave Cheneyd3c79d32016-04-27 15:10:10 +10002217 Fatalf("convas: not OAS %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002218 }
2219
2220 n.Typecheck = 1
2221
Russ Cox382b44e2015-02-23 16:07:24 -05002222 var lt *Type
2223 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002224 if n.Left == nil || n.Right == nil {
2225 goto out
2226 }
2227
2228 lt = n.Left.Type
2229 rt = n.Right.Type
2230 if lt == nil || rt == nil {
2231 goto out
2232 }
2233
2234 if isblank(n.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002235 n.Right = defaultlit(n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002236 goto out
2237 }
2238
2239 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002240 map_ := n.Left.Left
2241 key := n.Left.Right
2242 val := n.Right
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002243 map_ = walkexpr(map_, init)
2244 key = walkexpr(key, init)
2245 val = walkexpr(val, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002246
2247 // orderexpr made sure key and val are addressable.
2248 key = Nod(OADDR, key, nil)
2249
2250 val = Nod(OADDR, val, nil)
2251 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2252 goto out
2253 }
2254
2255 if !Eqtype(lt, rt) {
2256 n.Right = assignconv(n.Right, lt, "assignment")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002257 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002258 }
2259
2260out:
2261 ullmancalc(n)
2262 return n
2263}
2264
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002265// from ascompat[te]
2266// evaluating actual function arguments.
2267// f(a,b)
2268// if there is exactly one function expr,
2269// then it is done first. otherwise must
2270// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002271func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002272 c := 0 // function calls
2273 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002274
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002275 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002276 t++
2277 ullmancalc(n)
2278 if n.Ullman >= UINF {
2279 c++
2280 }
2281 }
2282
2283 if c == 0 || t == 1 {
2284 return all
2285 }
2286
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002287 var g []*Node // fncalls assigned to tempnames
2288 var f *Node // last fncall assigned to stack
2289 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002290 d := 0
2291 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002292 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002293 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002294 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002295 continue
2296 }
2297
2298 d++
2299 if d == c {
2300 f = n
2301 continue
2302 }
2303
2304 // make assignment of fncall to tempname
2305 a = temp(n.Right.Type)
2306
2307 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002308 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002309
2310 // put normal arg assignment on list
2311 // with fncall replaced by tempname
2312 n.Right = a.Left
2313
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002314 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002315 }
2316
2317 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002318 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002319 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002320 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002321}
2322
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002323// from ascompat[ee]
2324// a,b = c,d
2325// simultaneous assignment. there cannot
2326// be later use of an earlier lvalue.
2327//
2328// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002329func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002330 var l *Node
2331
2332 // If a needed expression may be affected by an
2333 // earlier assignment, make an early copy of that
2334 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002335 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002336
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002337 var mapinit Nodes
2338 for i, n := range all {
2339 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002340
2341 // Save subexpressions needed on left side.
2342 // Drill through non-dereferences.
2343 for {
2344 if l.Op == ODOT || l.Op == OPAREN {
2345 l = l.Left
2346 continue
2347 }
2348
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002349 if l.Op == OINDEX && l.Left.Type.IsArray() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002350 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002351 l = l.Left
2352 continue
2353 }
2354
2355 break
2356 }
2357
2358 switch l.Op {
2359 default:
Dave Cheney733f8352016-04-27 19:34:17 +10002360 Fatalf("reorder3 unexpected lvalue %#v", l.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05002361
2362 case ONAME:
2363 break
2364
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002365 case OINDEX, OINDEXMAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002366 l.Left = reorder3save(l.Left, all, i, &early)
2367 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002368 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002369 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002370 }
2371
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002372 case OIND, ODOTPTR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002373 l.Left = reorder3save(l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002374 }
2375
2376 // Save expression on right side.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002377 all[i].Right = reorder3save(all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002378 }
2379
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002380 early = append(mapinit.Slice(), early...)
2381 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002382}
2383
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002384// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002385// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002386// copy into a temporary during *early and
2387// replace *np with that temp.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002388// The result of reorder3save MUST be assigned back to n, e.g.
2389// n.Left = reorder3save(n.Left, all, i, early)
2390func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002391 if !aliased(n, all, i) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002392 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002393 }
2394
Russ Cox382b44e2015-02-23 16:07:24 -05002395 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002396 q = Nod(OAS, q, n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002397 q = typecheck(q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002398 *early = append(*early, q)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002399 return q.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002400}
2401
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002402// what's the outer value that a write to n affects?
2403// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002404func outervalue(n *Node) *Node {
2405 for {
2406 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002407 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002408 }
2409 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2410 n = n.Left
2411 continue
2412 }
2413
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002414 if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002415 n = n.Left
2416 continue
2417 }
2418
2419 break
2420 }
2421
2422 return n
2423}
2424
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002425// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002426// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002427func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002428 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002429 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002430 }
2431
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002432 // Treat all fields of a struct as referring to the whole struct.
2433 // We could do better but we would have to keep track of the fields.
2434 for n.Op == ODOT {
2435 n = n.Left
2436 }
2437
Russ Cox8c195bd2015-02-13 14:40:36 -05002438 // Look for obvious aliasing: a variable being assigned
2439 // during the all list and appearing in n.
2440 // Also record whether there are any writes to main memory.
2441 // Also record whether there are any writes to variables
2442 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002443 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002444
Russ Cox382b44e2015-02-23 16:07:24 -05002445 varwrite := 0
2446 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002447 for _, an := range all[:i] {
2448 a = outervalue(an.Left)
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002449
2450 for a.Op == ODOT {
2451 a = a.Left
2452 }
2453
Russ Cox8c195bd2015-02-13 14:40:36 -05002454 if a.Op != ONAME {
2455 memwrite = 1
2456 continue
2457 }
2458
2459 switch n.Class {
2460 default:
2461 varwrite = 1
2462 continue
2463
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002464 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002465 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002466 varwrite = 1
2467 continue
2468 }
2469
Russ Coxdc7b54b2015-02-17 22:13:49 -05002470 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002471 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002472 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002473 }
2474 }
2475 }
2476
2477 // The variables being written do not appear in n.
2478 // However, n might refer to computed addresses
2479 // that are being written.
2480
2481 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002482 if memwrite == 0 && varwrite == 0 {
2483 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002484 }
2485
2486 // If n does not refer to computed addresses
2487 // (that is, if n only refers to variables whose addresses
2488 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002489 if varexpr(n) {
2490 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002491 }
2492
2493 // Otherwise, both the writes and n refer to computed memory addresses.
2494 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002495 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002496}
2497
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002498// does the evaluation of n only refer to variables
2499// whose addresses have not been taken?
2500// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002501func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002502 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002503 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002504 }
2505
2506 switch n.Op {
2507 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002508 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002509
2510 case ONAME:
2511 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002512 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002513 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002514 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002515 }
2516 }
2517
Russ Coxdc7b54b2015-02-17 22:13:49 -05002518 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002519
2520 case OADD,
2521 OSUB,
2522 OOR,
2523 OXOR,
2524 OMUL,
2525 ODIV,
2526 OMOD,
2527 OLSH,
2528 ORSH,
2529 OAND,
2530 OANDNOT,
2531 OPLUS,
2532 OMINUS,
2533 OCOM,
2534 OPAREN,
2535 OANDAND,
2536 OOROR,
Russ Cox8c195bd2015-02-13 14:40:36 -05002537 OCONV,
2538 OCONVNOP,
2539 OCONVIFACE,
2540 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002541 return varexpr(n.Left) && varexpr(n.Right)
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002542
2543 case ODOT: // but not ODOTPTR
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002544 // Should have been handled in aliased.
2545 Fatalf("varexpr unexpected ODOT")
Russ Cox8c195bd2015-02-13 14:40:36 -05002546 }
2547
2548 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002549 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002550}
2551
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002552// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002553func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002554 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002555 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002556 }
2557 switch r.Op {
2558 // match each right given left
2559 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002560 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002561
2562 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002563 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002564 }
2565
Russ Coxdc7b54b2015-02-17 22:13:49 -05002566 if vmatch2(l, r.Left) {
2567 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002568 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002569 if vmatch2(l, r.Right) {
2570 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002571 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002572 for _, n := range r.List.Slice() {
2573 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002574 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002575 }
2576 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002577 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002578}
2579
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002580// is any name mentioned in l also mentioned in r?
2581// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002582func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002583 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002585 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002586 }
2587 switch l.Op {
2588 case ONAME:
2589 switch l.Class {
Russ Cox20803b82016-05-25 10:29:50 -04002590 case PPARAM, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002591 break
2592
2593 // assignment to non-stack variable
2594 // must be delayed if right has function calls.
2595 default:
2596 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002597 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002598 }
2599 }
2600
2601 return vmatch2(l, r)
2602
2603 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002604 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002605 }
2606
Russ Coxdc7b54b2015-02-17 22:13:49 -05002607 if vmatch1(l.Left, r) {
2608 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002609 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002610 if vmatch1(l.Right, r) {
2611 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002612 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002613 for _, n := range l.List.Slice() {
2614 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002615 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002616 }
2617 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002618 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002619}
2620
Matthew Dempsky2339b132016-03-09 18:54:26 -08002621// paramstoheap returns code to allocate memory for heap-escaped parameters
2622// and to copy non-result prameters' values from the stack.
2623// If out is true, then code is also produced to zero-initialize their
2624// stack memory addresses.
Russ Coxdec1bae2016-05-25 10:01:58 -04002625func paramstoheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002626 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002627 for _, t := range params.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002628 // For precise stacks, the garbage collector assumes results
2629 // are always live, so zero them always.
Russ Coxdec1bae2016-05-25 10:01:58 -04002630 if params.StructType().Funarg == FunargResults {
Russ Cox8c195bd2015-02-13 14:40:36 -05002631 // Defer might stop a panic and show the
2632 // return values as they exist at the time of panic.
2633 // Make sure to zero them on entry to the function.
Russ Coxdec1bae2016-05-25 10:01:58 -04002634 nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002635 }
2636
Russ Coxb6dc3e62016-05-25 01:33:24 -04002637 v := t.Nname
2638 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
2639 v = nil
2640 }
2641 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002642 continue
2643 }
2644
Russ Coxb6dc3e62016-05-25 01:33:24 -04002645 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
2646 nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
2647 if stackcopy.Class == PPARAM {
2648 nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
2649 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002650 }
2651 }
2652
2653 return nn
2654}
2655
Matthew Dempsky2339b132016-03-09 18:54:26 -08002656// returnsfromheap returns code to copy values for heap-escaped parameters
2657// back to the stack.
2658func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002659 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002660 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002661 v := t.Nname
Russ Coxb6dc3e62016-05-25 01:33:24 -04002662 if v == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05002663 continue
2664 }
Russ Coxb6dc3e62016-05-25 01:33:24 -04002665 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
2666 nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
2667 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002668 }
2669
2670 return nn
2671}
2672
Matthew Dempsky2339b132016-03-09 18:54:26 -08002673// heapmoves generates code to handle migrating heap-escaped parameters
2674// between the stack and the heap. The generated code is added to Curfn's
2675// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002676func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002677 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002678 lineno = Curfn.Lineno
Russ Coxdec1bae2016-05-25 10:01:58 -04002679 nn := paramstoheap(Curfn.Type.Recvs())
2680 nn = append(nn, paramstoheap(Curfn.Type.Params())...)
2681 nn = append(nn, paramstoheap(Curfn.Type.Results())...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002682 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002683 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002684 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002685 lineno = lno
2686}
2687
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002688func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002689 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002690 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002691 }
2692
Matthew Dempskyc8377612016-03-17 01:47:16 -07002693 n := fn.Type.Params().NumFields()
Russ Cox8c195bd2015-02-13 14:40:36 -05002694
Russ Cox382b44e2015-02-23 16:07:24 -05002695 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002696 r.List.Set(va[:n])
Matthew Dempskyc8377612016-03-17 01:47:16 -07002697 if fn.Type.Results().NumFields() > 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002698 r = typecheck(r, Erv|Efnstruct)
Russ Cox8c195bd2015-02-13 14:40:36 -05002699 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002700 r = typecheck(r, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002701 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002702 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002703 r.Type = t
2704 return r
2705}
2706
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002707func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002708 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002709}
2710
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002711func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002712 return vmkcall(fn, t, init, args)
2713}
2714
2715func conv(n *Node, t *Type) *Node {
2716 if Eqtype(n.Type, t) {
2717 return n
2718 }
2719 n = Nod(OCONV, n, nil)
2720 n.Type = t
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002721 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05002722 return n
2723}
2724
2725func chanfn(name string, n int, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002726 if !t.IsChan() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002727 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002728 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002729 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002730 switch n {
2731 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002732 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002733 case 1:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002734 fn = substArgTypes(fn, t.Elem())
Russ Cox13f9c8b2015-03-08 13:33:49 -04002735 case 2:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002736 fn = substArgTypes(fn, t.Elem(), t.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002737 }
2738 return fn
2739}
2740
2741func mapfn(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002742 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002743 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002744 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002745 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002746 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05002747 return fn
2748}
2749
2750func mapfndel(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002751 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002752 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002753 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002754 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002755 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002756 return fn
2757}
2758
2759func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002760 fn := syslook(name)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002761 fn = substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002762 return fn
2763}
2764
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002765func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002766 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002767 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002768
2769 if c < 2 {
2770 Yyerror("addstr count %d too small", c)
2771 }
2772
Russ Cox382b44e2015-02-23 16:07:24 -05002773 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002774 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002775 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002776 for _, n1 := range n.List.Slice() {
2777 if n1.Op == OLITERAL {
2778 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002779 }
2780 }
2781
2782 // Don't allocate the buffer if the result won't fit.
2783 if sz < tmpstringbufsize {
2784 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002785 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002786
2787 buf = Nod(OADDR, temp(t), nil)
2788 }
2789 }
2790
2791 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002792 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002793 for _, n2 := range n.List.Slice() {
2794 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002795 }
2796
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002797 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002798 if c <= 5 {
2799 // small numbers of strings use direct runtime helpers.
2800 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002801 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002802 } else {
2803 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002804 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002805
Josh Bleecher Snydereb98e512016-03-28 22:57:57 -07002806 t := typSlice(Types[TSTRING])
Russ Cox382b44e2015-02-23 16:07:24 -05002807 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002808 if prealloc[n] != nil {
2809 prealloc[slice] = prealloc[n]
2810 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002811 slice.List.Set(args[1:]) // skip buf arg
Keith Randall934c3592016-04-23 22:59:01 -07002812 args = []*Node{buf, slice}
Russ Cox8c195bd2015-02-13 14:40:36 -05002813 slice.Esc = EscNone
2814 }
2815
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002816 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002817 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002818 r.List.Set(args)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002819 r = typecheck(r, Erv)
2820 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002821 r.Type = n.Type
2822
2823 return r
2824}
2825
2826// expand append(l1, l2...) to
2827// init {
2828// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002829// n := len(s) + len(l2)
2830// // Compare as uint so growslice can panic on overflow.
2831// if uint(n) > uint(cap(s)) {
2832// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002833// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002834// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002835// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2836// }
2837// s
2838//
2839// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002840func appendslice(n *Node, init *Nodes) *Node {
2841 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002842
2843 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2844 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002845 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002846 ls := n.List.Slice()
2847 for i1, n1 := range ls {
2848 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002849 }
2850
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002851 l1 := n.List.First()
2852 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002853
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002854 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002855
2856 // var s []T
2857 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002858 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002859
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002860 // n := len(s) + len(l2)
2861 nn := temp(Types[TINT])
2862 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002863
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002864 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002865 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002866 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2867 nif.Left.Left.Type = Types[TUINT]
2868 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002869
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002870 // instantiate growslice(Type*, []any, int) []any
2871 fn := syslook("growslice")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002872 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002873
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002874 // s = growslice(T, s, n)
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002875 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 -08002876 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002877
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002878 // s = s[:n]
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002879 nt := Nod(OSLICE, s, nil)
2880 nt.SetSliceBounds(nil, nn, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002881 nt.Etype = 1
2882 l = append(l, Nod(OAS, s, nt))
2883
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002884 if haspointers(l1.Type.Elem()) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002885 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002886 nptr1 := Nod(OSLICE, s, nil)
2887 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002888 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002889 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002890 fn := syslook("typedslicecopy")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002891 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002892 var ln Nodes
2893 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002894 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002895 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002896 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002897 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002898 // copy(s[len(l1):], l2)
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07002899 nptr1 := Nod(OSLICE, s, nil)
2900 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002901 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002902 nptr2 := l2
2903 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002904 if l2.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002905 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002906 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002907 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002908 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002909 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002910 var ln Nodes
2911 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002912 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002913 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002914 } else {
2915 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002916 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002917 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002918
Russ Cox8c195bd2015-02-13 14:40:36 -05002919 nptr1 = Nod(OADDR, nptr1, nil)
2920
Russ Cox382b44e2015-02-23 16:07:24 -05002921 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002922
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002923 fn := syslook("memmove")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002924 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002925
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002926 var ln Nodes
2927 ln.Set(l)
2928 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002929
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002930 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002931 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2932 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002933 }
2934
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002935 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002936 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002937 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002938 return s
2939}
2940
Russ Cox85520472015-05-06 12:34:30 -04002941// Rewrite append(src, x, y, z) so that any side effects in
2942// x, y, z (including runtime panics) are evaluated in
2943// initialization statements before the append.
2944// For normal code generation, stop there and leave the
2945// rest to cgen_append.
2946//
2947// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002948//
2949// init {
2950// s := src
2951// const argc = len(args) - 1
2952// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002953// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002954// }
2955// n := len(s)
2956// s = s[:n+argc]
2957// s[n] = a
2958// s[n+1] = b
2959// ...
2960// }
2961// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002962func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002963 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002964 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002965 n.List.SetIndex(0, walkexpr(n.List.Index(0), init))
Russ Cox85520472015-05-06 12:34:30 -04002966 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002967 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002968
2969 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2970 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002971 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002972 // Using cheapexpr also makes sure that the evaluation
2973 // of all arguments (and especially any panics) happen
2974 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002975 ls := n.List.Slice()[1:]
2976 for i, n := range ls {
2977 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002978 }
2979
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002980 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002981
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002982 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002983 if argc < 1 {
2984 return nsrc
2985 }
2986
Russ Cox85520472015-05-06 12:34:30 -04002987 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002988 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002989 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002990 return n
2991 }
2992
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002993 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002994
Russ Cox382b44e2015-02-23 16:07:24 -05002995 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002996 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002997
Russ Cox382b44e2015-02-23 16:07:24 -05002998 na := Nodintconst(int64(argc)) // const argc
2999 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04003000 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05003001
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003002 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003003 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05003004
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003005 nx.Nbody.Set1(Nod(OAS, ns,
Keith Randallbfe0cbd2016-04-19 15:38:59 -07003006 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003007 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05003008
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003009 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05003010
Russ Cox382b44e2015-02-23 16:07:24 -05003011 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003012 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05003013
Josh Bleecher Snyderf12bd8a2016-04-21 11:55:33 -07003014 nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
3015 nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003016 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003017 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05003018
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003019 ls = n.List.Slice()[1:]
3020 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05003021 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05003022 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08003023 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
3024 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003025 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05003026 }
3027 }
3028
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003029 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003030 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003031 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003032 return ns
3033}
3034
3035// Lower copy(a, b) to a memmove call or a runtime call.
3036//
3037// init {
3038// n := len(a)
3039// if n > len(b) { n = len(b) }
3040// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
3041// }
3042// n;
3043//
3044// Also works if b is a string.
3045//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003046func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003047 if haspointers(n.Left.Type.Elem()) {
Russ Cox382b44e2015-02-23 16:07:24 -05003048 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003049 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05003050 }
3051
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07003052 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05003053 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003054 if n.Right.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003055 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003056 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003057 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05003058 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003059 fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003060 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003061 }
3062
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003063 n.Left = walkexpr(n.Left, init)
3064 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003065 nl := temp(n.Left.Type)
3066 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003067 var l []*Node
3068 l = append(l, Nod(OAS, nl, n.Left))
3069 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003070
Russ Cox382b44e2015-02-23 16:07:24 -05003071 nfrm := Nod(OSPTR, nr, nil)
3072 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003073
Russ Cox382b44e2015-02-23 16:07:24 -05003074 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003075
3076 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003077 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003078
3079 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003080 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003081
Russ Cox66be1482015-05-26 21:30:20 -04003082 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003083 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003084 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003085
3086 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003087 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003088
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003089 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
Russ Cox382b44e2015-02-23 16:07:24 -05003090 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003091 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003092 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003093 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003094
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003095 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003096 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003097 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003098 return nlen
3099}
3100
Russ Cox8c195bd2015-02-13 14:40:36 -05003101func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003102 // Should only arrive here with large memory or
3103 // a struct/array containing a non-memory field/element.
3104 // Small memory is handled inline, and single non-memory
3105 // is handled during type check (OCMPSTR etc).
Matthew Dempsky077902d2016-04-01 11:22:03 -07003106 switch a, _ := algtype1(t); a {
3107 case AMEM:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003108 n := syslook("memequal")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003109 n = substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003110 *needsize = 1
3111 return n
Matthew Dempsky077902d2016-04-01 11:22:03 -07003112 case ASPECIAL:
3113 sym := typesymprefix(".eq", t)
3114 n := newname(sym)
3115 n.Class = PFUNC
3116 ntype := Nod(OTFUNC, nil, nil)
3117 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3118 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3119 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3120 ntype = typecheck(ntype, Etype)
3121 n.Type = ntype.Type
3122 *needsize = 0
3123 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003124 }
Matthew Dempsky077902d2016-04-01 11:22:03 -07003125 Fatalf("eqfor %v", t)
3126 return nil
Russ Cox8c195bd2015-02-13 14:40:36 -05003127}
3128
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003129// The result of walkcompare MUST be assigned back to n, e.g.
3130// n.Left = walkcompare(n.Left, init)
3131func walkcompare(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003132 // Given interface value l and concrete value r, rewrite
3133 // l == r
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003134 // into types-equal && data-equal.
3135 // This is efficient, avoids allocations, and avoids runtime calls.
3136 var l, r *Node
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003137 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003138 l = n.Left
3139 r = n.Right
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003140 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003141 l = n.Right
3142 r = n.Left
3143 }
3144
3145 if l != nil {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003146 // Handle both == and !=.
3147 eq := n.Op
3148 var andor Op
3149 if eq == OEQ {
3150 andor = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003151 } else {
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003152 andor = OOROR
Russ Cox8c195bd2015-02-13 14:40:36 -05003153 }
Josh Bleecher Snyder1a7fc7b2016-06-06 13:01:48 -07003154 // Check for types equal.
3155 // For empty interface, this is:
3156 // l.tab == type(r)
3157 // For non-empty interface, this is:
3158 // l.tab != nil && l.tab._type == type(r)
3159 var eqtype *Node
3160 tab := Nod(OITAB, l, nil)
3161 rtyp := typename(r.Type)
3162 if l.Type.IsEmptyInterface() {
3163 tab.Type = Ptrto(Types[TUINT8])
3164 tab.Typecheck = 1
3165 eqtype = Nod(eq, tab, rtyp)
3166 } else {
3167 nonnil := Nod(Brcom(eq), nodnil(), tab)
3168 match := Nod(eq, itabType(tab), rtyp)
3169 eqtype = Nod(andor, nonnil, match)
3170 }
3171 // Check for data equal.
3172 eqdata := Nod(eq, ifaceData(l, r.Type), r)
3173 // Put it all together.
3174 expr := Nod(andor, eqtype, eqdata)
3175 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003176 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003177 }
3178
3179 // Must be comparison of array or struct.
3180 // Otherwise back end handles it.
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003181 // While we're here, decide whether to
3182 // inline or call an eq alg.
Russ Cox44928112015-03-02 20:34:22 -05003183 t := n.Left.Type
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003184 var inline bool
Russ Cox8c195bd2015-02-13 14:40:36 -05003185 switch t.Etype {
3186 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003187 return n
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003188 case TARRAY:
3189 inline = t.NumElem() <= 1 || (t.NumElem() <= 4 && issimple[t.Elem().Etype])
3190 case TSTRUCT:
3191 inline = t.NumFields() <= 4
Russ Cox8c195bd2015-02-13 14:40:36 -05003192 }
3193
Russ Cox44928112015-03-02 20:34:22 -05003194 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003195 for cmpl != nil && cmpl.Op == OCONVNOP {
3196 cmpl = cmpl.Left
3197 }
Russ Cox44928112015-03-02 20:34:22 -05003198 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003199 for cmpr != nil && cmpr.Op == OCONVNOP {
3200 cmpr = cmpr.Left
3201 }
3202
Russ Coxdc7b54b2015-02-17 22:13:49 -05003203 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003204 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003205 }
3206
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003207 // Chose not to inline. Call equality function directly.
3208 if !inline {
3209 // eq algs take pointers
3210 pl := temp(Ptrto(t))
3211 al := Nod(OAS, pl, Nod(OADDR, cmpl, nil))
3212 al.Right.Etype = 1 // addr does not escape
3213 al = typecheck(al, Etop)
3214 init.Append(al)
Russ Cox8c195bd2015-02-13 14:40:36 -05003215
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003216 pr := temp(Ptrto(t))
3217 ar := Nod(OAS, pr, Nod(OADDR, cmpr, nil))
3218 ar.Right.Etype = 1 // addr does not escape
3219 ar = typecheck(ar, Etop)
3220 init.Append(ar)
Russ Cox8c195bd2015-02-13 14:40:36 -05003221
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003222 var needsize int
3223 call := Nod(OCALL, eqfor(t, &needsize), nil)
3224 call.List.Append(pl)
3225 call.List.Append(pr)
3226 if needsize != 0 {
3227 call.List.Append(Nodintconst(t.Width))
3228 }
3229 res := call
3230 if n.Op != OEQ {
3231 res = Nod(ONOT, res, nil)
3232 }
3233 n = finishcompare(n, res, init)
3234 return n
3235 }
3236
3237 // inline: build boolean expression comparing element by element
3238 andor := OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003239 if n.Op == ONE {
3240 andor = OOROR
3241 }
Russ Cox44928112015-03-02 20:34:22 -05003242 var expr *Node
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003243 compare := func(el, er *Node) {
3244 a := Nod(n.Op, el, er)
Russ Cox8c195bd2015-02-13 14:40:36 -05003245 if expr == nil {
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003246 expr = a
3247 } else {
3248 expr = Nod(andor, expr, a)
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003249 }
3250 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003251 cmpl = safeexpr(cmpl, init)
3252 cmpr = safeexpr(cmpr, init)
3253 if t.IsStruct() {
3254 for _, f := range t.Fields().Slice() {
3255 sym := f.Sym
3256 if isblanksym(sym) {
Russ Cox8c195bd2015-02-13 14:40:36 -05003257 continue
3258 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003259 compare(
3260 NodSym(OXDOT, cmpl, sym),
3261 NodSym(OXDOT, cmpr, sym),
3262 )
Russ Cox8c195bd2015-02-13 14:40:36 -05003263 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003264 } else {
3265 for i := 0; int64(i) < t.NumElem(); i++ {
3266 compare(
3267 Nod(OINDEX, cmpl, Nodintconst(int64(i))),
3268 Nod(OINDEX, cmpr, Nodintconst(int64(i))),
3269 )
Russ Cox8c195bd2015-02-13 14:40:36 -05003270 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003271 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003272 if expr == nil {
3273 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003274 }
Josh Bleecher Snyder0bc94a82016-04-15 15:49:00 -07003275 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003276 return n
Russ Cox44928112015-03-02 20:34:22 -05003277}
3278
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003279// The result of finishcompare MUST be assigned back to n, e.g.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003280// n.Left = finishcompare(n.Left, x, r, init)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003281func finishcompare(n, r *Node, init *Nodes) *Node {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003282 // Use nn here to avoid passing r to typecheck.
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003283 nn := r
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003284 nn = typecheck(nn, Erv)
3285 nn = walkexpr(nn, init)
3286 r = nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003287 if r.Type != n.Type {
3288 r = Nod(OCONVNOP, r, nil)
3289 r.Type = n.Type
3290 r.Typecheck = 1
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003291 nn = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003292 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003293 return nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003294}
3295
Russ Coxdc7b54b2015-02-17 22:13:49 -05003296func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003297 var ar *Node
3298 var br *Node
3299 for a != nil && b != nil && a.Op == b.Op {
3300 switch a.Op {
3301 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003302 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003303
3304 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003305 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003306
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003307 case ODOT, ODOTPTR:
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003308 if a.Sym != b.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003309 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003310 }
3311
3312 case OINDEX:
3313 ar = a.Right
3314 br = b.Right
Matthew Dempskyd3253872016-03-20 13:55:42 -07003315 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003316 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003317 }
3318 }
3319
3320 a = a.Left
3321 b = b.Left
3322 }
3323
Russ Coxdc7b54b2015-02-17 22:13:49 -05003324 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003325}
3326
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003327// The result of walkrotate MUST be assigned back to n, e.g.
3328// n.Left = walkrotate(n.Left)
3329func walkrotate(n *Node) *Node {
Cherry Zhangd99cee72016-08-10 13:24:03 -04003330 //TODO: enable LROT on ARM64 once the old backend is gone
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07003331 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003332 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003333 }
3334
Russ Cox8c195bd2015-02-13 14:40:36 -05003335 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003336 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003337
Russ Cox382b44e2015-02-23 16:07:24 -05003338 r := n.Right
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003339 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 -07003340 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003341 }
3342
3343 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003344 if !samecheap(l.Left, r.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003345 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003346 }
3347
3348 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003349 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003350
Michael Munday613ba6c2016-04-12 12:26:17 -04003351 if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
3352 // only supports 32-bit and 64-bit rotates
3353 return n
3354 }
3355
Russ Coxdc7b54b2015-02-17 22:13:49 -05003356 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003357 sl := int(l.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003358 if sl >= 0 {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003359 sr := int(r.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003360 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003361 // Rewrite left shift half to left rotate.
3362 if l.Op == OLSH {
3363 n = l
3364 } else {
3365 n = r
3366 }
3367 n.Op = OLROT
3368
3369 // Remove rotate 0 and rotate w.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003370 s := int(n.Right.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003371
3372 if s == 0 || s == w {
3373 n = n.Left
3374 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003375 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003376 }
3377 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003378 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003379 }
3380
3381 // 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 -07003382 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003383}
3384
Josh Bleecher Snyder62861882016-05-26 18:08:24 -07003385// isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers.
3386func (n *Node) isIntOrdering() bool {
3387 switch n.Op {
3388 case OLE, OLT, OGE, OGT:
3389 default:
3390 return false
3391 }
3392 return n.Left.Type.IsInteger() && n.Right.Type.IsInteger()
3393}
3394
3395// walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10.
3396// n must be an OANDAND or OOROR node.
3397// The result of walkinrange MUST be assigned back to n, e.g.
3398// n.Left = walkinrange(n.Left)
3399func walkinrange(n *Node, init *Nodes) *Node {
3400 // We are looking for something equivalent to a opl b OP b opr c, where:
3401 // * a, b, and c have integer type
3402 // * b is side-effect-free
3403 // * opl and opr are each < or ≤
3404 // * OP is &&
3405 l := n.Left
3406 r := n.Right
3407 if !l.isIntOrdering() || !r.isIntOrdering() {
3408 return n
3409 }
3410
3411 // Find b, if it exists, and rename appropriately.
3412 // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right
3413 // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c
3414 a, opl, b := l.Left, l.Op, l.Right
3415 x, opr, c := r.Left, r.Op, r.Right
3416 for i := 0; ; i++ {
3417 if samesafeexpr(b, x) {
3418 break
3419 }
3420 if i == 3 {
3421 // Tried all permutations and couldn't find an appropriate b == x.
3422 return n
3423 }
3424 if i&1 == 0 {
3425 a, opl, b = b, Brrev(opl), a
3426 } else {
3427 x, opr, c = c, Brrev(opr), x
3428 }
3429 }
3430
3431 // If n.Op is ||, apply de Morgan.
3432 // Negate the internal ops now; we'll negate the top level op at the end.
3433 // Henceforth assume &&.
3434 negateResult := n.Op == OOROR
3435 if negateResult {
3436 opl = Brcom(opl)
3437 opr = Brcom(opr)
3438 }
3439
3440 cmpdir := func(o Op) int {
3441 switch o {
3442 case OLE, OLT:
3443 return -1
3444 case OGE, OGT:
3445 return +1
3446 }
3447 Fatalf("walkinrange cmpdir %v", o)
3448 return 0
3449 }
3450 if cmpdir(opl) != cmpdir(opr) {
3451 // Not a range check; something like b < a && b < c.
3452 return n
3453 }
3454
3455 switch opl {
3456 case OGE, OGT:
3457 // We have something like a > b && b ≥ c.
3458 // Switch and reverse ops and rename constants,
3459 // to make it look like a ≤ b && b < c.
3460 a, c = c, a
3461 opl, opr = Brrev(opr), Brrev(opl)
3462 }
3463
3464 // We must ensure that c-a is non-negative.
3465 // For now, require a and c to be constants.
3466 // In the future, we could also support a == 0 and c == len/cap(...).
3467 // Unfortunately, by this point, most len/cap expressions have been
3468 // stored into temporary variables.
3469 if !Isconst(a, CTINT) || !Isconst(c, CTINT) {
3470 return n
3471 }
3472
3473 if opl == OLT {
3474 // We have a < b && ...
3475 // We need a ≤ b && ... to safely use unsigned comparison tricks.
3476 // If a is not the maximum constant for b's type,
3477 // we can increment a and switch to ≤.
3478 if a.Int64() >= Maxintval[b.Type.Etype].Int64() {
3479 return n
3480 }
3481 a = Nodintconst(a.Int64() + 1)
3482 opl = OLE
3483 }
3484
3485 bound := c.Int64() - a.Int64()
3486 if bound < 0 {
3487 // Bad news. Something like 5 <= x && x < 3.
3488 // Rare in practice, and we still need to generate side-effects,
3489 // so just leave it alone.
3490 return n
3491 }
3492
3493 // We have a ≤ b && b < c (or a ≤ b && b ≤ c).
3494 // This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a),
3495 // which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a),
3496 // which is equivalent to uint(b-a) < uint(c-a).
3497 ut := b.Type.toUnsigned()
3498 lhs := conv(Nod(OSUB, b, a), ut)
3499 rhs := Nodintconst(bound)
3500 if negateResult {
3501 // Negate top level.
3502 opr = Brcom(opr)
3503 }
3504 cmp := Nod(opr, lhs, rhs)
3505 cmp.Lineno = n.Lineno
3506 cmp = addinit(cmp, l.Ninit.Slice())
3507 cmp = addinit(cmp, r.Ninit.Slice())
3508 cmp = typecheck(cmp, Erv)
3509 cmp = walkexpr(cmp, init)
3510 return cmp
3511}
3512
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003513// walkmul rewrites integer multiplication by powers of two as shifts.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003514// The result of walkmul MUST be assigned back to n, e.g.
3515// n.Left = walkmul(n.Left, init)
3516func walkmul(n *Node, init *Nodes) *Node {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003517 if !n.Type.IsInteger() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003518 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003519 }
3520
Russ Cox382b44e2015-02-23 16:07:24 -05003521 var nr *Node
3522 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003523 if n.Right.Op == OLITERAL {
3524 nl = n.Left
3525 nr = n.Right
3526 } else if n.Left.Op == OLITERAL {
3527 nl = n.Right
3528 nr = n.Left
3529 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003530 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003531 }
3532
Russ Cox382b44e2015-02-23 16:07:24 -05003533 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003534
3535 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003536 var pow int
3537 var w int
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003538 if nr.Int64() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003539 cheapexpr(nl, init)
3540 Nodconst(n, n.Type, 0)
3541 goto ret
3542 }
3543
3544 // nr is a constant.
3545 pow = powtwo(nr)
3546
3547 if pow < 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003548 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003549 }
3550 if pow >= 1000 {
3551 // negative power of 2, like -16
3552 neg = 1
3553
3554 pow -= 1000
3555 }
3556
3557 w = int(nl.Type.Width * 8)
3558 if pow+1 >= w { // too big, shouldn't happen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003559 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003560 }
3561
3562 nl = cheapexpr(nl, init)
3563
3564 if pow == 0 {
3565 // x*1 is x
3566 n = nl
3567
3568 goto ret
3569 }
3570
3571 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3572
3573ret:
3574 if neg != 0 {
3575 n = Nod(OMINUS, n, nil)
3576 }
3577
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003578 n = typecheck(n, Erv)
3579 n = walkexpr(n, init)
3580 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003581}
3582
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003583// walkdiv rewrites division by a constant as less expensive
3584// operations.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003585// The result of walkdiv MUST be assigned back to n, e.g.
3586// n.Left = walkdiv(n.Left, init)
3587func walkdiv(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003588 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003589
3590 // TODO(minux)
Zhongwei Yao74a9bad2016-04-25 11:08:38 +08003591 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003592 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003593 }
3594
Russ Cox8c195bd2015-02-13 14:40:36 -05003595 if n.Right.Op != OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003596 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003597 }
3598
3599 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003600 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003601
Russ Cox382b44e2015-02-23 16:07:24 -05003602 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003603
3604 // special cases of mod/div
3605 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003606 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003607
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003608 s := 0 // 1 if nr is negative.
3609 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003610 if pow >= 1000 {
3611 // negative power of 2
3612 s = 1
3613
3614 pow -= 1000
3615 }
3616
3617 if pow+1 >= w {
3618 // divisor too large.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003619 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003620 }
3621
3622 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003623 // try to do division by multiply by (2^w)/d
3624 // see hacker's delight chapter 10
3625 // TODO: support 64-bit magic multiply here.
3626 var m Magic
3627 m.W = w
3628
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003629 if nl.Type.IsSigned() {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003630 m.Sd = nr.Int64()
Russ Cox79f727a2015-03-02 12:35:15 -05003631 Smagic(&m)
3632 } else {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003633 m.Ud = uint64(nr.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003634 Umagic(&m)
3635 }
3636
3637 if m.Bad != 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003638 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003639 }
3640
3641 // We have a quick division method so use it
3642 // for modulo too.
3643 if n.Op == OMOD {
3644 // rewrite as A%B = A - (A/B*B).
3645 n1 := Nod(ODIV, nl, nr)
3646
3647 n2 := Nod(OMUL, n1, nr)
3648 n = Nod(OSUB, nl, n2)
3649 goto ret
3650 }
3651
3652 switch Simtype[nl.Type.Etype] {
3653 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003654 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003655
3656 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003657 case TUINT8, TUINT16, TUINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003658 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003659
Dave Cheneya4be24c2016-03-23 13:27:49 +11003660 Nodconst(&nc, nl.Type, int64(m.Um))
3661 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003662 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003663 if m.Ua != 0 {
3664 // Select a Go type with (at least) twice the width.
3665 var twide *Type
3666 switch Simtype[nl.Type.Etype] {
3667 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003668 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003669
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003670 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003671 twide = Types[TUINT32]
3672
3673 case TUINT32:
3674 twide = Types[TUINT64]
3675
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003676 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003677 twide = Types[TINT32]
3678
3679 case TINT32:
3680 twide = Types[TINT64]
3681 }
3682
3683 // add numerator (might overflow).
3684 // n2 = (n1 + nl)
3685 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3686
3687 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003688 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003689
Dave Cheneya4be24c2016-03-23 13:27:49 +11003690 Nodconst(&nc, Types[TUINT], int64(m.S))
3691 n = conv(Nod(ORSH, n2, &nc), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003692 } else {
3693 // n = n1 >> m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003694 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003695
Dave Cheneya4be24c2016-03-23 13:27:49 +11003696 Nodconst(&nc, Types[TUINT], int64(m.S))
3697 n = Nod(ORSH, n1, &nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003698 }
3699
3700 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003701 case TINT8, TINT16, TINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003702 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003703
Dave Cheneya4be24c2016-03-23 13:27:49 +11003704 Nodconst(&nc, nl.Type, m.Sm)
3705 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003706 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003707 if m.Sm < 0 {
3708 // add the numerator.
3709 n1 = Nod(OADD, n1, nl)
3710 }
3711
3712 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003713 var ns Node
Russ Cox79f727a2015-03-02 12:35:15 -05003714
Dave Cheneya4be24c2016-03-23 13:27:49 +11003715 Nodconst(&ns, Types[TUINT], int64(m.S))
3716 n2 := conv(Nod(ORSH, n1, &ns), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003717
3718 // add 1 iff n1 is negative.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003719 var nneg Node
Russ Cox79f727a2015-03-02 12:35:15 -05003720
Dave Cheneya4be24c2016-03-23 13:27:49 +11003721 Nodconst(&nneg, Types[TUINT], int64(w)-1)
3722 n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative.
Russ Cox79f727a2015-03-02 12:35:15 -05003723 n = Nod(OSUB, n2, n3)
3724
3725 // apply sign.
3726 if m.Sd < 0 {
3727 n = Nod(OMINUS, n, nil)
3728 }
3729 }
3730
3731 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003732 }
3733
3734 switch pow {
3735 case 0:
3736 if n.Op == OMOD {
3737 // nl % 1 is zero.
3738 Nodconst(n, n.Type, 0)
3739 } else if s != 0 {
3740 // divide by -1
3741 n.Op = OMINUS
3742
3743 n.Right = nil
3744 } else {
3745 // divide by 1
3746 n = nl
3747 }
3748
3749 default:
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003750 if n.Type.IsSigned() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003751 if n.Op == OMOD {
3752 // signed modulo 2^pow is like ANDing
3753 // with the last pow bits, but if nl < 0,
3754 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003755 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003756
Dave Cheneya4be24c2016-03-23 13:27:49 +11003757 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3758 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003759 if pow == 1 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003760 n1 = typecheck(n1, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003761 n1 = cheapexpr(n1, init)
3762
3763 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003764 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003765
Dave Cheneya4be24c2016-03-23 13:27:49 +11003766 var nc Node
3767 Nodconst(&nc, nl.Type, 1)
3768 n3 := Nod(OAND, n2, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003769 n = Nod(OADD, n3, n1)
3770 } else {
3771 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003772 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003773
Dave Cheneya4be24c2016-03-23 13:27:49 +11003774 Nodconst(&nc, nl.Type, (1<<uint(pow))-1)
3775 n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003776 n2 = typecheck(n2, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003777 n2 = cheapexpr(n2, init)
3778
Russ Cox382b44e2015-02-23 16:07:24 -05003779 n3 := Nod(OADD, nl, n2)
Dave Cheneya4be24c2016-03-23 13:27:49 +11003780 n4 := Nod(OAND, n3, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003781 n = Nod(OSUB, n4, n2)
3782 }
3783
3784 break
3785 } else {
3786 // arithmetic right shift does not give the correct rounding.
3787 // if nl >= 0, nl >> n == nl / nr
3788 // if nl < 0, we want to add 2^n-1 first.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003789 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003790
Dave Cheneya4be24c2016-03-23 13:27:49 +11003791 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3792 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003793 if pow == 1 {
3794 // nl+1 is nl-(-1)
3795 n.Left = Nod(OSUB, nl, n1)
3796 } else {
3797 // Do a logical right right on -1 to keep pow bits.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003798 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003799
Dave Cheneya4be24c2016-03-23 13:27:49 +11003800 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
Josh Bleecher Snyder62861882016-05-26 18:08:24 -07003801 n2 := Nod(ORSH, conv(n1, nl.Type.toUnsigned()), &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003802 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3803 }
3804
3805 // n = (nl + 2^pow-1) >> pow
3806 n.Op = ORSH
3807
Dave Cheneya4be24c2016-03-23 13:27:49 +11003808 var n2 Node
3809 Nodconst(&n2, Types[Simtype[TUINT]], int64(pow))
3810 n.Right = &n2
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 n.Typecheck = 0
3812 }
3813
3814 if s != 0 {
3815 n = Nod(OMINUS, n, nil)
3816 }
3817 break
3818 }
3819
Dave Cheneya4be24c2016-03-23 13:27:49 +11003820 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003821 if n.Op == OMOD {
3822 // n = nl & (nr-1)
3823 n.Op = OAND
3824
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003825 Nodconst(&nc, nl.Type, nr.Int64()-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003826 } else {
3827 // n = nl >> pow
3828 n.Op = ORSH
3829
Dave Cheneya4be24c2016-03-23 13:27:49 +11003830 Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
Russ Cox8c195bd2015-02-13 14:40:36 -05003831 }
3832
3833 n.Typecheck = 0
Dave Cheneya4be24c2016-03-23 13:27:49 +11003834 n.Right = &nc
Russ Cox8c195bd2015-02-13 14:40:36 -05003835 }
3836
3837 goto ret
3838
Russ Cox8c195bd2015-02-13 14:40:36 -05003839ret:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003840 n = typecheck(n, Erv)
3841 n = walkexpr(n, init)
3842 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003843}
3844
3845// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003846func bounded(n *Node, max int64) bool {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003847 if n.Type == nil || !n.Type.IsInteger() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003848 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003849 }
3850
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003851 sign := n.Type.IsSigned()
Russ Cox382b44e2015-02-23 16:07:24 -05003852 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003853
Russ Coxdc7b54b2015-02-17 22:13:49 -05003854 if Smallintconst(n) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003855 v := n.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003856 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003857 }
3858
3859 switch n.Op {
3860 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003861 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003862 if Smallintconst(n.Left) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003863 v = n.Left.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003864 } else if Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003865 v = n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003866 }
3867
3868 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003869 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003870 }
3871
3872 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003873 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003874 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003875 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003876 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003877 }
3878 }
3879
3880 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003881 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003882 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003883 for bits > 0 && v >= 2 {
3884 bits--
3885 v >>= 1
3886 }
3887 }
3888
3889 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003890 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003891 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003892 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003893 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003894 }
3895 bits -= int32(v)
3896 }
3897 }
3898
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003899 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003900 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003901 }
3902
Russ Coxdc7b54b2015-02-17 22:13:49 -05003903 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003904}
3905
David Crawshawcc158402016-03-10 16:15:26 -05003906// usemethod check interface method calls for uses of reflect.Type.Method.
3907func usemethod(n *Node) {
3908 t := n.Left.Type
3909
3910 // Looking for either of:
3911 // Method(int) reflect.Method
3912 // MethodByName(string) (reflect.Method, bool)
3913 //
3914 // TODO(crawshaw): improve precision of match by working out
3915 // how to check the method name.
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003916 if n := t.Params().NumFields(); n != 1 {
David Crawshawcc158402016-03-10 16:15:26 -05003917 return
3918 }
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003919 if n := t.Results().NumFields(); n != 1 && n != 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003920 return
3921 }
3922 p0 := t.Params().Field(0)
3923 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003924 var res1 *Field
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003925 if t.Results().NumFields() == 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003926 res1 = t.Results().Field(1)
3927 }
3928
3929 if res1 == nil {
3930 if p0.Type.Etype != TINT {
3931 return
3932 }
3933 } else {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003934 if !p0.Type.IsString() {
David Crawshawcc158402016-03-10 16:15:26 -05003935 return
3936 }
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003937 if !res1.Type.IsBoolean() {
David Crawshawcc158402016-03-10 16:15:26 -05003938 return
3939 }
3940 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003941 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003942 return
3943 }
3944
3945 Curfn.Func.ReflectMethod = true
3946}
3947
Russ Cox8c195bd2015-02-13 14:40:36 -05003948func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003949 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003950 return
3951 }
3952
3953 switch n.Op {
3954 default:
Dave Cheneyd3c79d32016-04-27 15:10:10 +10003955 Fatalf("usefield %v", n.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -05003956
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003957 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003958 break
3959 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003960 if n.Sym == nil {
Keith Randall71d13a82016-03-02 20:54:41 -08003961 // No field name. This DOTPTR was built by the compiler for access
3962 // to runtime data structures. Ignore.
3963 return
3964 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003965
Russ Cox496ad0a2015-05-26 21:49:31 -04003966 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003967 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003968 t = t.Elem()
Russ Cox496ad0a2015-05-26 21:49:31 -04003969 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003970 field := dotField[typeSym{t.Orig, n.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003971 if field == nil {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003972 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003973 }
Matthew Dempskye48a2952016-04-25 13:24:48 -07003974 if !strings.Contains(field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003975 return
3976 }
3977
Matthew Dempskya2a48062016-03-10 16:15:44 -08003978 outer := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003979 if outer.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003980 outer = outer.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05003981 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003982 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003983 Yyerror("tracked field must be in named struct type")
3984 }
3985 if !exportname(field.Sym.Name) {
3986 Yyerror("tracked field must be exported (upper case)")
3987 }
3988
Matthew Dempskya2a48062016-03-10 16:15:44 -08003989 sym := tracksym(outer, field)
3990 if Curfn.Func.FieldTrack == nil {
3991 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
3992 }
3993 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05003994}
3995
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003996func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003997 for _, n := range l.Slice() {
3998 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003999 return false
4000 }
4001 }
4002 return true
4003}
4004
Russ Coxdc7b54b2015-02-17 22:13:49 -05004005func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05004006 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05004007 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004008 }
4009
4010 switch n.Op {
4011 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004012 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004013
4014 // Discardable as long as the subpieces are.
4015 case ONAME,
4016 ONONAME,
4017 OTYPE,
4018 OPACK,
4019 OLITERAL,
4020 OADD,
4021 OSUB,
4022 OOR,
4023 OXOR,
4024 OADDSTR,
4025 OADDR,
4026 OANDAND,
4027 OARRAYBYTESTR,
4028 OARRAYRUNESTR,
4029 OSTRARRAYBYTE,
4030 OSTRARRAYRUNE,
4031 OCAP,
4032 OCMPIFACE,
4033 OCMPSTR,
4034 OCOMPLIT,
4035 OMAPLIT,
4036 OSTRUCTLIT,
4037 OARRAYLIT,
4038 OPTRLIT,
4039 OCONV,
4040 OCONVIFACE,
4041 OCONVNOP,
4042 ODOT,
4043 OEQ,
4044 ONE,
4045 OLT,
4046 OLE,
4047 OGT,
4048 OGE,
4049 OKEY,
4050 OLEN,
4051 OMUL,
4052 OLSH,
4053 ORSH,
4054 OAND,
4055 OANDNOT,
4056 ONEW,
4057 ONOT,
4058 OCOM,
4059 OPLUS,
4060 OMINUS,
4061 OOROR,
4062 OPAREN,
4063 ORUNESTR,
4064 OREAL,
4065 OIMAG,
4066 OCOMPLEX:
4067 break
4068
4069 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004070 case ODIV, OMOD:
Matthew Dempskyd3253872016-03-20 13:55:42 -07004071 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004072 break
4073 }
Matthew Dempskyd3253872016-03-20 13:55:42 -07004074 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004075 break
4076 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004077 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004078
4079 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07004080 case OMAKECHAN, OMAKEMAP:
Matthew Dempskyd3253872016-03-20 13:55:42 -07004081 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05004082 break
4083 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05004084 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004085
4086 // Difficult to tell what sizes are okay.
4087 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05004088 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004089 }
4090
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004091 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 -05004092 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05004093 }
4094
Russ Coxdc7b54b2015-02-17 22:13:49 -05004095 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05004096}
4097
4098// rewrite
4099// print(x, y, z)
4100// into
4101// func(a1, a2, a3) {
4102// print(a1, a2, a3)
4103// }(x, y, z)
4104// and same for println.
4105
4106var walkprintfunc_prgen int
4107
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004108// The result of walkprintfunc MUST be assigned back to n, e.g.
4109// n.Left = walkprintfunc(n.Left, init)
4110func walkprintfunc(n *Node, init *Nodes) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004111 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08004112 walkstmtlist(n.Ninit.Slice())
4113 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05004114 }
4115
Russ Cox382b44e2015-02-23 16:07:24 -05004116 t := Nod(OTFUNC, nil, nil)
4117 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004118 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05004119 var a *Node
4120 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004121 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05004122 buf = fmt.Sprintf("a%d", num)
4123 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004124 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
4125 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08004126 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05004127 }
4128
Russ Cox382b44e2015-02-23 16:07:24 -05004129 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05004130 walkprintfunc_prgen++
4131 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04004132 fn.Func.Nname = newname(Lookup(buf))
4133 fn.Func.Nname.Name.Defn = fn
4134 fn.Func.Nname.Name.Param.Ntype = t
4135 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05004136
Russ Cox382b44e2015-02-23 16:07:24 -05004137 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05004138 Curfn = nil
4139 funchdr(fn)
4140
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02004141 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004142 a.List.Set(printargs)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004143 a = typecheck(a, Etop)
4144 a = walkstmt(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004145
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08004146 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05004147
4148 funcbody(fn)
4149
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004150 fn = typecheck(fn, Etop)
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07004151 typecheckslice(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08004152 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05004153 Curfn = oldfn
4154
4155 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04004156 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08004157 a.List.Set(n.List.Slice())
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07004158 a = typecheck(a, Etop)
4159 a = walkexpr(a, init)
4160 return a
Russ Cox8c195bd2015-02-13 14:40:36 -05004161}