blob: 04ccfad9710bbe5de8b736fdb21794ee9b8dc668 [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.
30 // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080031 for i, ln := range fn.Func.Dcl {
32 if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070033 ln = typecheck(ln, Erv|Easgn)
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080034 fn.Func.Dcl[i] = ln
Russ Cox8c195bd2015-02-13 14:40:36 -050035 }
36 }
37
38 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080039 for _, ln := range fn.Func.Dcl {
40 if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
41 ln.Name.Defn.Left.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -050042 }
43 }
44
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080045 for _, ln := range fn.Func.Dcl {
46 if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050047 continue
48 }
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080049 if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
Russ Cox4fdd5362015-05-26 22:19:27 -040050 if defn.Left.Used {
Russ Cox8c195bd2015-02-13 14:40:36 -050051 continue
52 }
Russ Cox4fdd5362015-05-26 22:19:27 -040053 lineno = defn.Left.Lineno
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080054 Yyerror("%v declared and not used", ln.Sym)
Russ Cox4fdd5362015-05-26 22:19:27 -040055 defn.Left.Used = true // suppress repeats
Russ Cox8c195bd2015-02-13 14:40:36 -050056 } else {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080057 lineno = ln.Lineno
58 Yyerror("%v declared and not used", ln.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050059 }
60 }
61
Robert Griesemerc41608f2016-03-02 17:34:42 -080062 lineno = lno
Russ Cox8c195bd2015-02-13 14:40:36 -050063 if nerrors != 0 {
64 return
65 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080066 walkstmtlist(Curfn.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -050067 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040068 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080069 dumplist(s, Curfn.Nbody)
Russ Cox8c195bd2015-02-13 14:40:36 -050070 }
71
72 heapmoves()
Josh Bleecher Snyder1da62af2016-04-24 13:50:26 -070073 if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040074 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080075 dumplist(s, Curfn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050076 }
77}
78
Ian Lance Taylore28a8902016-03-07 22:54:46 -080079func walkstmtlist(s []*Node) {
80 for i := range s {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070081 s[i] = walkstmt(s[i])
Russ Cox8c195bd2015-02-13 14:40:36 -050082 }
83}
84
Ian Lance Taylore28a8902016-03-07 22:54:46 -080085func samelist(a, b []*Node) bool {
86 if len(a) != len(b) {
87 return false
Ian Lance Taylor188e3d22016-02-26 14:28:48 -080088 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080089 for i, n := range a {
90 if n != b[i] {
Russ Coxdc7b54b2015-02-17 22:13:49 -050091 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050092 }
93 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -080094 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050095}
96
Dave Cheneyb006d382015-03-06 18:42:58 +110097func paramoutheap(fn *Node) bool {
Ian Lance Taylorb66a8922016-02-25 10:35:19 -080098 for _, ln := range fn.Func.Dcl {
99 switch ln.Class {
Russ Cox8c195bd2015-02-13 14:40:36 -0500100 case PPARAMOUT,
101 PPARAMOUT | PHEAP:
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800102 return ln.Addrtaken
Russ Cox8c195bd2015-02-13 14:40:36 -0500103
104 // stop early - parameters are over
105 case PAUTO,
106 PAUTO | PHEAP:
Dave Cheneyb006d382015-03-06 18:42:58 +1100107 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500108 }
109 }
110
Dave Cheneyb006d382015-03-06 18:42:58 +1100111 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500112}
113
114// adds "adjust" to all the argument locations for the call n.
115// n must be a defer or go node that has already been walked.
116func adjustargs(n *Node, adjust int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500117 var arg *Node
118 var lhs *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500119
Russ Cox382b44e2015-02-23 16:07:24 -0500120 callfunc := n.Left
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800121 for _, arg = range callfunc.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500122 if arg.Op != OAS {
123 Yyerror("call arg not assignment")
124 }
125 lhs = arg.Left
126 if lhs.Op == ONAME {
127 // This is a temporary introduced by reorder1.
128 // The real store to the stack appears later in the arg list.
129 continue
130 }
131
132 if lhs.Op != OINDREG {
133 Yyerror("call argument store does not use OINDREG")
134 }
135
136 // can't really check this in machine-indep code.
137 //if(lhs->val.u.reg != D_SP)
138 // yyerror("call arg assign not indreg(SP)");
139 lhs.Xoffset += int64(adjust)
140 }
141}
142
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700143// The result of walkstmt MUST be assigned back to n, e.g.
144// n.Left = walkstmt(n.Left)
145func walkstmt(n *Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500146 if n == nil {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700147 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500148 }
149 if n.Dodata == 2 { // don't walk, generated by anylit.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700150 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500151 }
152
153 setlineno(n)
154
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800155 walkstmtlist(n.Ninit.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500156
157 switch n.Op {
158 default:
159 if n.Op == ONAME {
Russ Cox17228f42015-04-17 12:03:22 -0400160 Yyerror("%v is not a top level statement", n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500161 } else {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -0800162 Yyerror("%v is not a top level statement", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500163 }
164 Dump("nottop", n)
165
166 case OAS,
167 OASOP,
168 OAS2,
169 OAS2DOTTYPE,
170 OAS2RECV,
171 OAS2FUNC,
172 OAS2MAPR,
173 OCLOSE,
174 OCOPY,
175 OCALLMETH,
176 OCALLINTER,
177 OCALL,
178 OCALLFUNC,
179 ODELETE,
180 OSEND,
181 OPRINT,
182 OPRINTN,
183 OPANIC,
184 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400185 ORECOVER,
186 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500187 if n.Typecheck == 0 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700188 Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500189 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700190 wascopy := n.Op == OCOPY
Russ Cox382b44e2015-02-23 16:07:24 -0500191 init := n.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800192 n.Ninit.Set(nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700193 n = walkexpr(n, &init)
194 n = addinit(n, init.Slice())
195 if wascopy && n.Op == OCONVNOP {
Russ Cox8c195bd2015-02-13 14:40:36 -0500196 n.Op = OEMPTY // don't leave plain values as statements.
197 }
198
199 // special case for a receive where we throw away
200 // the value received.
201 case ORECV:
202 if n.Typecheck == 0 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700203 Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500204 }
Russ Cox382b44e2015-02-23 16:07:24 -0500205 init := n.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800206 n.Ninit.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500207
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700208 n.Left = walkexpr(n.Left, &init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500209 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 -0700210 n = walkexpr(n, &init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500211
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700212 n = addinit(n, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500213
214 case OBREAK,
215 ODCL,
216 OCONTINUE,
217 OFALL,
218 OGOTO,
219 OLABEL,
220 ODCLCONST,
221 ODCLTYPE,
222 OCHECKNIL,
Russ Cox1ac637c2016-01-13 00:46:28 -0500223 OVARKILL,
224 OVARLIVE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500225 break
226
227 case OBLOCK:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800228 walkstmtlist(n.List.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500229
230 case OXCASE:
231 Yyerror("case statement out of place")
232 n.Op = OCASE
233 fallthrough
234
235 case OCASE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700236 n.Right = walkstmt(n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500237
238 case ODEFER:
HĂ¥vard Haugen25946642015-09-07 22:19:30 +0200239 hasdefer = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500240 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700241 case OPRINT, OPRINTN:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700242 n.Left = walkprintfunc(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500243
244 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700245 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500246
247 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700248 n.Left = walkexpr(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500249 }
250
251 // make room for size & fn arguments.
252 adjustargs(n, 2*Widthptr)
253
254 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400255 if n.Left != nil {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800256 walkstmtlist(n.Left.Ninit.Slice())
Russ Cox66be1482015-05-26 21:30:20 -0400257 init := n.Left.Ninit
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800258 n.Left.Ninit.Set(nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700259 n.Left = walkexpr(n.Left, &init)
260 n.Left = addinit(n.Left, init.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500261 }
262
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700263 n.Right = walkstmt(n.Right)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800264 walkstmtlist(n.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500265
266 case OIF:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700267 n.Left = walkexpr(n.Left, &n.Ninit)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800268 walkstmtlist(n.Nbody.Slice())
269 walkstmtlist(n.Rlist.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500270
271 case OPROC:
272 switch n.Left.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700273 case OPRINT, OPRINTN:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700274 n.Left = walkprintfunc(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500275
276 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700277 n.Left = copyany(n.Left, &n.Ninit, true)
Russ Cox8c195bd2015-02-13 14:40:36 -0500278
279 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700280 n.Left = walkexpr(n.Left, &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500281 }
282
283 // make room for size & fn arguments.
284 adjustargs(n, 2*Widthptr)
285
286 case ORETURN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800287 walkexprlist(n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800288 if n.List.Len() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500289 break
290 }
Josh Bleecher Snyderf38f43d2016-04-01 20:11:30 -0700291 if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500292 // assign to the function out parameters,
293 // so that reorder3 can fix up conflicts
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800294 var rl []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500295
Robert Griesemercd7d7382015-10-26 14:57:36 -0700296 var cl Class
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800297 for _, ln := range Curfn.Func.Dcl {
298 cl = ln.Class &^ PHEAP
Russ Cox8c195bd2015-02-13 14:40:36 -0500299 if cl == PAUTO {
300 break
301 }
302 if cl == PPARAMOUT {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800303 rl = append(rl, ln)
Russ Cox8c195bd2015-02-13 14:40:36 -0500304 }
305 }
306
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800307 if got, want := n.List.Len(), len(rl); got != want {
Matthew Dempsky22a204d2015-12-14 12:37:26 -0800308 // order should have rewritten multi-value function calls
309 // with explicit OAS2FUNC nodes.
310 Fatalf("expected %v return arguments, have %v", want, got)
311 }
312
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800313 if samelist(rl, n.List.Slice()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500314 // special return in disguise
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800315 n.List.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500316
317 break
318 }
319
Russ Cox8c195bd2015-02-13 14:40:36 -0500320 // move function calls out, to make reorder3's job easier.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800321 walkexprlistsafe(n.List.Slice(), &n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500322
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800323 ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800324 n.List.Set(reorder3(ll))
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800325 ls := n.List.Slice()
326 for i, n := range ls {
327 ls[i] = applywritebarrier(n)
Matthew Dempsky85dd62d2015-12-11 19:11:54 -0800328 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500329 break
330 }
331
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800332 ll := ascompatte(n.Op, nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800333 n.List.Set(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500334
335 case ORETJMP:
336 break
337
338 case OSELECT:
339 walkselect(n)
340
341 case OSWITCH:
342 walkswitch(n)
343
344 case ORANGE:
345 walkrange(n)
346
347 case OXFALL:
348 Yyerror("fallthrough statement out of place")
349 n.Op = OFALL
350 }
351
352 if n.Op == ONAME {
Matthew Dempsky63142022016-03-15 13:06:58 -0700353 Fatalf("walkstmt ended up with name: %v", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500354 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700355 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500356}
357
David Chasee5060c72015-05-20 15:16:34 -0400358func isSmallMakeSlice(n *Node) bool {
359 if n.Op != OMAKESLICE {
360 return false
361 }
362 l := n.Left
363 r := n.Right
364 if r == nil {
365 r = l
366 }
367 t := n.Type
368
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -0700369 return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
David Chasee5060c72015-05-20 15:16:34 -0400370}
371
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900372// walk the whole tree of the body of an
373// expression or simple statement.
374// the types expressions are calculated.
375// compile-time constants are evaluated.
376// complex side effects like statements are appended to init
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800377func walkexprlist(s []*Node, init *Nodes) {
378 for i := range s {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700379 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500380 }
381}
382
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800383func walkexprlistsafe(s []*Node, init *Nodes) {
384 for i, n := range s {
385 s[i] = safeexpr(n, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700386 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500387 }
388}
389
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800390func walkexprlistcheap(s []*Node, init *Nodes) {
391 for i, n := range s {
392 s[i] = cheapexpr(n, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700393 s[i] = walkexpr(s[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500394 }
395}
396
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000397// Build name of function: convI2E etc.
398// Not all names are possible
399// (e.g., we'll never generate convE2E or convE2I).
400func convFuncName(from, to *Type) string {
401 tkind := to.iet()
402 switch from.iet() {
403 case 'I':
404 switch tkind {
405 case 'E':
406 return "convI2E"
407 case 'I':
408 return "convI2I"
409 }
410 case 'T':
411 switch tkind {
412 case 'E':
413 return "convT2E"
414 case 'I':
415 return "convT2I"
416 }
417 }
418 Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
419 panic("unreachable")
420}
421
422// Build name of function: assertI2E etc.
423// If with2suffix is true, the form ending in "2" is returned".
424func assertFuncName(from, to *Type, with2suffix bool) string {
425 l := len("assertX2X2")
426 if !with2suffix {
427 l--
428 }
429 tkind := to.iet()
430 switch from.iet() {
431 case 'E':
432 switch tkind {
433 case 'I':
434 return "assertE2I2"[:l]
435 case 'E':
436 return "assertE2E2"[:l]
437 case 'T':
438 return "assertE2T2"[:l]
439 }
440 case 'I':
441 switch tkind {
442 case 'I':
443 return "assertI2I2"[:l]
444 case 'E':
445 return "assertI2E2"[:l]
446 case 'T':
447 return "assertI2T2"[:l]
448 }
449 }
450 Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
451 panic("unreachable")
452}
453
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700454// The result of walkexpr MUST be assigned back to n, e.g.
455// n.Left = walkexpr(n.Left, init)
456func walkexpr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500457 if n == nil {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700458 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500459 }
460
461 if init == &n.Ninit {
462 // not okay to use n->ninit when walking n,
463 // because we might replace n with some other node
464 // and would lose the init list.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200465 Fatalf("walkexpr init == &n->ninit")
Russ Cox8c195bd2015-02-13 14:40:36 -0500466 }
467
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800468 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800469 walkstmtlist(n.Ninit.Slice())
470 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 }
472
473 // annoying case - not typechecked
474 if n.Op == OKEY {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700475 n.Left = walkexpr(n.Left, init)
476 n.Right = walkexpr(n.Right, init)
477 return n
Russ Cox8c195bd2015-02-13 14:40:36 -0500478 }
479
Russ Cox382b44e2015-02-23 16:07:24 -0500480 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500481
482 if Debug['w'] > 1 {
483 Dump("walk-before", n)
484 }
485
486 if n.Typecheck != 1 {
Matthew Dempsky63142022016-03-15 13:06:58 -0700487 Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500488 }
489
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200490opswitch:
Russ Cox8c195bd2015-02-13 14:40:36 -0500491 switch n.Op {
492 default:
493 Dump("walk", n)
Matthew Dempsky63142022016-03-15 13:06:58 -0700494 Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, FmtShort|FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500495
496 case OTYPE,
497 ONONAME,
498 OINDREG,
499 OEMPTY,
Russ Cox92c826b2015-04-03 12:23:28 -0400500 OPARAM,
501 OGETG:
Russ Cox8c195bd2015-02-13 14:40:36 -0500502
503 case ONOT,
504 OMINUS,
505 OPLUS,
506 OCOM,
507 OREAL,
508 OIMAG,
509 ODOTMETH,
510 ODOTINTER:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700511 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500512
513 case OIND:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700514 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500515
516 case ODOT:
517 usefield(n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700518 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500519
520 case ODOTPTR:
521 usefield(n)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700522 if n.Op == ODOTPTR && n.Left.Type.Elem().Width == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500523 // No actual copy will be generated, so emit an explicit nil check.
524 n.Left = cheapexpr(n.Left, init)
525
526 checknil(n.Left, init)
527 }
528
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700529 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500530
531 case OEFACE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700532 n.Left = walkexpr(n.Left, init)
533 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500534
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700535 case OSPTR, OITAB:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700536 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500537
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700538 case OLEN, OCAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700539 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500540
541 // replace len(*[10]int) with 10.
542 // delayed until now to preserve side effects.
Russ Cox382b44e2015-02-23 16:07:24 -0500543 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500544
Matthew Dempskye76fc1b2016-03-30 15:09:25 -0700545 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -0700546 t = t.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -0500547 }
Matthew Dempsky1624a9c2016-03-30 14:45:47 -0700548 if t.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500549 safeexpr(n.Left, init)
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -0700550 Nodconst(n, n.Type, t.NumElem())
Russ Cox8c195bd2015-02-13 14:40:36 -0500551 n.Typecheck = 1
552 }
553
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700554 case OLSH, ORSH:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700555 n.Left = walkexpr(n.Left, init)
556 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500557 t := n.Left.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500558 n.Bounded = bounded(n.Right, 8*t.Width)
559 if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500560 Warn("shift bounds check elided")
561 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500562
563 // Use results from call expression as arguments for complex.
564 case OAND,
565 OSUB,
566 OHMUL,
567 OLT,
568 OLE,
569 OGE,
570 OGT,
571 OADD,
572 OCOMPLEX,
573 OLROT:
574 if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800575 n.Left = n.List.First()
576 n.Right = n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500577 }
578
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700579 n.Left = walkexpr(n.Left, init)
580 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500581
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700582 case OOR, OXOR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700583 n.Left = walkexpr(n.Left, init)
584 n.Right = walkexpr(n.Right, init)
585 n = walkrotate(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500586
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700587 case OEQ, ONE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700588 n.Left = walkexpr(n.Left, init)
589 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500590
591 // Disable safemode while compiling this code: the code we
592 // generate internally can refer to unsafe.Pointer.
593 // In this case it can happen if we need to generate an ==
594 // for a struct containing a reflect.Value, which itself has
595 // an unexported field of type unsafe.Pointer.
Russ Cox382b44e2015-02-23 16:07:24 -0500596 old_safemode := safemode
Matthew Dempsky980ab122016-04-13 18:37:18 -0700597 safemode = false
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700598 n = walkcompare(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500599 safemode = old_safemode
Russ Cox8c195bd2015-02-13 14:40:36 -0500600
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700601 case OANDAND, OOROR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700602 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500603
David Chaseffe7fbf2015-03-27 12:34:45 -0400604 // cannot put side effects from n.Right on init,
605 // because they cannot run before n.Left is checked.
606 // save elsewhere and store on the eventual n.Right.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800607 var ll Nodes
Russ Cox8c195bd2015-02-13 14:40:36 -0500608
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700609 n.Right = walkexpr(n.Right, &ll)
610 n.Right = addinit(n.Right, ll.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500611
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700612 case OPRINT, OPRINTN:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800613 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500614 n = walkprint(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500615
616 case OPANIC:
617 n = mkcall("gopanic", nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500618
619 case ORECOVER:
620 n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500621
622 case OLITERAL:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700623 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500624
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700625 case OCLOSUREVAR, OCFUNC:
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700626 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500627
628 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500629 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700630 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500631 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500632
633 case OCALLINTER:
David Crawshawcc158402016-03-10 16:15:26 -0500634 usemethod(n)
Russ Cox382b44e2015-02-23 16:07:24 -0500635 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800636 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200637 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500638 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700639 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800640 walkexprlist(n.List.Slice(), init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800641 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800642 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500643
644 case OCALLFUNC:
645 if n.Left.Op == OCLOSURE {
646 // Transform direct call of a closure to call of a normal function.
647 // transformclosure already did all preparation work.
648
David Chase731dcda2015-07-23 14:17:07 -0400649 // Prepend captured variables to argument list.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800650 n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500651
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800652 n.Left.Func.Enter.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500653
654 // Replace OCLOSURE with ONAME/PFUNC.
Russ Coxbd4fff62015-05-27 10:42:55 -0400655 n.Left = n.Left.Func.Closure.Func.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500656
657 // Update type of OCALLFUNC node.
658 // Output arguments had not changed, but their offsets could.
Matthew Dempskyc8377612016-03-17 01:47:16 -0700659 if n.Left.Type.Results().NumFields() == 1 {
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -0700660 n.Type = n.Left.Type.Results().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 } else {
Matthew Dempskydb506fe2016-03-08 16:31:28 -0800662 n.Type = n.Left.Type.Results()
Russ Cox8c195bd2015-02-13 14:40:36 -0500663 }
664 }
665
Russ Cox382b44e2015-02-23 16:07:24 -0500666 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800667 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200668 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500669 }
670
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700671 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800672 walkexprlist(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500673
Russ Cox92dba0d2015-04-01 16:02:34 -0400674 if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
Michael Munday613ba6c2016-04-12 12:26:17 -0400675 if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
Russ Cox92dba0d2015-04-01 16:02:34 -0400676 n.Op = OSQRT
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800677 n.Left = n.List.First()
678 n.List.Set(nil)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200679 break opswitch
Russ Cox92dba0d2015-04-01 16:02:34 -0400680 }
681 }
682
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800683 ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800684 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500685
686 case OCALLMETH:
Russ Cox382b44e2015-02-23 16:07:24 -0500687 t := n.Left.Type
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800688 if n.List.Len() != 0 && n.List.First().Op == OAS {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200689 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500690 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700691 n.Left = walkexpr(n.Left, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800692 walkexprlist(n.List.Slice(), init)
Matthew Dempskyf91b8322016-03-09 20:54:59 -0800693 ll := ascompatte(n.Op, n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800694 lr := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800695 ll = append(ll, lr...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500696 n.Left.Left = nil
697 ullmancalc(n.Left)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800698 n.List.Set(reorder1(ll))
Russ Cox8c195bd2015-02-13 14:40:36 -0500699
700 case OAS:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800701 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500702
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700703 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500704 n.Left = safeexpr(n.Left, init)
705
Russ Coxdc7b54b2015-02-17 22:13:49 -0500706 if oaslit(n, init) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200707 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500708 }
709
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700710 if n.Right == nil || iszero(n.Right) && !instrumenting {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200711 break
Russ Cox8c195bd2015-02-13 14:40:36 -0500712 }
713
714 switch n.Right.Op {
715 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700716 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500717
Russ Cox8c195bd2015-02-13 14:40:36 -0500718 case ODOTTYPE:
Russ Cox4224d812015-03-20 00:06:10 -0400719 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
720 // It needs to be removed in all three places.
721 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700722 if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400723 // handled directly during cgen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700724 n.Right = walkexpr(n.Right, init)
Russ Cox4224d812015-03-20 00:06:10 -0400725 break
726 }
727
David Chaseffe7fbf2015-03-27 12:34:45 -0400728 // x = i.(T); n.Left is x, n.Right.Left is i.
Russ Cox4224d812015-03-20 00:06:10 -0400729 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700730 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500731
Russ Cox382b44e2015-02-23 16:07:24 -0500732 n1 := Nod(OADDR, n.Left, nil)
733 r := n.Right // i.(T)
Russ Cox8c195bd2015-02-13 14:40:36 -0500734
Russ Cox4224d812015-03-20 00:06:10 -0400735 if Debug_typeassert > 0 {
736 Warn("type assertion not inlined")
737 }
738
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800739 fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700740 fn = substArgTypes(fn, r.Left.Type, r.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500741
742 n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700743 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200744 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -0500745
Russ Cox8c195bd2015-02-13 14:40:36 -0500746 case ORECV:
David Chaseffe7fbf2015-03-27 12:34:45 -0400747 // x = <-c; n.Left is x, n.Right.Left is c.
Russ Cox4224d812015-03-20 00:06:10 -0400748 // orderstmt made sure x is addressable.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700749 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500750
Russ Cox382b44e2015-02-23 16:07:24 -0500751 n1 := Nod(OADDR, n.Left, nil)
752 r := n.Right.Left // the channel
Russ Cox8c195bd2015-02-13 14:40:36 -0500753 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700754 n = walkexpr(n, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200755 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400756
757 case OAPPEND:
758 // x = append(...)
759 r := n.Right
760 if r.Isddd {
761 r = appendslice(r, init) // also works for append(slice, string).
762 } else {
763 r = walkappend(r, init, n)
764 }
765 n.Right = r
766 if r.Op == OAPPEND {
767 // Left in place for back end.
768 // Do not add a new write barrier.
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200769 break opswitch
Russ Cox85520472015-05-06 12:34:30 -0400770 }
771 // Otherwise, lowered for race detector.
772 // Treat as ordinary assignment.
Russ Cox8c195bd2015-02-13 14:40:36 -0500773 }
774
775 if n.Left != nil && n.Right != nil {
Josh Bleecher Snyder68884052016-03-26 08:17:43 -0700776 dd := n.Dodata
777 n = convas(n, init)
778 n.Dodata = dd
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800779 n = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500780 }
781
Russ Cox8c195bd2015-02-13 14:40:36 -0500782 case OAS2:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800783 init.AppendNodes(&n.Ninit)
784 walkexprlistsafe(n.List.Slice(), init)
785 walkexprlistsafe(n.Rlist.Slice(), init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800786 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500787 ll = reorder3(ll)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800788 for i, n := range ll {
789 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500790 }
791 n = liststmt(ll)
Russ Cox8c195bd2015-02-13 14:40:36 -0500792
793 // a,b,... = fn()
794 case OAS2FUNC:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800795 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500796
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800797 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800798 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700799 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500800
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800801 ll := ascompatet(n.Op, n.List, r.Type, 0, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800802 for i, n := range ll {
803 ll[i] = applywritebarrier(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500804 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800805 n = liststmt(append([]*Node{r}, ll...))
Russ Cox8c195bd2015-02-13 14:40:36 -0500806
807 // x, y = <-c
808 // orderstmt made sure x is addressable.
809 case OAS2RECV:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800810 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500811
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800812 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800813 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700814 r.Left = walkexpr(r.Left, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500815 var n1 *Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800816 if isblank(n.List.First()) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500817 n1 = nodnil()
818 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800819 n1 = Nod(OADDR, n.List.First(), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500820 }
821 n1.Etype = 1 // addr does not escape
Russ Cox382b44e2015-02-23 16:07:24 -0500822 fn := chanfn("chanrecv2", 2, r.Left.Type)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800823 r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
824 n = Nod(OAS, n.List.Second(), r)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700825 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500826
827 // a,b = m[i];
828 case OAS2MAPR:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800829 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -0500830
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800831 r := n.Rlist.First()
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800832 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700833 r.Left = walkexpr(r.Left, init)
834 r.Right = walkexpr(r.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -0500835 t := r.Left.Type
836 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700837 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800838 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800839 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -0500840 p = "mapaccess2_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800841 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -0500842 p = "mapaccess2_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -0800843 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -0500844 p = "mapaccess2_faststr"
845 }
846 }
847
Russ Cox382b44e2015-02-23 16:07:24 -0500848 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500849 if p != "" {
850 // fast versions take key by value
851 key = r.Right
852 } else {
853 // standard version takes key by reference
854 // orderexpr made sure key is addressable.
855 key = Nod(OADDR, r.Right, nil)
856
857 p = "mapaccess2"
858 }
859
860 // from:
861 // a,b = m[i]
862 // to:
863 // var,b = mapaccess2*(t, m, i)
864 // a = *var
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800865 a := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -0500866
Keith Randall60fd32a2016-04-19 08:31:04 -0700867 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
868 fn := mapfn(p, t)
869 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
870 } else {
871 fn := mapfn("mapaccess2_fat", t)
872 z := zeroaddr(w)
873 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
874 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500875
876 // mapaccess2* returns a typed bool, but due to spec changes,
877 // the boolean result of i.(T) is now untyped so we make it the
878 // same type as the variable on the lhs.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800879 if !isblank(n.List.Second()) {
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -0800880 r.Type.Field(1).Type = n.List.Second().Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500881 }
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800882 n.Rlist.Set1(r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500883 n.Op = OAS2FUNC
884
885 // don't generate a = *var if a is _
886 if !isblank(a) {
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -0700887 var_ := temp(Ptrto(t.Val()))
Russ Cox8c195bd2015-02-13 14:40:36 -0500888 var_.Typecheck = 1
Keith Randall3c1a4c12016-04-19 21:06:53 -0700889 var_.NonNil = true // mapaccess always returns a non-nil pointer
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800890 n.List.SetIndex(0, var_)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700891 n = walkexpr(n, init)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800892 init.Append(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500893 n = Nod(OAS, a, Nod(OIND, var_, nil))
894 }
895
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700896 n = typecheck(n, Etop)
897 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500898
Russ Cox8c195bd2015-02-13 14:40:36 -0500899 case ODELETE:
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800900 init.AppendNodes(&n.Ninit)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800901 map_ := n.List.First()
902 key := n.List.Second()
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700903 map_ = walkexpr(map_, init)
904 key = walkexpr(key, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500905
906 // orderstmt made sure key is addressable.
907 key = Nod(OADDR, key, nil)
908
Russ Cox382b44e2015-02-23 16:07:24 -0500909 t := map_.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500910 n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
Russ Cox8c195bd2015-02-13 14:40:36 -0500911
Russ Cox8c195bd2015-02-13 14:40:36 -0500912 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800913 e := n.Rlist.First() // i.(T)
Russ Cox4224d812015-03-20 00:06:10 -0400914 // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
915 // It needs to be removed in all three places.
916 // That would allow inlining x.(struct{*int}) the same as x.(*int).
Ian Lance Taylor9e902f02015-10-20 10:00:07 -0700917 if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
Russ Cox4224d812015-03-20 00:06:10 -0400918 // handled directly during gen.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800919 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700920 e.Left = walkexpr(e.Left, init)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200921 break
Russ Cox4224d812015-03-20 00:06:10 -0400922 }
923
924 // res, ok = i.(T)
925 // orderstmt made sure a is addressable.
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800926 init.AppendNodes(&n.Ninit)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700927
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800928 walkexprlistsafe(n.List.Slice(), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700929 e.Left = walkexpr(e.Left, init)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700930 t := e.Type // T
931 from := e.Left // i
Russ Cox8c195bd2015-02-13 14:40:36 -0500932
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700933 oktype := Types[TBOOL]
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800934 ok := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -0500935 if !isblank(ok) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700936 oktype = ok.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500937 }
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700938
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000939 fromKind := from.Type.iet()
940 toKind := t.iet()
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700941
942 // Avoid runtime calls in a few cases of the form _, ok := i.(T).
943 // This is faster and shorter and allows the corresponding assertX2X2
944 // routines to skip nil checks on their last argument.
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800945 if isblank(n.List.First()) {
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700946 var fast *Node
947 switch {
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000948 case fromKind == 'E' && toKind == 'T':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700949 tab := Nod(OITAB, from, nil) // type:eface::tab:iface
950 typ := Nod(OCONVNOP, typename(t), nil)
951 typ.Type = Ptrto(Types[TUINTPTR])
952 fast = Nod(OEQ, tab, typ)
Brad Fitzpatricke3a9dca2016-03-04 22:02:27 +0000953 case fromKind == 'I' && toKind == 'E',
954 fromKind == 'E' && toKind == 'E':
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700955 tab := Nod(OITAB, from, nil)
Josh Bleecher Snyder6d448442015-03-19 09:49:25 -0700956 fast = Nod(ONE, nodnil(), tab)
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700957 }
958 if fast != nil {
Russ Cox4224d812015-03-20 00:06:10 -0400959 if Debug_typeassert > 0 {
960 Warn("type assertion (ok only) inlined")
961 }
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700962 n = Nod(OAS, ok, fast)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700963 n = typecheck(n, Etop)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +0200964 break
Josh Bleecher Snyder25e793d2015-03-17 15:14:31 -0700965 }
966 }
967
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700968 var resptr *Node // &res
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800969 if isblank(n.List.First()) {
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700970 resptr = nodnil()
971 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800972 resptr = Nod(OADDR, n.List.First(), nil)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700973 }
974 resptr.Etype = 1 // addr does not escape
975
Russ Cox4224d812015-03-20 00:06:10 -0400976 if Debug_typeassert > 0 {
977 Warn("type assertion not inlined")
978 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800979 fn := syslook(assertFuncName(from.Type, t, true))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700980 fn = substArgTypes(fn, from.Type, t)
Josh Bleecher Snyder55b45162015-03-17 13:56:29 -0700981 call := mkcall1(fn, oktype, init, typename(t), from, resptr)
982 n = Nod(OAS, ok, call)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700983 n = typecheck(n, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500984
Russ Cox4224d812015-03-20 00:06:10 -0400985 case ODOTTYPE, ODOTTYPE2:
986 if !isdirectiface(n.Type) || Isfat(n.Type) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +0200987 Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
Russ Cox4224d812015-03-20 00:06:10 -0400988 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700989 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500990
991 case OCONVIFACE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700992 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -0500993
Michel Lespinasse7427f2c2016-03-18 16:20:20 -0700994 // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
995 if isdirectiface(n.Left.Type) {
996 var t *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700997 if n.Type.IsEmptyInterface() {
Michel Lespinasse7427f2c2016-03-18 16:20:20 -0700998 t = typename(n.Left.Type)
999 } else {
1000 t = itabname(n.Left.Type, n.Type)
1001 }
1002 l := Nod(OEFACE, t, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001003 l.Type = n.Type
1004 l.Typecheck = n.Typecheck
1005 n = l
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001006 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001007 }
1008
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001009 var ll []*Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001010 if n.Type.IsEmptyInterface() {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001011 if !n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001012 ll = append(ll, typename(n.Left.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001013 }
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001014 } else {
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001015 if n.Left.Type.IsInterface() {
Michel Lespinasse859b63c2016-03-18 17:21:33 -07001016 ll = append(ll, typename(n.Type))
1017 } else {
1018 ll = append(ll, itabname(n.Left.Type, n.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -05001019 }
1020 }
1021
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001022 if n.Left.Type.IsInterface() {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001023 ll = append(ll, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001024 } else {
1025 // regular types are passed by reference to avoid C vararg calls
David Chaseffe7fbf2015-03-27 12:34:45 -04001026 // orderexpr arranged for n.Left to be a temporary for all
Russ Cox8c195bd2015-02-13 14:40:36 -05001027 // the conversions it could see. comparison of an interface
1028 // with a non-interface, especially in a switch on interface value
1029 // with non-interface cases, is not visible to orderstmt, so we
1030 // have to fall back on allocating a temp here.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001031 if islvalue(n.Left) {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001032 ll = append(ll, Nod(OADDR, n.Left, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001033 } else {
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001034 ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05001035 }
David Chase22701332015-03-27 11:21:14 -04001036 dowidth(n.Left.Type)
1037 r := nodnil()
1038 if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
1039 // Allocate stack buffer for value stored in interface.
1040 r = temp(n.Left.Type)
1041 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001042 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001043 init.Append(r)
David Chase22701332015-03-27 11:21:14 -04001044 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001045 r = typecheck(r, Erv)
David Chase22701332015-03-27 11:21:14 -04001046 }
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001047 ll = append(ll, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001048 }
1049
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001050 fn := syslook(convFuncName(n.Left.Type, n.Type))
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001051 if !n.Left.Type.IsInterface() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001052 fn = substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001053 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001054 fn = substArgTypes(fn, n.Left.Type, n.Type)
David Chase22701332015-03-27 11:21:14 -04001055 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001056 dowidth(fn.Type)
1057 n = Nod(OCALL, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001058 n.List.Set(ll)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001059 n = typecheck(n, Erv)
1060 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001061
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001062 case OCONV, OCONVNOP:
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07001063 if Thearch.LinkArch.Family == sys.ARM {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001064 if n.Left.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001065 if n.Type.Etype == TINT64 {
1066 n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001067 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001068 }
1069
1070 if n.Type.Etype == TUINT64 {
1071 n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001072 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001073 }
1074 }
1075
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001076 if n.Type.IsFloat() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001077 if n.Left.Type.Etype == TINT64 {
1078 n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001079 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001080 }
1081
1082 if n.Left.Type.Etype == TUINT64 {
1083 n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001084 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001085 }
1086 }
1087 }
1088
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001089 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001090
1091 case OANDNOT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001092 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001093 n.Op = OAND
1094 n.Right = Nod(OCOM, n.Right, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001095 n.Right = typecheck(n.Right, Erv)
1096 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001097
1098 case OMUL:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001099 n.Left = walkexpr(n.Left, init)
1100 n.Right = walkexpr(n.Right, init)
1101 n = walkmul(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001102
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001103 case ODIV, OMOD:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001104 n.Left = walkexpr(n.Left, init)
1105 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001106
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001107 // rewrite complex div into function call.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001108 et := n.Left.Type.Etype
Russ Cox8c195bd2015-02-13 14:40:36 -05001109
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001110 if Iscomplex[et] && n.Op == ODIV {
Russ Cox382b44e2015-02-23 16:07:24 -05001111 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001112 n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
1113 n = conv(n, t)
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001114 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001115 }
1116
1117 // Nothing to do for float divisions.
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001118 if Isfloat[et] {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001119 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001120 }
1121
1122 // Try rewriting as shifts or magic multiplies.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001123 n = walkdiv(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001124
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001125 // rewrite 64-bit div and mod into function calls
1126 // on 32-bit architectures.
Russ Cox8c195bd2015-02-13 14:40:36 -05001127 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001128 case OMOD, ODIV:
Russ Cox8c195bd2015-02-13 14:40:36 -05001129 if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001130 break opswitch
Russ Cox8c195bd2015-02-13 14:40:36 -05001131 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001132 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05001133 if et == TINT64 {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001134 fn = "int64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001135 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001136 fn = "uint64"
Russ Cox8c195bd2015-02-13 14:40:36 -05001137 }
1138 if n.Op == ODIV {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001139 fn += "div"
Russ Cox8c195bd2015-02-13 14:40:36 -05001140 } else {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001141 fn += "mod"
Russ Cox8c195bd2015-02-13 14:40:36 -05001142 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08001143 n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001144 }
1145
Russ Cox8c195bd2015-02-13 14:40:36 -05001146 case OINDEX:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001147 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001148
1149 // save the original node for bounds checking elision.
1150 // If it was a ODIV/OMOD walk might rewrite it.
Russ Cox382b44e2015-02-23 16:07:24 -05001151 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001152
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001153 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001154
1155 // if range of type cannot exceed static array bound,
1156 // disable bounds check.
Russ Coxdc7b54b2015-02-17 22:13:49 -05001157 if n.Bounded {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001158 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001159 }
Russ Cox382b44e2015-02-23 16:07:24 -05001160 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001161 if t != nil && t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001162 t = t.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05001163 }
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001164 if t.IsArray() {
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001165 n.Bounded = bounded(r, t.NumElem())
Russ Coxdc7b54b2015-02-17 22:13:49 -05001166 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001167 Warn("index bounds check elided")
1168 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001169 if Smallintconst(n.Right) && !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001170 Yyerror("index out of bounds")
1171 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001172 } else if Isconst(n.Left, CTSTR) {
Russ Cox81d58102015-05-27 00:47:05 -04001173 n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
Russ Coxdc7b54b2015-02-17 22:13:49 -05001174 if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001175 Warn("index bounds check elided")
1176 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001177 if Smallintconst(n.Right) {
1178 if !n.Bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -05001179 Yyerror("index out of bounds")
1180 } else {
1181 // replace "abc"[1] with 'b'.
1182 // delayed until now because "abc"[1] is not
1183 // an ideal constant.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001184 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05001185
Russ Cox81d58102015-05-27 00:47:05 -04001186 Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001187 n.Typecheck = 1
1188 }
1189 }
1190 }
1191
Russ Coxdc7b54b2015-02-17 22:13:49 -05001192 if Isconst(n.Right, CTINT) {
Robert Griesemer07749ae2016-03-21 10:52:03 -07001193 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 -05001194 Yyerror("index out of bounds")
1195 }
1196 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001197
1198 case OINDEXMAP:
1199 if n.Etype == 1 {
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001200 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001201 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001202 n.Left = walkexpr(n.Left, init)
1203 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001204
Russ Cox382b44e2015-02-23 16:07:24 -05001205 t := n.Left.Type
1206 p := ""
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001207 if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
Matthew Dempsky1c2bdfb2016-03-10 05:22:14 -08001208 switch algtype(t.Key()) {
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001209 case AMEM32:
Russ Cox8c195bd2015-02-13 14:40:36 -05001210 p = "mapaccess1_fast32"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001211 case AMEM64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001212 p = "mapaccess1_fast64"
Matthew Dempsky423b0cc2015-12-07 02:12:12 -08001213 case ASTRING:
Russ Cox8c195bd2015-02-13 14:40:36 -05001214 p = "mapaccess1_faststr"
1215 }
1216 }
1217
Russ Cox382b44e2015-02-23 16:07:24 -05001218 var key *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001219 if p != "" {
1220 // fast versions take key by value
1221 key = n.Right
1222 } else {
1223 // standard version takes key by reference.
1224 // orderexpr made sure key is addressable.
1225 key = Nod(OADDR, n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001226 p = "mapaccess1"
1227 }
1228
Keith Randall60fd32a2016-04-19 08:31:04 -07001229 if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
1230 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
1231 } else {
1232 p = "mapaccess1_fat"
1233 z := zeroaddr(w)
1234 n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
1235 }
Keith Randall3c1a4c12016-04-19 21:06:53 -07001236 n.NonNil = true // mapaccess always returns a non-nil pointer
Russ Cox8c195bd2015-02-13 14:40:36 -05001237 n = Nod(OIND, n, nil)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001238 n.Type = t.Val()
Russ Cox8c195bd2015-02-13 14:40:36 -05001239 n.Typecheck = 1
1240
Russ Cox8c195bd2015-02-13 14:40:36 -05001241 case ORECV:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001242 Fatalf("walkexpr ORECV") // should see inside OAS only
Russ Cox8c195bd2015-02-13 14:40:36 -05001243
Russ Coxd4472792015-05-06 12:35:53 -04001244 case OSLICE, OSLICEARR, OSLICESTR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001245 n.Left = walkexpr(n.Left, init)
1246 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001247 if n.Right.Left != nil && iszero(n.Right.Left) {
1248 // Reduce x[0:j] to x[:j].
1249 n.Right.Left = nil
1250 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001251 n.Right.Right = walkexpr(n.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001252 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001253
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001254 case OSLICE3, OSLICE3ARR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001255 n.Left = walkexpr(n.Left, init)
1256 n.Right.Left = walkexpr(n.Right.Left, init)
Russ Coxd4472792015-05-06 12:35:53 -04001257 if n.Right.Left != nil && iszero(n.Right.Left) {
1258 // Reduce x[0:j:k] to x[:j:k].
1259 n.Right.Left = nil
1260 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001261 n.Right.Right.Left = walkexpr(n.Right.Right.Left, init)
1262 n.Right.Right.Right = walkexpr(n.Right.Right.Right, init)
Russ Coxd4472792015-05-06 12:35:53 -04001263
1264 r := n.Right.Right.Right
1265 if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
1266 // Reduce x[i:j:cap(x)] to x[i:j].
1267 n.Right.Right = n.Right.Right.Left
1268 if n.Op == OSLICE3 {
1269 n.Op = OSLICE
1270 } else {
1271 n.Op = OSLICEARR
1272 }
1273 n = reduceSlice(n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001274 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001275
1276 case OADDR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001277 n.Left = walkexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001278
1279 case ONEW:
David Chasee5060c72015-05-20 15:16:34 -04001280 if n.Esc == EscNone {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001281 if n.Type.Elem().Width >= 1<<16 {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001282 Fatalf("large ONEW with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001283 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001284 r := temp(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001285 r = Nod(OAS, r, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001286 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001287 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001288 r = Nod(OADDR, r.Left, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001289 r = typecheck(r, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001290 n = r
1291 } else {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001292 n = callnew(n.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05001293 }
1294
Russ Cox8c195bd2015-02-13 14:40:36 -05001295 // If one argument to the comparison is an empty string,
1296 // comparing the lengths instead will yield the same result
1297 // without the function call.
1298 case OCMPSTR:
Russ Cox81d58102015-05-27 00:47:05 -04001299 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 +02001300 // TODO(marvin): Fix Node.EType type union.
1301 r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001302 r = typecheck(r, Erv)
1303 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001304 r.Type = n.Type
1305 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001306 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001307 }
1308
1309 // s + "badgerbadgerbadger" == "badgerbadgerbadger"
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001310 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 +02001311 // TODO(marvin): Fix Node.EType type union.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001312 r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001313 r = typecheck(r, Erv)
1314 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001315 r.Type = n.Type
1316 n = r
HĂ¥vard Haugen9238cbd2015-09-20 23:28:34 +02001317 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001318 }
1319
Russ Cox382b44e2015-02-23 16:07:24 -05001320 var r *Node
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001321 // TODO(marvin): Fix Node.EType type union.
1322 if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001323 // prepare for rewrite below
1324 n.Left = cheapexpr(n.Left, init)
1325
1326 n.Right = cheapexpr(n.Right, init)
1327
1328 r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1329
1330 // quick check of len before full compare for == or !=
1331 // eqstring assumes that the lengths are equal
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001332 // TODO(marvin): Fix Node.EType type union.
1333 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001334 // len(left) == len(right) && eqstring(left, right)
1335 r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1336 } else {
1337 // len(left) != len(right) || !eqstring(left, right)
1338 r = Nod(ONOT, r, nil)
1339
1340 r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
1341 }
1342
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001343 r = typecheck(r, Erv)
1344 r = walkexpr(r, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05001345 } else {
1346 // sys_cmpstring(s1, s2) :: 0
1347 r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
1348
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001349 // TODO(marvin): Fix Node.EType type union.
1350 r = Nod(Op(n.Etype), r, Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -05001351 }
1352
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001353 r = typecheck(r, Erv)
Matthew Dempsky3efefd92016-03-30 14:56:08 -07001354 if !n.Type.IsBoolean() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001355 Fatalf("cmp %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001356 }
1357 r.Type = n.Type
1358 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001359
1360 case OADDSTR:
1361 n = addstr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001362
1363 case OAPPEND:
Russ Cox85520472015-05-06 12:34:30 -04001364 // order should make sure we only see OAS(node, OAPPEND), which we handle above.
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001365 Fatalf("append outside assignment")
Russ Cox8c195bd2015-02-13 14:40:36 -05001366
1367 case OCOPY:
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07001368 n = copyany(n, init, instrumenting)
Russ Cox8c195bd2015-02-13 14:40:36 -05001369
1370 // cannot use chanfn - closechan takes any, not chan any
1371 case OCLOSE:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001372 fn := syslook("closechan")
Russ Cox8c195bd2015-02-13 14:40:36 -05001373
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001374 fn = substArgTypes(fn, n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001375 n = mkcall1(fn, nil, init, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001376
1377 case OMAKECHAN:
1378 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 -05001379
1380 case OMAKEMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001381 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001382
Russ Cox382b44e2015-02-23 16:07:24 -05001383 a := nodnil() // hmap buffer
1384 r := nodnil() // bucket buffer
Russ Cox8c195bd2015-02-13 14:40:36 -05001385 if n.Esc == EscNone {
1386 // Allocate hmap buffer on stack.
Matthew Dempsky98779002016-02-23 07:46:01 +00001387 var_ := temp(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001388
1389 a = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001390 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001391 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001392 a = Nod(OADDR, var_, nil)
1393
1394 // Allocate one bucket on stack.
1395 // Maximum key/value size is 128 bytes, larger objects
1396 // are stored with an indirection. So max bucket size is 2048+eps.
1397 var_ = temp(mapbucket(t))
1398
1399 r = Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001400 r = typecheck(r, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001401 init.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001402 r = Nod(OADDR, var_, nil)
1403 }
1404
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001405 fn := syslook("makemap")
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07001406 fn = substArgTypes(fn, hmap(t), mapbucket(t), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05001407 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001408
1409 case OMAKESLICE:
Russ Cox382b44e2015-02-23 16:07:24 -05001410 l := n.Left
1411 r := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05001412 if r == nil {
1413 r = safeexpr(l, init)
1414 l = r
1415 }
Russ Cox382b44e2015-02-23 16:07:24 -05001416 t := n.Type
David Chasee5060c72015-05-20 15:16:34 -04001417 if n.Esc == EscNone {
1418 if !isSmallMakeSlice(n) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001419 Fatalf("non-small OMAKESLICE with EscNone: %v", n)
David Chasee5060c72015-05-20 15:16:34 -04001420 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001421 // var arr [r]T
1422 // n = arr[:l]
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001423 t = aindex(r, t.Elem()) // [r]T
Russ Cox382b44e2015-02-23 16:07:24 -05001424 var_ := temp(t)
1425 a := Nod(OAS, var_, nil) // zero temp
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001426 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001427 init.Append(a)
Russ Cox382b44e2015-02-23 16:07:24 -05001428 r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
David Chaseffe7fbf2015-03-27 12:34:45 -04001429 r = conv(r, n.Type) // in case n.Type is named.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001430 r = typecheck(r, Erv)
1431 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001432 n = r
1433 } else {
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001434 // makeslice(et *Type, nel int64, max int64) (ary []any)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001435 fn := syslook("makeslice")
Russ Cox8c195bd2015-02-13 14:40:36 -05001436
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001437 fn = substArgTypes(fn, t.Elem()) // any-1
Keith Randallbfe0cbd2016-04-19 15:38:59 -07001438 n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001439 }
1440
Russ Cox8c195bd2015-02-13 14:40:36 -05001441 case ORUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001442 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001443 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05001444 t := aindex(Nodintconst(4), Types[TUINT8])
1445 var_ := temp(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001446 a = Nod(OADDR, var_, nil)
1447 }
1448
1449 // intstring(*[4]byte, rune)
1450 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
1451
Russ Cox8c195bd2015-02-13 14:40:36 -05001452 case OARRAYBYTESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001453 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001454 if n.Esc == EscNone {
1455 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001456 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001457
1458 a = Nod(OADDR, temp(t), nil)
1459 }
1460
1461 // slicebytetostring(*[32]byte, []byte) string;
1462 n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
1463
Russ Cox8c195bd2015-02-13 14:40:36 -05001464 // slicebytetostringtmp([]byte) string;
1465 case OARRAYBYTESTRTMP:
1466 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
1467
Russ Cox8c195bd2015-02-13 14:40:36 -05001468 // slicerunetostring(*[32]byte, []rune) string;
1469 case OARRAYRUNESTR:
Russ Cox382b44e2015-02-23 16:07:24 -05001470 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001471
1472 if n.Esc == EscNone {
1473 // Create temporary buffer for string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001474 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001475
1476 a = Nod(OADDR, temp(t), nil)
1477 }
1478
1479 n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001480
1481 // stringtoslicebyte(*32[byte], string) []byte;
1482 case OSTRARRAYBYTE:
Russ Cox382b44e2015-02-23 16:07:24 -05001483 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001484
1485 if n.Esc == EscNone {
1486 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001487 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05001488
1489 a = Nod(OADDR, temp(t), nil)
1490 }
1491
1492 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05001493
1494 // stringtoslicebytetmp(string) []byte;
1495 case OSTRARRAYBYTETMP:
1496 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
1497
Russ Cox8c195bd2015-02-13 14:40:36 -05001498 // stringtoslicerune(*[32]rune, string) []rune
1499 case OSTRARRAYRUNE:
Russ Cox382b44e2015-02-23 16:07:24 -05001500 a := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05001501
1502 if n.Esc == EscNone {
1503 // Create temporary buffer for slice on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05001504 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
Russ Cox8c195bd2015-02-13 14:40:36 -05001505
1506 a = Nod(OADDR, temp(t), nil)
1507 }
1508
1509 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05001510
1511 // ifaceeq(i1 any-1, i2 any-2) (ret bool);
1512 case OCMPIFACE:
1513 if !Eqtype(n.Left.Type, n.Right.Type) {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08001514 Fatalf("ifaceeq %v %v %v", Oconv(n.Op, 0), n.Left.Type, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001515 }
Russ Cox382b44e2015-02-23 16:07:24 -05001516 var fn *Node
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001517 if n.Left.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001518 fn = syslook("efaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001519 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001520 fn = syslook("ifaceeq")
Russ Cox8c195bd2015-02-13 14:40:36 -05001521 }
1522
1523 n.Right = cheapexpr(n.Right, init)
1524 n.Left = cheapexpr(n.Left, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001525 fn = substArgTypes(fn, n.Right.Type, n.Left.Type)
Russ Cox382b44e2015-02-23 16:07:24 -05001526 r := mkcall1(fn, n.Type, init, n.Left, n.Right)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001527 // TODO(marvin): Fix Node.EType type union.
1528 if Op(n.Etype) == ONE {
Russ Cox8c195bd2015-02-13 14:40:36 -05001529 r = Nod(ONOT, r, nil)
1530 }
1531
1532 // check itable/type before full compare.
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001533 // TODO(marvin): Fix Node.EType type union.
1534 if Op(n.Etype) == OEQ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001535 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1536 } else {
1537 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
1538 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001539 r = typecheck(r, Erv)
1540 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001541 r.Type = n.Type
1542 n = r
Russ Cox8c195bd2015-02-13 14:40:36 -05001543
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001544 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
Josh Bleecher Snyder3c6e60c2016-04-19 12:08:33 -07001545 if isStaticCompositeLiteral(n) {
Keith Randallb024ed02016-04-18 11:17:55 -07001546 // n can be directly represented in the read-only data section.
1547 // Make direct reference to the static data. See issue 12841.
1548 vstat := staticname(n.Type, 0)
1549 if n.Op == OSTRUCTLIT {
1550 structlit(0, 1, n, vstat, init)
1551 } else {
1552 arraylit(0, 1, n, vstat, init)
1553 }
1554 n = vstat
1555 n = typecheck(n, Erv)
1556 break
1557 }
Russ Cox382b44e2015-02-23 16:07:24 -05001558 var_ := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001559 anylit(0, n, var_, init)
1560 n = var_
Russ Cox8c195bd2015-02-13 14:40:36 -05001561
1562 case OSEND:
Russ Cox382b44e2015-02-23 16:07:24 -05001563 n1 := n.Right
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001564 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001565 n1 = walkexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001566 n1 = Nod(OADDR, n1, nil)
1567 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001568
1569 case OCLOSURE:
1570 n = walkclosure(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001571
1572 case OCALLPART:
1573 n = walkpartialcall(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001574 }
1575
Russ Cox8c195bd2015-02-13 14:40:36 -05001576 // Expressions that are constant at run time but not
1577 // considered const by the language spec are not turned into
1578 // constants until walk. For example, if n is y%1 == 0, the
1579 // walk of y%1 may have replaced it by 0.
1580 // Check whether n with its updated args is itself now a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05001581 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001582
1583 evconst(n)
1584 n.Type = t
1585 if n.Op == OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001586 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001587 }
1588
1589 ullmancalc(n)
1590
1591 if Debug['w'] != 0 && n != nil {
1592 Dump("walk", n)
1593 }
1594
1595 lineno = lno
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001596 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05001597}
1598
Russ Coxd4472792015-05-06 12:35:53 -04001599func reduceSlice(n *Node) *Node {
1600 r := n.Right.Right
1601 if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
1602 // Reduce x[i:len(x)] to x[i:].
1603 n.Right.Right = nil
1604 }
1605 if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
1606 // Reduce x[:] to x.
1607 if Debug_slice > 0 {
1608 Warn("slice: omit slice operation")
1609 }
1610 return n.Left
1611 }
1612 return n
1613}
1614
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001615func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001616 // convas will turn map assigns into function calls,
1617 // making it impossible for reorder3 to work.
Russ Cox382b44e2015-02-23 16:07:24 -05001618 n := Nod(OAS, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001619
1620 if l.Op == OINDEXMAP {
1621 return n
1622 }
1623
1624 return convas(n, init)
1625}
1626
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001627func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001628 // check assign expression list to
1629 // a expression list. called in
1630 // expr-list = expr-list
Russ Cox8c195bd2015-02-13 14:40:36 -05001631
1632 // ensure order of evaluation for function calls
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001633 for i := range nl {
1634 nl[i] = safeexpr(nl[i], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001635 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001636 for i1 := range nr {
1637 nr[i1] = safeexpr(nr[i1], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001638 }
1639
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001640 var nn []*Node
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001641 i := 0
1642 for ; i < len(nl); i++ {
1643 if i >= len(nr) {
1644 break
1645 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001646 // Do not generate 'x = x' during return. See issue 4014.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001647 if op == ORETURN && nl[i] == nr[i] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001648 continue
1649 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001650 nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001651 }
1652
1653 // cannot happen: caller checked that lists had same length
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001654 if i < len(nl) || i < len(nr) {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001655 var nln, nrn Nodes
1656 nln.Set(nl)
1657 nrn.Set(nr)
Matthew Dempsky63142022016-03-15 13:06:58 -07001658 Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nln, FmtSign), Oconv(op, 0), Hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -05001659 }
1660 return nn
1661}
1662
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001663// l is an lv and rt is the type of an rv
1664// return 1 if this implies a function call
1665// evaluating the lv or a function call
1666// in the conversion of the types
Russ Coxdc7b54b2015-02-17 22:13:49 -05001667func fncall(l *Node, rt *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001668 if l.Ullman >= UINF || l.Op == OINDEXMAP {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001669 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001670 }
Russ Cox175929b2015-03-02 14:22:05 -05001671 var r Node
Russ Coxdc7b54b2015-02-17 22:13:49 -05001672 if needwritebarrier(l, &r) {
1673 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001674 }
1675 if Eqtype(l.Type, rt) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001676 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001677 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001678 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001679}
1680
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001681// check assign type list to
1682// a expression list. called in
1683// expr-list = func()
1684func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
1685 r, saver := IterFields(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -05001686
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001687 var nn, mm []*Node
1688 var ullmanOverflow bool
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001689 var i int
1690 for i = 0; i < nl.Len(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001691 if r == nil {
1692 break
1693 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001694 l := nl.Index(i)
Russ Cox8c195bd2015-02-13 14:40:36 -05001695 if isblank(l) {
Matthew Dempsky7758a942016-03-08 15:02:40 -08001696 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001697 continue
1698 }
1699
1700 // any lv that causes a fn call must be
1701 // deferred until all the return arguments
1702 // have been pulled from the output arguments
Russ Coxdc7b54b2015-02-17 22:13:49 -05001703 if fncall(l, r.Type) {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001704 tmp := temp(r.Type)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001705 tmp = typecheck(tmp, Erv)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001706 a := Nod(OAS, l, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001707 a = convas(a, init)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001708 mm = append(mm, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001709 l = tmp
1710 }
1711
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001712 a := Nod(OAS, l, nodarg(r, fp))
Russ Cox8c195bd2015-02-13 14:40:36 -05001713 a = convas(a, init)
1714 ullmancalc(a)
1715 if a.Ullman >= UINF {
1716 Dump("ascompatet ucount", a)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001717 ullmanOverflow = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001718 }
1719
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001720 nn = append(nn, a)
Matthew Dempsky7758a942016-03-08 15:02:40 -08001721 r = saver.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001722 }
1723
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001724 if i < nl.Len() || r != nil {
Matthew Dempskydbed1c62016-03-17 13:26:08 -07001725 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
Russ Cox8c195bd2015-02-13 14:40:36 -05001726 }
1727
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001728 if ullmanOverflow {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001729 Fatalf("ascompatet: too many function calls evaluating parameters")
Russ Cox8c195bd2015-02-13 14:40:36 -05001730 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001731 return append(nn, mm...)
Russ Cox8c195bd2015-02-13 14:40:36 -05001732}
1733
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001734// package all the arguments that match a ... T parameter into a []T.
Matthew Dempsky2e936902016-03-14 01:20:49 -07001735func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
David Chase7fbb1b32015-03-26 16:36:15 -04001736 esc := uint16(EscUnknown)
Russ Cox8c195bd2015-02-13 14:40:36 -05001737 if ddd != nil {
Dave Cheneye4981812015-03-10 09:58:01 +11001738 esc = ddd.Esc
Russ Cox8c195bd2015-02-13 14:40:36 -05001739 }
1740
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001741 tslice := typSlice(l.Type.Elem())
Josh Bleecher Snyderb6b144b2015-05-04 15:01:29 -07001742 tslice.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -05001743
Russ Cox382b44e2015-02-23 16:07:24 -05001744 var n *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001745 if len(lr0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001746 n = nodnil()
1747 n.Type = tslice
1748 } else {
1749 n = Nod(OCOMPLIT, nil, typenod(tslice))
Russ Cox60e5f5b2015-05-26 23:05:35 -04001750 if ddd != nil && prealloc[ddd] != nil {
1751 prealloc[n] = prealloc[ddd] // temporary to use
Russ Cox8c195bd2015-02-13 14:40:36 -05001752 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001753 n.List.Set(lr0)
Dave Cheneye4981812015-03-10 09:58:01 +11001754 n.Esc = esc
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001755 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05001756 if n.Type == nil {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02001757 Fatalf("mkdotargslice: typecheck failed")
Russ Cox8c195bd2015-02-13 14:40:36 -05001758 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001759 n = walkexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001760 }
1761
Russ Cox382b44e2015-02-23 16:07:24 -05001762 a := Nod(OAS, nodarg(l, fp), n)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001763 nn = append(nn, convas(a, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001764 return nn
1765}
1766
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001767// helpers for shape errors
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001768func dumptypes(nl *Type, what string) string {
1769 s := ""
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001770 for _, l := range nl.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001771 if s != "" {
1772 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001773 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07001774 s += Fldconv(l, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001775 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001776 if s == "" {
1777 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001778 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001779 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001780}
1781
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001782func dumpnodetypes(l []*Node, what string) string {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001783 s := ""
1784 for _, r := range l {
1785 if s != "" {
1786 s += ", "
Russ Cox8c195bd2015-02-13 14:40:36 -05001787 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001788 s += Tconv(r.Type, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -05001789 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001790 if s == "" {
1791 s = fmt.Sprintf("[no arguments %s]", what)
Russ Cox8c195bd2015-02-13 14:40:36 -05001792 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001793 return s
Russ Cox8c195bd2015-02-13 14:40:36 -05001794}
1795
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09001796// check assign expression list to
1797// a type list. called in
1798// return expr-list
1799// func(expr-list)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001800func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05001801 lr0 := lr
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001802 l, savel := IterFields(nl)
Russ Cox175929b2015-03-02 14:22:05 -05001803 var r *Node
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001804 if len(lr) > 0 {
1805 r = lr[0]
Russ Cox8c195bd2015-02-13 14:40:36 -05001806 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001807 var nn []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001808
1809 // f(g()) where g has multiple return values
Josh Bleecher Snyderfda831e2016-04-05 16:44:07 -07001810 if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001811 // optimization - can do block copy
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001812 if eqtypenoname(r.Type, nl) {
1813 arg := nodarg(nl, fp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001814 r = Nod(OCONVNOP, r, nil)
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001815 r.Type = arg.Type
1816 nn = []*Node{convas(Nod(OAS, arg, r), init)}
Russ Cox8c195bd2015-02-13 14:40:36 -05001817 goto ret
1818 }
1819
1820 // conversions involved.
1821 // copy into temporaries.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001822 var alist []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001823
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001824 for _, l := range r.Type.Fields().Slice() {
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001825 tmp := temp(l.Type)
1826 alist = append(alist, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -05001827 }
1828
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001829 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001830 a.List.Set(alist)
1831 a.Rlist.Set(lr)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001832 a = typecheck(a, Etop)
1833 a = walkstmt(a)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001834 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05001835 lr = alist
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08001836 r = lr[0]
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001837 l, savel = IterFields(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -05001838 }
1839
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001840 for {
1841 if l != nil && l.Isddd {
1842 // the ddd parameter must be last
1843 ll := savel.Next()
Russ Cox8c195bd2015-02-13 14:40:36 -05001844
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001845 if ll != nil {
1846 Yyerror("... must be last argument")
Russ Cox8c195bd2015-02-13 14:40:36 -05001847 }
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001848
1849 // special case --
1850 // only if we are assigning a single ddd
1851 // argument to a ddd parameter then it is
Eric Engestrom7a8caf72016-04-03 12:43:27 +01001852 // passed through unencapsulated
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001853 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
1854 a := Nod(OAS, nodarg(l, fp), r)
1855 a = convas(a, init)
1856 nn = append(nn, a)
1857 break
1858 }
1859
1860 // normal case -- make a slice of all
1861 // remaining arguments and pass it to
1862 // the ddd parameter.
1863 nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
1864
1865 break
Russ Cox8c195bd2015-02-13 14:40:36 -05001866 }
1867
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001868 if l == nil || r == nil {
1869 if l != nil || r != nil {
1870 l1 := dumptypes(nl, "expected")
1871 l2 := dumpnodetypes(lr0, "given")
1872 if l != nil {
1873 Yyerror("not enough arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
1874 } else {
1875 Yyerror("too many arguments to %v\n\t%s\n\t%s", Oconv(op, 0), l1, l2)
1876 }
1877 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001878
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001879 break
1880 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001881
Matthew Dempskyd20b92e2016-03-09 19:32:10 -08001882 a := Nod(OAS, nodarg(l, fp), r)
1883 a = convas(a, init)
1884 nn = append(nn, a)
1885
1886 l = savel.Next()
1887 r = nil
1888 lr = lr[1:]
1889 if len(lr) > 0 {
1890 r = lr[0]
1891 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001892 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001893
1894ret:
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08001895 for _, n := range nn {
1896 n.Typecheck = 1
Russ Cox8c195bd2015-02-13 14:40:36 -05001897 }
1898 return nn
1899}
1900
1901// generate code for print
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001902func walkprint(nn *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05001903 var r *Node
1904 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001905 var on *Node
1906 var t *Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001907 var et EType
Russ Cox8c195bd2015-02-13 14:40:36 -05001908
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001909 op := nn.Op
Russ Cox382b44e2015-02-23 16:07:24 -05001910 all := nn.List
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001911 var calls []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05001912 notfirst := false
Russ Cox8c195bd2015-02-13 14:40:36 -05001913
1914 // Hoist all the argument evaluation up before the lock.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001915 walkexprlistcheap(all.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05001916
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001917 calls = append(calls, mkcall("printlock", nil, init))
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001918 for i1, n1 := range all.Slice() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001919 if notfirst {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001920 calls = append(calls, mkcall("printsp", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05001921 }
1922
Russ Coxdc7b54b2015-02-17 22:13:49 -05001923 notfirst = op == OPRINTN
Russ Cox8c195bd2015-02-13 14:40:36 -05001924
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001925 n = n1
Russ Cox8c195bd2015-02-13 14:40:36 -05001926 if n.Op == OLITERAL {
Russ Cox81d58102015-05-27 00:47:05 -04001927 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001928 case CTRUNE:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001929 n = defaultlit(n, runetype)
Russ Cox8c195bd2015-02-13 14:40:36 -05001930
1931 case CTINT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001932 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05001933
1934 case CTFLT:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001935 n = defaultlit(n, Types[TFLOAT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05001936 }
1937 }
1938
1939 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001940 n = defaultlit(n, Types[TINT64])
Russ Cox8c195bd2015-02-13 14:40:36 -05001941 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001942 n = defaultlit(n, nil)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08001943 all.SetIndex(i1, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05001944 if n.Type == nil || n.Type.Etype == TFORW {
1945 continue
1946 }
1947
1948 t = n.Type
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001949 et = n.Type.Etype
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001950 if n.Type.IsInterface() {
Matthew Dempsky00e5a682016-04-01 13:36:24 -07001951 if n.Type.IsEmptyInterface() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001952 on = syslook("printeface")
Russ Cox8c195bd2015-02-13 14:40:36 -05001953 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001954 on = syslook("printiface")
Russ Cox8c195bd2015-02-13 14:40:36 -05001955 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001956 on = substArgTypes(on, n.Type) // any-1
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001957 } else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001958 on = syslook("printpointer")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001959 on = substArgTypes(on, n.Type) // any-1
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07001960 } else if n.Type.IsSlice() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001961 on = syslook("printslice")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07001962 on = substArgTypes(on, n.Type) // any-1
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001963 } else if Isint[et] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001964 if et == TUINT64 {
Matthew Dempsky980ab122016-04-13 18:37:18 -07001965 if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001966 on = syslook("printhex")
Russ Cox8c195bd2015-02-13 14:40:36 -05001967 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001968 on = syslook("printuint")
Russ Cox8c195bd2015-02-13 14:40:36 -05001969 }
1970 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001971 on = syslook("printint")
Russ Cox8c195bd2015-02-13 14:40:36 -05001972 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001973 } else if Isfloat[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001974 on = syslook("printfloat")
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001975 } else if Iscomplex[et] {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001976 on = syslook("printcomplex")
Russ Cox8c195bd2015-02-13 14:40:36 -05001977 } else if et == TBOOL {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001978 on = syslook("printbool")
Russ Cox8c195bd2015-02-13 14:40:36 -05001979 } else if et == TSTRING {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08001980 on = syslook("printstring")
Russ Cox8c195bd2015-02-13 14:40:36 -05001981 } else {
1982 badtype(OPRINT, n.Type, nil)
1983 continue
1984 }
1985
Matthew Dempsky0d2e92c2016-03-13 23:02:38 -07001986 t = on.Type.Params().Field(0).Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001987
1988 if !Eqtype(t, n.Type) {
1989 n = Nod(OCONV, n, nil)
1990 n.Type = t
1991 }
1992
1993 r = Nod(OCALL, on, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08001994 r.List.Append(n)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001995 calls = append(calls, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05001996 }
1997
1998 if op == OPRINTN {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08001999 calls = append(calls, mkcall("printnl", nil, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002000 }
2001
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002002 calls = append(calls, mkcall("printunlock", nil, init))
Russ Cox8c195bd2015-02-13 14:40:36 -05002003
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002004 typecheckslice(calls, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002005 walkexprlist(calls, init)
2006
2007 r = Nod(OEMPTY, nil, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002008 r = typecheck(r, Etop)
2009 r = walkexpr(r, init)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002010 r.Ninit.Set(calls)
Russ Cox8c195bd2015-02-13 14:40:36 -05002011 return r
2012}
2013
2014func callnew(t *Type) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002015 dowidth(t)
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002016 fn := syslook("newobject")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002017 fn = substArgTypes(fn, t)
Keith Randall3c1a4c12016-04-19 21:06:53 -07002018 v := mkcall1(fn, Ptrto(t), nil, typename(t))
2019 v.NonNil = true
2020 return v
Russ Cox8c195bd2015-02-13 14:40:36 -05002021}
2022
Russ Cox3b6e86f2015-06-29 15:17:14 -04002023func iscallret(n *Node) bool {
2024 n = outervalue(n)
2025 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
2026}
2027
Russ Coxdc7b54b2015-02-17 22:13:49 -05002028func isstack(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002029 n = outervalue(n)
2030
2031 // If n is *autotmp and autotmp = &foo, replace n with foo.
2032 // We introduce such temps when initializing struct literals.
2033 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
Russ Cox4fdd5362015-05-26 22:19:27 -04002034 defn := n.Left.Name.Defn
Russ Cox8c195bd2015-02-13 14:40:36 -05002035 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
2036 n = defn.Right.Left
2037 }
2038 }
2039
2040 switch n.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -05002041 case OINDREG:
Russ Cox85520472015-05-06 12:34:30 -04002042 return n.Reg == int16(Thearch.REGSP)
Russ Cox8c195bd2015-02-13 14:40:36 -05002043
2044 case ONAME:
2045 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002046 case PAUTO, PPARAM, PPARAMOUT:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002047 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002048 }
2049 }
2050
Russ Coxdc7b54b2015-02-17 22:13:49 -05002051 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002052}
2053
Russ Coxdc7b54b2015-02-17 22:13:49 -05002054func isglobal(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002055 n = outervalue(n)
2056
2057 switch n.Op {
2058 case ONAME:
2059 switch n.Class {
2060 case PEXTERN:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002061 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002062 }
2063 }
2064
Russ Coxdc7b54b2015-02-17 22:13:49 -05002065 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002066}
2067
2068// Do we need a write barrier for the assignment l = r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002069func needwritebarrier(l *Node, r *Node) bool {
Matthew Dempsky980ab122016-04-13 18:37:18 -07002070 if !use_writebarrier {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002071 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002072 }
2073
2074 if l == nil || isblank(l) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002075 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002076 }
2077
2078 // No write barrier for write of non-pointers.
2079 dowidth(l.Type)
2080
2081 if !haspointers(l.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002082 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002083 }
2084
2085 // No write barrier for write to stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002086 if isstack(l) {
2087 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002088 }
2089
Russ Cox9f90f312015-06-29 12:49:25 -04002090 // No write barrier for implicit zeroing.
2091 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002092 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002093 }
2094
Russ Cox9f90f312015-06-29 12:49:25 -04002095 // Ignore no-op conversions when making decision.
2096 // Ensures that xp = unsafe.Pointer(&x) is treated
2097 // the same as xp = &x.
2098 for r.Op == OCONVNOP {
2099 r = r.Left
2100 }
2101
2102 // No write barrier for zeroing or initialization to constant.
2103 if iszero(r) || r.Op == OLITERAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002104 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002105 }
2106
2107 // No write barrier for storing static (read-only) data.
2108 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002109 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002110 }
2111
2112 // No write barrier for storing address of stack values,
2113 // which are guaranteed only to be written to the stack.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002114 if r.Op == OADDR && isstack(r.Left) {
2115 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002116 }
2117
2118 // No write barrier for storing address of global, which
2119 // is live no matter what.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002120 if r.Op == OADDR && isglobal(r.Left) {
2121 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002122 }
2123
Austin Clements3e54ca92016-03-16 18:22:58 -04002124 // No write barrier for storing global function, which is live
2125 // no matter what.
2126 if r.Op == ONAME && r.Class == PFUNC {
2127 return false
2128 }
2129
Russ Cox8c195bd2015-02-13 14:40:36 -05002130 // Otherwise, be conservative and use write barrier.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002131 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002132}
2133
2134// TODO(rsc): Perhaps componentgen should run before this.
2135
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002136func applywritebarrier(n *Node) *Node {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002137 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
Russ Cox972a4782015-05-21 15:00:06 -04002138 if Debug_wb > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002139 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002140 }
Russ Cox972a4782015-05-21 15:00:06 -04002141 n.Op = OASWB
2142 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002143 }
Russ Cox8c195bd2015-02-13 14:40:36 -05002144 return n
2145}
2146
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002147func convas(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002148 if n.Op != OAS {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002149 Fatalf("convas: not OAS %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05002150 }
2151
2152 n.Typecheck = 1
2153
Russ Cox382b44e2015-02-23 16:07:24 -05002154 var lt *Type
2155 var rt *Type
Russ Cox8c195bd2015-02-13 14:40:36 -05002156 if n.Left == nil || n.Right == nil {
2157 goto out
2158 }
2159
2160 lt = n.Left.Type
2161 rt = n.Right.Type
2162 if lt == nil || rt == nil {
2163 goto out
2164 }
2165
2166 if isblank(n.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002167 n.Right = defaultlit(n.Right, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002168 goto out
2169 }
2170
2171 if n.Left.Op == OINDEXMAP {
Russ Cox382b44e2015-02-23 16:07:24 -05002172 map_ := n.Left.Left
2173 key := n.Left.Right
2174 val := n.Right
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002175 map_ = walkexpr(map_, init)
2176 key = walkexpr(key, init)
2177 val = walkexpr(val, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002178
2179 // orderexpr made sure key and val are addressable.
2180 key = Nod(OADDR, key, nil)
2181
2182 val = Nod(OADDR, val, nil)
2183 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
2184 goto out
2185 }
2186
2187 if !Eqtype(lt, rt) {
2188 n.Right = assignconv(n.Right, lt, "assignment")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002189 n.Right = walkexpr(n.Right, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002190 }
2191
2192out:
2193 ullmancalc(n)
2194 return n
2195}
2196
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002197// from ascompat[te]
2198// evaluating actual function arguments.
2199// f(a,b)
2200// if there is exactly one function expr,
2201// then it is done first. otherwise must
2202// make temp variables
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002203func reorder1(all []*Node) []*Node {
Russ Cox382b44e2015-02-23 16:07:24 -05002204 c := 0 // function calls
2205 t := 0 // total parameters
Russ Cox8c195bd2015-02-13 14:40:36 -05002206
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002207 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002208 t++
2209 ullmancalc(n)
2210 if n.Ullman >= UINF {
2211 c++
2212 }
2213 }
2214
2215 if c == 0 || t == 1 {
2216 return all
2217 }
2218
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002219 var g []*Node // fncalls assigned to tempnames
2220 var f *Node // last fncall assigned to stack
2221 var r []*Node // non fncalls and tempnames assigned to stack
Russ Cox382b44e2015-02-23 16:07:24 -05002222 d := 0
2223 var a *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002224 for _, n := range all {
Russ Cox8c195bd2015-02-13 14:40:36 -05002225 if n.Ullman < UINF {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002226 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002227 continue
2228 }
2229
2230 d++
2231 if d == c {
2232 f = n
2233 continue
2234 }
2235
2236 // make assignment of fncall to tempname
2237 a = temp(n.Right.Type)
2238
2239 a = Nod(OAS, a, n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002240 g = append(g, a)
Russ Cox8c195bd2015-02-13 14:40:36 -05002241
2242 // put normal arg assignment on list
2243 // with fncall replaced by tempname
2244 n.Right = a.Left
2245
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002246 r = append(r, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002247 }
2248
2249 if f != nil {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002250 g = append(g, f)
Russ Cox8c195bd2015-02-13 14:40:36 -05002251 }
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08002252 return append(g, r...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002253}
2254
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002255// from ascompat[ee]
2256// a,b = c,d
2257// simultaneous assignment. there cannot
2258// be later use of an earlier lvalue.
2259//
2260// function calls have been removed.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002261func reorder3(all []*Node) []*Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002262 var l *Node
2263
2264 // If a needed expression may be affected by an
2265 // earlier assignment, make an early copy of that
2266 // expression and use the copy instead.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002267 var early []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002268
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002269 var mapinit Nodes
2270 for i, n := range all {
2271 l = n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002272
2273 // Save subexpressions needed on left side.
2274 // Drill through non-dereferences.
2275 for {
2276 if l.Op == ODOT || l.Op == OPAREN {
2277 l = l.Left
2278 continue
2279 }
2280
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002281 if l.Op == OINDEX && l.Left.Type.IsArray() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002282 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002283 l = l.Left
2284 continue
2285 }
2286
2287 break
2288 }
2289
2290 switch l.Op {
2291 default:
Matthew Dempsky63142022016-03-15 13:06:58 -07002292 Fatalf("reorder3 unexpected lvalue %v", Oconv(l.Op, FmtSharp))
Russ Cox8c195bd2015-02-13 14:40:36 -05002293
2294 case ONAME:
2295 break
2296
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002297 case OINDEX, OINDEXMAP:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002298 l.Left = reorder3save(l.Left, all, i, &early)
2299 l.Right = reorder3save(l.Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002300 if l.Op == OINDEXMAP {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002301 all[i] = convas(all[i], &mapinit)
Russ Cox8c195bd2015-02-13 14:40:36 -05002302 }
2303
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002304 case OIND, ODOTPTR:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002305 l.Left = reorder3save(l.Left, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002306 }
2307
2308 // Save expression on right side.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002309 all[i].Right = reorder3save(all[i].Right, all, i, &early)
Russ Cox8c195bd2015-02-13 14:40:36 -05002310 }
2311
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002312 early = append(mapinit.Slice(), early...)
2313 return append(early, all...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002314}
2315
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002316// if the evaluation of *np would be affected by the
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002317// assignments in all up to but not including the ith assignment,
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002318// copy into a temporary during *early and
2319// replace *np with that temp.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002320// The result of reorder3save MUST be assigned back to n, e.g.
2321// n.Left = reorder3save(n.Left, all, i, early)
2322func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002323 if !aliased(n, all, i) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002324 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05002325 }
2326
Russ Cox382b44e2015-02-23 16:07:24 -05002327 q := temp(n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002328 q = Nod(OAS, q, n)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002329 q = typecheck(q, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002330 *early = append(*early, q)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002331 return q.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05002332}
2333
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002334// what's the outer value that a write to n affects?
2335// outer value means containing struct or array.
Russ Cox8c195bd2015-02-13 14:40:36 -05002336func outervalue(n *Node) *Node {
2337 for {
2338 if n.Op == OXDOT {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002339 Fatalf("OXDOT in walk")
Russ Cox8c195bd2015-02-13 14:40:36 -05002340 }
2341 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
2342 n = n.Left
2343 continue
2344 }
2345
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002346 if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() {
Russ Cox8c195bd2015-02-13 14:40:36 -05002347 n = n.Left
2348 continue
2349 }
2350
2351 break
2352 }
2353
2354 return n
2355}
2356
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002357// Is it possible that the computation of n might be
Josh Bleecher Snyderbcce5bd2015-06-10 15:31:53 -07002358// affected by writes in as up to but not including the ith element?
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002359func aliased(n *Node, all []*Node, i int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002360 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002361 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002362 }
2363
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002364 // Treat all fields of a struct as referring to the whole struct.
2365 // We could do better but we would have to keep track of the fields.
2366 for n.Op == ODOT {
2367 n = n.Left
2368 }
2369
Russ Cox8c195bd2015-02-13 14:40:36 -05002370 // Look for obvious aliasing: a variable being assigned
2371 // during the all list and appearing in n.
2372 // Also record whether there are any writes to main memory.
2373 // Also record whether there are any writes to variables
2374 // whose addresses have been taken.
Russ Cox382b44e2015-02-23 16:07:24 -05002375 memwrite := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05002376
Russ Cox382b44e2015-02-23 16:07:24 -05002377 varwrite := 0
2378 var a *Node
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002379 for _, an := range all[:i] {
2380 a = outervalue(an.Left)
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002381
2382 for a.Op == ODOT {
2383 a = a.Left
2384 }
2385
Russ Cox8c195bd2015-02-13 14:40:36 -05002386 if a.Op != ONAME {
2387 memwrite = 1
2388 continue
2389 }
2390
2391 switch n.Class {
2392 default:
2393 varwrite = 1
2394 continue
2395
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002396 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002397 if n.Addrtaken {
Russ Cox8c195bd2015-02-13 14:40:36 -05002398 varwrite = 1
2399 continue
2400 }
2401
Russ Coxdc7b54b2015-02-17 22:13:49 -05002402 if vmatch2(a, n) {
Russ Cox8c195bd2015-02-13 14:40:36 -05002403 // Direct hit.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002404 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002405 }
2406 }
2407 }
2408
2409 // The variables being written do not appear in n.
2410 // However, n might refer to computed addresses
2411 // that are being written.
2412
2413 // If no computed addresses are affected by the writes, no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002414 if memwrite == 0 && varwrite == 0 {
2415 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002416 }
2417
2418 // If n does not refer to computed addresses
2419 // (that is, if n only refers to variables whose addresses
2420 // have not been taken), no aliasing.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002421 if varexpr(n) {
2422 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002423 }
2424
2425 // Otherwise, both the writes and n refer to computed memory addresses.
2426 // Assume that they might conflict.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002427 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002428}
2429
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002430// does the evaluation of n only refer to variables
2431// whose addresses have not been taken?
2432// (and no other memory)
Russ Coxdc7b54b2015-02-17 22:13:49 -05002433func varexpr(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002434 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002435 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002436 }
2437
2438 switch n.Op {
2439 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002440 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002441
2442 case ONAME:
2443 switch n.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002444 case PAUTO, PPARAM, PPARAMOUT:
Dave Cheney7885de52015-03-05 18:20:54 +11002445 if !n.Addrtaken {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002446 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002447 }
2448 }
2449
Russ Coxdc7b54b2015-02-17 22:13:49 -05002450 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002451
2452 case OADD,
2453 OSUB,
2454 OOR,
2455 OXOR,
2456 OMUL,
2457 ODIV,
2458 OMOD,
2459 OLSH,
2460 ORSH,
2461 OAND,
2462 OANDNOT,
2463 OPLUS,
2464 OMINUS,
2465 OCOM,
2466 OPAREN,
2467 OANDAND,
2468 OOROR,
Russ Cox8c195bd2015-02-13 14:40:36 -05002469 OCONV,
2470 OCONVNOP,
2471 OCONVIFACE,
2472 ODOTTYPE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002473 return varexpr(n.Left) && varexpr(n.Right)
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002474
2475 case ODOT: // but not ODOTPTR
Ian Lance Taylor92bb6942016-03-31 13:58:33 -07002476 // Should have been handled in aliased.
2477 Fatalf("varexpr unexpected ODOT")
Russ Cox8c195bd2015-02-13 14:40:36 -05002478 }
2479
2480 // Be conservative.
Russ Coxdc7b54b2015-02-17 22:13:49 -05002481 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002482}
2483
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002484// is the name l mentioned in r?
Russ Coxdc7b54b2015-02-17 22:13:49 -05002485func vmatch2(l *Node, r *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05002486 if r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002487 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002488 }
2489 switch r.Op {
2490 // match each right given left
2491 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002492 return l == r
Russ Cox8c195bd2015-02-13 14:40:36 -05002493
2494 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002495 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002496 }
2497
Russ Coxdc7b54b2015-02-17 22:13:49 -05002498 if vmatch2(l, r.Left) {
2499 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002500 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002501 if vmatch2(l, r.Right) {
2502 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002503 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002504 for _, n := range r.List.Slice() {
2505 if vmatch2(l, n) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002506 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002507 }
2508 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002509 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002510}
2511
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002512// is any name mentioned in l also mentioned in r?
2513// called by sinit.go
Russ Coxdc7b54b2015-02-17 22:13:49 -05002514func vmatch1(l *Node, r *Node) bool {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09002515 // isolate all left sides
Russ Cox8c195bd2015-02-13 14:40:36 -05002516 if l == nil || r == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002517 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002518 }
2519 switch l.Op {
2520 case ONAME:
2521 switch l.Class {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07002522 case PPARAM, PPARAMREF, PAUTO:
Russ Cox8c195bd2015-02-13 14:40:36 -05002523 break
2524
2525 // assignment to non-stack variable
2526 // must be delayed if right has function calls.
2527 default:
2528 if r.Ullman >= UINF {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002529 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002530 }
2531 }
2532
2533 return vmatch2(l, r)
2534
2535 case OLITERAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05002536 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002537 }
2538
Russ Coxdc7b54b2015-02-17 22:13:49 -05002539 if vmatch1(l.Left, r) {
2540 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002541 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002542 if vmatch1(l.Right, r) {
2543 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002544 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002545 for _, n := range l.List.Slice() {
2546 if vmatch1(n, r) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05002547 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05002548 }
2549 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05002550 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05002551}
2552
Matthew Dempsky2339b132016-03-09 18:54:26 -08002553// paramstoheap returns code to allocate memory for heap-escaped parameters
2554// and to copy non-result prameters' values from the stack.
2555// If out is true, then code is also produced to zero-initialize their
2556// stack memory addresses.
2557func paramstoheap(params *Type, out bool) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002558 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002559 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002560 v := t.Nname
2561 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
Russ Cox8c195bd2015-02-13 14:40:36 -05002562 v = nil
2563 }
2564
2565 // For precise stacks, the garbage collector assumes results
2566 // are always live, so zero them always.
Matthew Dempsky2339b132016-03-09 18:54:26 -08002567 if out {
Russ Cox8c195bd2015-02-13 14:40:36 -05002568 // Defer might stop a panic and show the
2569 // return values as they exist at the time of panic.
2570 // Make sure to zero them on entry to the function.
Keith Randall4fffd4562016-02-29 13:31:48 -08002571 nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002572 }
2573
Russ Coxdc7b54b2015-02-17 22:13:49 -05002574 if v == nil || v.Class&PHEAP == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05002575 continue
2576 }
2577
2578 // generate allocation & copying code
Matthew Dempsky980ab122016-04-13 18:37:18 -07002579 if compiling_runtime {
Russ Cox17228f42015-04-17 12:03:22 -04002580 Yyerror("%v escapes to heap, not allowed in runtime.", v)
Russ Cox8c195bd2015-02-13 14:40:36 -05002581 }
Russ Cox60e5f5b2015-05-26 23:05:35 -04002582 if prealloc[v] == nil {
2583 prealloc[v] = callnew(v.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002584 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002585 nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002586 if v.Class&^PHEAP != PPARAMOUT {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002587 as := Nod(OAS, v, v.Name.Param.Stackparam)
Russ Cox3c3019a2015-05-27 00:44:05 -04002588 v.Name.Param.Stackparam.Typecheck = 1
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002589 as = typecheck(as, Etop)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002590 as = applywritebarrier(as)
2591 nn = append(nn, as)
Russ Cox8c195bd2015-02-13 14:40:36 -05002592 }
2593 }
2594
2595 return nn
2596}
2597
Matthew Dempsky2339b132016-03-09 18:54:26 -08002598// returnsfromheap returns code to copy values for heap-escaped parameters
2599// back to the stack.
2600func returnsfromheap(params *Type) []*Node {
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002601 var nn []*Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002602 for _, t := range params.Fields().Slice() {
Matthew Dempsky2339b132016-03-09 18:54:26 -08002603 v := t.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -05002604 if v == nil || v.Class != PHEAP|PPARAMOUT {
2605 continue
2606 }
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002607 nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
Russ Cox8c195bd2015-02-13 14:40:36 -05002608 }
2609
2610 return nn
2611}
2612
Matthew Dempsky2339b132016-03-09 18:54:26 -08002613// heapmoves generates code to handle migrating heap-escaped parameters
2614// between the stack and the heap. The generated code is added to Curfn's
2615// Enter and Exit lists.
Russ Cox8c195bd2015-02-13 14:40:36 -05002616func heapmoves() {
Russ Cox382b44e2015-02-23 16:07:24 -05002617 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -05002618 lineno = Curfn.Lineno
Matthew Dempskyf91b8322016-03-09 20:54:59 -08002619 nn := paramstoheap(Curfn.Type.Recvs(), false)
Matthew Dempsky2339b132016-03-09 18:54:26 -08002620 nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...)
2621 nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -08002622 Curfn.Func.Enter.Append(nn...)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002623 lineno = Curfn.Func.Endlineno
Matthew Dempsky2339b132016-03-09 18:54:26 -08002624 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002625 lineno = lno
2626}
2627
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002628func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002629 if fn.Type == nil || fn.Type.Etype != TFUNC {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002630 Fatalf("mkcall %v %v", fn, fn.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05002631 }
2632
Matthew Dempskyc8377612016-03-17 01:47:16 -07002633 n := fn.Type.Params().NumFields()
Russ Cox8c195bd2015-02-13 14:40:36 -05002634
Russ Cox382b44e2015-02-23 16:07:24 -05002635 r := Nod(OCALL, fn, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002636 r.List.Set(va[:n])
Matthew Dempskyc8377612016-03-17 01:47:16 -07002637 if fn.Type.Results().NumFields() > 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002638 r = typecheck(r, Erv|Efnstruct)
Russ Cox8c195bd2015-02-13 14:40:36 -05002639 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002640 r = typecheck(r, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002641 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002642 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002643 r.Type = t
2644 return r
2645}
2646
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002647func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002648 return vmkcall(syslook(name), t, init, args)
Russ Cox8c195bd2015-02-13 14:40:36 -05002649}
2650
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002651func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002652 return vmkcall(fn, t, init, args)
2653}
2654
2655func conv(n *Node, t *Type) *Node {
2656 if Eqtype(n.Type, t) {
2657 return n
2658 }
2659 n = Nod(OCONV, n, nil)
2660 n.Type = t
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002661 n = typecheck(n, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05002662 return n
2663}
2664
2665func chanfn(name string, n int, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002666 if !t.IsChan() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002667 Fatalf("chanfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002668 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002669 fn := syslook(name)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002670 switch n {
2671 default:
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002672 Fatalf("chanfn %d", n)
Russ Cox13f9c8b2015-03-08 13:33:49 -04002673 case 1:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002674 fn = substArgTypes(fn, t.Elem())
Russ Cox13f9c8b2015-03-08 13:33:49 -04002675 case 2:
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002676 fn = substArgTypes(fn, t.Elem(), t.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002677 }
2678 return fn
2679}
2680
2681func mapfn(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002682 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002683 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002684 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002685 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002686 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val())
Russ Cox8c195bd2015-02-13 14:40:36 -05002687 return fn
2688}
2689
2690func mapfndel(name string, t *Type) *Node {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002691 if !t.IsMap() {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02002692 Fatalf("mapfn %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05002693 }
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002694 fn := syslook(name)
Josh Bleecher Snyder093a9a12016-03-28 21:48:47 -07002695 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key())
Russ Cox8c195bd2015-02-13 14:40:36 -05002696 return fn
2697}
2698
2699func writebarrierfn(name string, l *Type, r *Type) *Node {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002700 fn := syslook(name)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002701 fn = substArgTypes(fn, l, r)
Russ Cox8c195bd2015-02-13 14:40:36 -05002702 return fn
2703}
2704
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002705func addstr(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05002706 // orderexpr rewrote OADDSTR to have a list of strings.
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002707 c := n.List.Len()
Russ Cox8c195bd2015-02-13 14:40:36 -05002708
2709 if c < 2 {
2710 Yyerror("addstr count %d too small", c)
2711 }
2712
Russ Cox382b44e2015-02-23 16:07:24 -05002713 buf := nodnil()
Russ Cox8c195bd2015-02-13 14:40:36 -05002714 if n.Esc == EscNone {
Russ Cox382b44e2015-02-23 16:07:24 -05002715 sz := int64(0)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002716 for _, n1 := range n.List.Slice() {
2717 if n1.Op == OLITERAL {
2718 sz += int64(len(n1.Val().U.(string)))
Russ Cox8c195bd2015-02-13 14:40:36 -05002719 }
2720 }
2721
2722 // Don't allocate the buffer if the result won't fit.
2723 if sz < tmpstringbufsize {
2724 // Create temporary buffer for result string on stack.
Russ Cox382b44e2015-02-23 16:07:24 -05002725 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
Russ Cox8c195bd2015-02-13 14:40:36 -05002726
2727 buf = Nod(OADDR, temp(t), nil)
2728 }
2729 }
2730
2731 // build list of string arguments
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002732 args := []*Node{buf}
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002733 for _, n2 := range n.List.Slice() {
2734 args = append(args, conv(n2, Types[TSTRING]))
Russ Cox8c195bd2015-02-13 14:40:36 -05002735 }
2736
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002737 var fn string
Russ Cox8c195bd2015-02-13 14:40:36 -05002738 if c <= 5 {
2739 // small numbers of strings use direct runtime helpers.
2740 // note: orderexpr knows this cutoff too.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002741 fn = fmt.Sprintf("concatstring%d", c)
Russ Cox8c195bd2015-02-13 14:40:36 -05002742 } else {
2743 // large numbers of strings are passed to the runtime as a slice.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -08002744 fn = "concatstrings"
Russ Cox8c195bd2015-02-13 14:40:36 -05002745
Josh Bleecher Snydereb98e512016-03-28 22:57:57 -07002746 t := typSlice(Types[TSTRING])
Russ Cox382b44e2015-02-23 16:07:24 -05002747 slice := Nod(OCOMPLIT, nil, typenod(t))
Russ Cox60e5f5b2015-05-26 23:05:35 -04002748 if prealloc[n] != nil {
2749 prealloc[slice] = prealloc[n]
2750 }
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002751 slice.List.Set(args[1:]) // skip buf arg
Keith Randall934c3592016-04-23 22:59:01 -07002752 args = []*Node{buf, slice}
Russ Cox8c195bd2015-02-13 14:40:36 -05002753 slice.Esc = EscNone
2754 }
2755
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002756 cat := syslook(fn)
Russ Cox382b44e2015-02-23 16:07:24 -05002757 r := Nod(OCALL, cat, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002758 r.List.Set(args)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002759 r = typecheck(r, Erv)
2760 r = walkexpr(r, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002761 r.Type = n.Type
2762
2763 return r
2764}
2765
2766// expand append(l1, l2...) to
2767// init {
2768// s := l1
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002769// n := len(s) + len(l2)
2770// // Compare as uint so growslice can panic on overflow.
2771// if uint(n) > uint(cap(s)) {
2772// s = growslice(s, n)
Russ Cox8c195bd2015-02-13 14:40:36 -05002773// }
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002774// s = s[:n]
Russ Cox8c195bd2015-02-13 14:40:36 -05002775// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
2776// }
2777// s
2778//
2779// l2 is allowed to be a string.
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002780func appendslice(n *Node, init *Nodes) *Node {
2781 walkexprlistsafe(n.List.Slice(), init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002782
2783 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2784 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002785 // modifying here. Fix explicitly.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002786 ls := n.List.Slice()
2787 for i1, n1 := range ls {
2788 ls[i1] = cheapexpr(n1, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002789 }
2790
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002791 l1 := n.List.First()
2792 l2 := n.List.Second()
Russ Cox8c195bd2015-02-13 14:40:36 -05002793
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002794 var l []*Node
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002795
2796 // var s []T
2797 s := temp(l1.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002798 l = append(l, Nod(OAS, s, l1)) // s = l1
Russ Cox8c195bd2015-02-13 14:40:36 -05002799
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002800 // n := len(s) + len(l2)
2801 nn := temp(Types[TINT])
2802 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002803
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002804 // if uint(n) > uint(cap(s))
Russ Cox382b44e2015-02-23 16:07:24 -05002805 nif := Nod(OIF, nil, nil)
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002806 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
2807 nif.Left.Left.Type = Types[TUINT]
2808 nif.Left.Right.Type = Types[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -05002809
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002810 // instantiate growslice(Type*, []any, int) []any
2811 fn := syslook("growslice")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002812 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002813
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002814 // s = growslice(T, s, n)
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002815 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 -08002816 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05002817
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002818 // s = s[:n]
2819 nt := Nod(OSLICE, s, Nod(OKEY, nil, nn))
2820 nt.Etype = 1
2821 l = append(l, Nod(OAS, s, nt))
2822
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002823 if haspointers(l1.Type.Elem()) {
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002824 // copy(s[len(l1):], l2)
2825 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002826
2827 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002828 nptr2 := l2
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002829 fn := syslook("typedslicecopy")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002830 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002831 var ln Nodes
2832 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002833 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002834 l = append(ln.Slice(), nt)
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002835 } else if instrumenting {
Russ Cox8c195bd2015-02-13 14:40:36 -05002836 // rely on runtime to instrument copy.
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002837 // copy(s[len(l1):], l2)
2838 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05002839
2840 nptr1.Etype = 1
Russ Cox382b44e2015-02-23 16:07:24 -05002841 nptr2 := l2
2842 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002843 if l2.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002844 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002845 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002846 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002847 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002848 fn = substArgTypes(fn, l1.Type, l2.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002849 var ln Nodes
2850 ln.Set(l)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002851 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002852 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002853 } else {
2854 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
Russ Cox382b44e2015-02-23 16:07:24 -05002855 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
Russ Coxdc7b54b2015-02-17 22:13:49 -05002856 nptr1.Bounded = true
Matthew Dempskyd1341d62016-03-13 15:22:45 -07002857
Russ Cox8c195bd2015-02-13 14:40:36 -05002858 nptr1 = Nod(OADDR, nptr1, nil)
2859
Russ Cox382b44e2015-02-23 16:07:24 -05002860 nptr2 := Nod(OSPTR, l2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05002861
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002862 fn := syslook("memmove")
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002863 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002864
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002865 var ln Nodes
2866 ln.Set(l)
2867 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
Russ Cox8c195bd2015-02-13 14:40:36 -05002868
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002869 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002870 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
2871 l = append(ln.Slice(), nt)
Russ Cox8c195bd2015-02-13 14:40:36 -05002872 }
2873
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002874 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002875 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002876 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002877 return s
2878}
2879
Russ Cox85520472015-05-06 12:34:30 -04002880// Rewrite append(src, x, y, z) so that any side effects in
2881// x, y, z (including runtime panics) are evaluated in
2882// initialization statements before the append.
2883// For normal code generation, stop there and leave the
2884// rest to cgen_append.
2885//
2886// For race detector, expand append(src, a [, b]* ) to
Russ Cox8c195bd2015-02-13 14:40:36 -05002887//
2888// init {
2889// s := src
2890// const argc = len(args) - 1
2891// if cap(s) - len(s) < argc {
Russ Cox32fddad2015-06-25 19:27:20 -04002892// s = growslice(s, len(s)+argc)
Russ Cox8c195bd2015-02-13 14:40:36 -05002893// }
2894// n := len(s)
2895// s = s[:n+argc]
2896// s[n] = a
2897// s[n+1] = b
2898// ...
2899// }
2900// s
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002901func walkappend(n *Node, init *Nodes, dst *Node) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002902 if !samesafeexpr(dst, n.List.First()) {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002903 n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002904 n.List.SetIndex(0, walkexpr(n.List.Index(0), init))
Russ Cox85520472015-05-06 12:34:30 -04002905 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002906 walkexprlistsafe(n.List.Slice()[1:], init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002907
2908 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
2909 // and n are name or literal, but those may index the slice we're
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002910 // modifying here. Fix explicitly.
Russ Cox85520472015-05-06 12:34:30 -04002911 // Using cheapexpr also makes sure that the evaluation
2912 // of all arguments (and especially any panics) happen
2913 // before we begin to modify the slice in a visible way.
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002914 ls := n.List.Slice()[1:]
2915 for i, n := range ls {
2916 ls[i] = cheapexpr(n, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05002917 }
2918
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002919 nsrc := n.List.First()
Russ Cox8c195bd2015-02-13 14:40:36 -05002920
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002921 argc := n.List.Len() - 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002922 if argc < 1 {
2923 return nsrc
2924 }
2925
Russ Cox85520472015-05-06 12:34:30 -04002926 // General case, with no function calls left as arguments.
Ian Lance Taylor0c69f132015-10-21 07:04:10 -07002927 // Leave for gen, except that instrumentation requires old form.
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002928 if !instrumenting {
Russ Cox85520472015-05-06 12:34:30 -04002929 return n
2930 }
2931
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002932 var l []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -05002933
Russ Cox382b44e2015-02-23 16:07:24 -05002934 ns := temp(nsrc.Type)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002935 l = append(l, Nod(OAS, ns, nsrc)) // s = src
Russ Cox8c195bd2015-02-13 14:40:36 -05002936
Russ Cox382b44e2015-02-23 16:07:24 -05002937 na := Nodintconst(int64(argc)) // const argc
2938 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
Russ Cox66be1482015-05-26 21:30:20 -04002939 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
Russ Cox8c195bd2015-02-13 14:40:36 -05002940
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002941 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002942 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
Russ Cox8c195bd2015-02-13 14:40:36 -05002943
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08002944 nx.Nbody.Set1(Nod(OAS, ns,
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002945 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08002946 Nod(OADD, Nod(OLEN, ns, nil), na))))
Russ Cox8c195bd2015-02-13 14:40:36 -05002947
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002948 l = append(l, nx)
Russ Cox8c195bd2015-02-13 14:40:36 -05002949
Russ Cox382b44e2015-02-23 16:07:24 -05002950 nn := temp(Types[TINT])
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002951 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
Russ Cox8c195bd2015-02-13 14:40:36 -05002952
2953 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
2954 nx.Etype = 1
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002955 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
Russ Cox8c195bd2015-02-13 14:40:36 -05002956
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002957 ls = n.List.Slice()[1:]
2958 for i, n := range ls {
Russ Cox8c195bd2015-02-13 14:40:36 -05002959 nx = Nod(OINDEX, ns, nn) // s[n] ...
Russ Coxdc7b54b2015-02-17 22:13:49 -05002960 nx.Bounded = true
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002961 l = append(l, Nod(OAS, nx, n)) // s[n] = arg
2962 if i+1 < len(ls) {
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08002963 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
Russ Cox8c195bd2015-02-13 14:40:36 -05002964 }
2965 }
2966
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07002967 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05002968 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002969 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05002970 return ns
2971}
2972
2973// Lower copy(a, b) to a memmove call or a runtime call.
2974//
2975// init {
2976// n := len(a)
2977// if n > len(b) { n = len(b) }
2978// memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
2979// }
2980// n;
2981//
2982// Also works if b is a string.
2983//
Ian Lance Taylore28a8902016-03-07 22:54:46 -08002984func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002985 if haspointers(n.Left.Type.Elem()) {
Russ Cox382b44e2015-02-23 16:07:24 -05002986 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002987 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -05002988 }
2989
Ian Lance Taylor9e902f02015-10-20 10:00:07 -07002990 if runtimecall {
Russ Cox382b44e2015-02-23 16:07:24 -05002991 var fn *Node
Matthew Dempsky3efefd92016-03-30 14:56:08 -07002992 if n.Right.Type.IsString() {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002993 fn = syslook("slicestringcopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002994 } else {
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002995 fn = syslook("slicecopy")
Russ Cox8c195bd2015-02-13 14:40:36 -05002996 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07002997 fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002998 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05002999 }
3000
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003001 n.Left = walkexpr(n.Left, init)
3002 n.Right = walkexpr(n.Right, init)
Russ Cox382b44e2015-02-23 16:07:24 -05003003 nl := temp(n.Left.Type)
3004 nr := temp(n.Right.Type)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003005 var l []*Node
3006 l = append(l, Nod(OAS, nl, n.Left))
3007 l = append(l, Nod(OAS, nr, n.Right))
Russ Cox8c195bd2015-02-13 14:40:36 -05003008
Russ Cox382b44e2015-02-23 16:07:24 -05003009 nfrm := Nod(OSPTR, nr, nil)
3010 nto := Nod(OSPTR, nl, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003011
Russ Cox382b44e2015-02-23 16:07:24 -05003012 nlen := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -05003013
3014 // n = len(to)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003015 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
Russ Cox8c195bd2015-02-13 14:40:36 -05003016
3017 // if n > len(frm) { n = len(frm) }
Russ Cox382b44e2015-02-23 16:07:24 -05003018 nif := Nod(OIF, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003019
Russ Cox66be1482015-05-26 21:30:20 -04003020 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003021 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003022 l = append(l, nif)
Russ Cox8c195bd2015-02-13 14:40:36 -05003023
3024 // Call memmove.
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003025 fn := syslook("memmove")
Russ Cox8c195bd2015-02-13 14:40:36 -05003026
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003027 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
Russ Cox382b44e2015-02-23 16:07:24 -05003028 nwid := temp(Types[TUINTPTR])
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003029 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003030 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003031 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
Russ Cox8c195bd2015-02-13 14:40:36 -05003032
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003033 typecheckslice(l, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -05003034 walkstmtlist(l)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003035 init.Append(l...)
Russ Cox8c195bd2015-02-13 14:40:36 -05003036 return nlen
3037}
3038
Russ Cox8c195bd2015-02-13 14:40:36 -05003039func eqfor(t *Type, needsize *int) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003040 // Should only arrive here with large memory or
3041 // a struct/array containing a non-memory field/element.
3042 // Small memory is handled inline, and single non-memory
3043 // is handled during type check (OCMPSTR etc).
Matthew Dempsky077902d2016-04-01 11:22:03 -07003044 switch a, _ := algtype1(t); a {
3045 case AMEM:
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003046 n := syslook("memequal")
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003047 n = substArgTypes(n, t, t)
Russ Cox8c195bd2015-02-13 14:40:36 -05003048 *needsize = 1
3049 return n
Matthew Dempsky077902d2016-04-01 11:22:03 -07003050 case ASPECIAL:
3051 sym := typesymprefix(".eq", t)
3052 n := newname(sym)
3053 n.Class = PFUNC
3054 ntype := Nod(OTFUNC, nil, nil)
3055 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3056 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
3057 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
3058 ntype = typecheck(ntype, Etype)
3059 n.Type = ntype.Type
3060 *needsize = 0
3061 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003062 }
Matthew Dempsky077902d2016-04-01 11:22:03 -07003063 Fatalf("eqfor %v", t)
3064 return nil
Russ Cox8c195bd2015-02-13 14:40:36 -05003065}
3066
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003067// The result of walkcompare MUST be assigned back to n, e.g.
3068// n.Left = walkcompare(n.Left, init)
3069func walkcompare(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003070 // Given interface value l and concrete value r, rewrite
3071 // l == r
3072 // to
3073 // x, ok := l.(type(r)); ok && x == r
3074 // Handle != similarly.
3075 // This avoids the allocation that would be required
3076 // to convert r to l for comparison.
Russ Cox175929b2015-03-02 14:22:05 -05003077 var l *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003078
Russ Cox175929b2015-03-02 14:22:05 -05003079 var r *Node
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003080 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003081 l = n.Left
3082 r = n.Right
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07003083 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003084 l = n.Right
3085 r = n.Left
3086 }
3087
3088 if l != nil {
Russ Cox382b44e2015-02-23 16:07:24 -05003089 x := temp(r.Type)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003090 if haspointers(r.Type) {
3091 a := Nod(OAS, x, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003092 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003093 init.Append(a)
Austin Clements05a3b1f2015-08-24 13:35:49 -04003094 }
Russ Cox382b44e2015-02-23 16:07:24 -05003095 ok := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -05003096
3097 // l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003098 a := Nod(ODOTTYPE, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003099
3100 a.Type = r.Type
3101
3102 // x, ok := l.(type(r))
Russ Cox382b44e2015-02-23 16:07:24 -05003103 expr := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003104
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003105 expr.List.Append(x)
3106 expr.List.Append(ok)
3107 expr.Rlist.Append(a)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003108 expr = typecheck(expr, Etop)
3109 expr = walkexpr(expr, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003110
3111 if n.Op == OEQ {
3112 r = Nod(OANDAND, ok, Nod(OEQ, x, r))
3113 } else {
3114 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
3115 }
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003116 init.Append(expr)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003117 n = finishcompare(n, r, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003118 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003119 }
3120
3121 // Must be comparison of array or struct.
3122 // Otherwise back end handles it.
Russ Cox44928112015-03-02 20:34:22 -05003123 t := n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05003124
3125 switch t.Etype {
3126 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003127 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003128
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07003129 case TARRAY, TSTRUCT:
Russ Cox8c195bd2015-02-13 14:40:36 -05003130 break
3131 }
3132
Russ Cox44928112015-03-02 20:34:22 -05003133 cmpl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003134 for cmpl != nil && cmpl.Op == OCONVNOP {
3135 cmpl = cmpl.Left
3136 }
Russ Cox44928112015-03-02 20:34:22 -05003137 cmpr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003138 for cmpr != nil && cmpr.Op == OCONVNOP {
3139 cmpr = cmpr.Left
3140 }
3141
Russ Coxdc7b54b2015-02-17 22:13:49 -05003142 if !islvalue(cmpl) || !islvalue(cmpr) {
HĂ¥vard Haugen3c9fa382015-08-30 23:10:03 +02003143 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
Russ Cox8c195bd2015-02-13 14:40:36 -05003144 }
3145
3146 l = temp(Ptrto(t))
Russ Cox44928112015-03-02 20:34:22 -05003147 a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -05003148 a.Right.Etype = 1 // addr does not escape
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003149 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003150 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003151
3152 r = temp(Ptrto(t))
3153 a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
3154 a.Right.Etype = 1 // addr does not escape
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003155 a = typecheck(a, Etop)
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003156 init.Append(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003157
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003158 var andor Op = OANDAND
Russ Cox8c195bd2015-02-13 14:40:36 -05003159 if n.Op == ONE {
3160 andor = OOROR
3161 }
3162
Russ Cox44928112015-03-02 20:34:22 -05003163 var expr *Node
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003164 if t.Etype == TARRAY && t.NumElem() <= 4 && issimple[t.Elem().Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05003165 // Four or fewer elements of a basic type.
3166 // Unroll comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003167 var li *Node
3168 var ri *Node
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003169 for i := 0; int64(i) < t.NumElem(); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05003170 li = Nod(OINDEX, l, Nodintconst(int64(i)))
3171 ri = Nod(OINDEX, r, Nodintconst(int64(i)))
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003172 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003173 if expr == nil {
3174 expr = a
3175 } else {
3176 expr = Nod(andor, expr, a)
3177 }
3178 }
3179
3180 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003181 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003182 }
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003183 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003184 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003185 }
3186
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003187 if t.Etype == TARRAY {
3188 // Zero- or single-element array, of any type.
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003189 switch t.NumElem() {
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003190 case 0:
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003191 n = finishcompare(n, Nodbool(n.Op == OEQ), init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003192 return n
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003193 case 1:
3194 l0 := Nod(OINDEX, l, Nodintconst(0))
3195 r0 := Nod(OINDEX, r, Nodintconst(0))
3196 a := Nod(n.Op, l0, r0)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003197 n = finishcompare(n, a, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003198 return n
Josh Bleecher Snyder4cef0e92015-05-04 15:02:09 -07003199 }
3200 }
3201
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003202 if t.IsStruct() && t.NumFields() <= 4 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003203 // Struct of four or fewer fields.
3204 // Inline comparisons.
Russ Cox382b44e2015-02-23 16:07:24 -05003205 var li *Node
3206 var ri *Node
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07003207 for _, t1 := range t.Fields().Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003208 if isblanksym(t1.Sym) {
3209 continue
3210 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003211 li = NodSym(OXDOT, l, t1.Sym)
3212 ri = NodSym(OXDOT, r, t1.Sym)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003213 a = Nod(n.Op, li, ri)
Russ Cox8c195bd2015-02-13 14:40:36 -05003214 if expr == nil {
3215 expr = a
3216 } else {
3217 expr = Nod(andor, expr, a)
3218 }
3219 }
3220
3221 if expr == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003222 expr = Nodbool(n.Op == OEQ)
Russ Cox8c195bd2015-02-13 14:40:36 -05003223 }
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003224 n = finishcompare(n, expr, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003225 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003226 }
3227
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003228 // Chose not to inline. Call equality function directly.
Russ Cox44928112015-03-02 20:34:22 -05003229 var needsize int
3230 call := Nod(OCALL, eqfor(t, &needsize), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003231
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003232 call.List.Append(l)
3233 call.List.Append(r)
Russ Cox8c195bd2015-02-13 14:40:36 -05003234 if needsize != 0 {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003235 call.List.Append(Nodintconst(t.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -05003236 }
3237 r = call
3238 if n.Op != OEQ {
3239 r = Nod(ONOT, r, nil)
3240 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003241
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003242 n = finishcompare(n, r, init)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003243 return n
Russ Cox44928112015-03-02 20:34:22 -05003244}
3245
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003246// The result of finishcompare MUST be assigned back to n, e.g.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003247// n.Left = finishcompare(n.Left, x, r, init)
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003248func finishcompare(n, r *Node, init *Nodes) *Node {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003249 // Use nn here to avoid passing r to typecheck.
Josh Bleecher Snyderbabc7352016-03-23 16:43:17 -07003250 nn := r
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003251 nn = typecheck(nn, Erv)
3252 nn = walkexpr(nn, init)
3253 r = nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003254 if r.Type != n.Type {
3255 r = Nod(OCONVNOP, r, nil)
3256 r.Type = n.Type
3257 r.Typecheck = 1
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003258 nn = r
Russ Cox8c195bd2015-02-13 14:40:36 -05003259 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003260 return nn
Russ Cox8c195bd2015-02-13 14:40:36 -05003261}
3262
Russ Coxdc7b54b2015-02-17 22:13:49 -05003263func samecheap(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003264 var ar *Node
3265 var br *Node
3266 for a != nil && b != nil && a.Op == b.Op {
3267 switch a.Op {
3268 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003269 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003270
3271 case ONAME:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003272 return a == b
Russ Cox8c195bd2015-02-13 14:40:36 -05003273
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003274 case ODOT, ODOTPTR:
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003275 if a.Sym != b.Sym {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003276 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003277 }
3278
3279 case OINDEX:
3280 ar = a.Right
3281 br = b.Right
Matthew Dempskyd3253872016-03-20 13:55:42 -07003282 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003283 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003284 }
3285 }
3286
3287 a = a.Left
3288 b = b.Left
3289 }
3290
Russ Coxdc7b54b2015-02-17 22:13:49 -05003291 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003292}
3293
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003294// The result of walkrotate MUST be assigned back to n, e.g.
3295// n.Left = walkrotate(n.Left)
3296func walkrotate(n *Node) *Node {
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07003297 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003298 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003299 }
3300
Russ Cox8c195bd2015-02-13 14:40:36 -05003301 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
Russ Cox382b44e2015-02-23 16:07:24 -05003302 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05003303
Russ Cox382b44e2015-02-23 16:07:24 -05003304 r := n.Right
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003305 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 -07003306 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003307 }
3308
3309 // Want same, side effect-free expression on lhs of both shifts.
Russ Coxdc7b54b2015-02-17 22:13:49 -05003310 if !samecheap(l.Left, r.Left) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003311 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003312 }
3313
3314 // Constants adding to width?
Russ Cox382b44e2015-02-23 16:07:24 -05003315 w := int(l.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003316
Michael Munday613ba6c2016-04-12 12:26:17 -04003317 if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
3318 // only supports 32-bit and 64-bit rotates
3319 return n
3320 }
3321
Russ Coxdc7b54b2015-02-17 22:13:49 -05003322 if Smallintconst(l.Right) && Smallintconst(r.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003323 sl := int(l.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003324 if sl >= 0 {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003325 sr := int(r.Right.Int64())
Russ Cox8c195bd2015-02-13 14:40:36 -05003326 if sr >= 0 && sl+sr == w {
Russ Cox79f727a2015-03-02 12:35:15 -05003327 // Rewrite left shift half to left rotate.
3328 if l.Op == OLSH {
3329 n = l
3330 } else {
3331 n = r
3332 }
3333 n.Op = OLROT
3334
3335 // Remove rotate 0 and rotate w.
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003336 s := int(n.Right.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003337
3338 if s == 0 || s == w {
3339 n = n.Left
3340 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003341 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003342 }
3343 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003344 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003345 }
3346
3347 // 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 -07003348 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003349}
3350
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003351// walkmul rewrites integer multiplication by powers of two as shifts.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003352// The result of walkmul MUST be assigned back to n, e.g.
3353// n.Left = walkmul(n.Left, init)
3354func walkmul(n *Node, init *Nodes) *Node {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003355 if !n.Type.IsInteger() {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003356 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003357 }
3358
Russ Cox382b44e2015-02-23 16:07:24 -05003359 var nr *Node
3360 var nl *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003361 if n.Right.Op == OLITERAL {
3362 nl = n.Left
3363 nr = n.Right
3364 } else if n.Left.Op == OLITERAL {
3365 nl = n.Right
3366 nr = n.Left
3367 } else {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003368 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003369 }
3370
Russ Cox382b44e2015-02-23 16:07:24 -05003371 neg := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05003372
3373 // x*0 is 0 (and side effects of x).
Russ Cox382b44e2015-02-23 16:07:24 -05003374 var pow int
3375 var w int
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003376 if nr.Int64() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003377 cheapexpr(nl, init)
3378 Nodconst(n, n.Type, 0)
3379 goto ret
3380 }
3381
3382 // nr is a constant.
3383 pow = powtwo(nr)
3384
3385 if pow < 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003386 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003387 }
3388 if pow >= 1000 {
3389 // negative power of 2, like -16
3390 neg = 1
3391
3392 pow -= 1000
3393 }
3394
3395 w = int(nl.Type.Width * 8)
3396 if pow+1 >= w { // too big, shouldn't happen
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003397 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003398 }
3399
3400 nl = cheapexpr(nl, init)
3401
3402 if pow == 0 {
3403 // x*1 is x
3404 n = nl
3405
3406 goto ret
3407 }
3408
3409 n = Nod(OLSH, nl, Nodintconst(int64(pow)))
3410
3411ret:
3412 if neg != 0 {
3413 n = Nod(OMINUS, n, nil)
3414 }
3415
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003416 n = typecheck(n, Erv)
3417 n = walkexpr(n, init)
3418 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003419}
3420
Jeremy Jackins6327e8d2015-10-22 09:51:12 +09003421// walkdiv rewrites division by a constant as less expensive
3422// operations.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003423// The result of walkdiv MUST be assigned back to n, e.g.
3424// n.Left = walkdiv(n.Left, init)
3425func walkdiv(n *Node, init *Nodes) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -05003426 // if >= 0, nr is 1<<pow // 1 if nr is negative.
Russ Cox8c195bd2015-02-13 14:40:36 -05003427
3428 // TODO(minux)
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07003429 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003430 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003431 }
3432
Russ Cox8c195bd2015-02-13 14:40:36 -05003433 if n.Right.Op != OLITERAL {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003434 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003435 }
3436
3437 // nr is a constant.
Russ Cox382b44e2015-02-23 16:07:24 -05003438 nl := cheapexpr(n.Left, init)
Russ Cox8c195bd2015-02-13 14:40:36 -05003439
Russ Cox382b44e2015-02-23 16:07:24 -05003440 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -05003441
3442 // special cases of mod/div
3443 // by a constant
Russ Cox382b44e2015-02-23 16:07:24 -05003444 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05003445
Russ Coxcdb7d7d2015-03-05 13:57:36 -05003446 s := 0 // 1 if nr is negative.
3447 pow := powtwo(nr) // if >= 0, nr is 1<<pow
Russ Cox8c195bd2015-02-13 14:40:36 -05003448 if pow >= 1000 {
3449 // negative power of 2
3450 s = 1
3451
3452 pow -= 1000
3453 }
3454
3455 if pow+1 >= w {
3456 // divisor too large.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003457 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003458 }
3459
3460 if pow < 0 {
Russ Cox79f727a2015-03-02 12:35:15 -05003461 // try to do division by multiply by (2^w)/d
3462 // see hacker's delight chapter 10
3463 // TODO: support 64-bit magic multiply here.
3464 var m Magic
3465 m.W = w
3466
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003467 if nl.Type.IsSigned() {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003468 m.Sd = nr.Int64()
Russ Cox79f727a2015-03-02 12:35:15 -05003469 Smagic(&m)
3470 } else {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003471 m.Ud = uint64(nr.Int64())
Russ Cox79f727a2015-03-02 12:35:15 -05003472 Umagic(&m)
3473 }
3474
3475 if m.Bad != 0 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003476 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003477 }
3478
3479 // We have a quick division method so use it
3480 // for modulo too.
3481 if n.Op == OMOD {
3482 // rewrite as A%B = A - (A/B*B).
3483 n1 := Nod(ODIV, nl, nr)
3484
3485 n2 := Nod(OMUL, n1, nr)
3486 n = Nod(OSUB, nl, n2)
3487 goto ret
3488 }
3489
3490 switch Simtype[nl.Type.Etype] {
3491 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003492 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003493
3494 // n1 = nl * magic >> w (HMUL)
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003495 case TUINT8, TUINT16, TUINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003496 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003497
Dave Cheneya4be24c2016-03-23 13:27:49 +11003498 Nodconst(&nc, nl.Type, int64(m.Um))
3499 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003500 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003501 if m.Ua != 0 {
3502 // Select a Go type with (at least) twice the width.
3503 var twide *Type
3504 switch Simtype[nl.Type.Etype] {
3505 default:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003506 return n
Russ Cox79f727a2015-03-02 12:35:15 -05003507
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003508 case TUINT8, TUINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003509 twide = Types[TUINT32]
3510
3511 case TUINT32:
3512 twide = Types[TUINT64]
3513
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003514 case TINT8, TINT16:
Russ Cox79f727a2015-03-02 12:35:15 -05003515 twide = Types[TINT32]
3516
3517 case TINT32:
3518 twide = Types[TINT64]
3519 }
3520
3521 // add numerator (might overflow).
3522 // n2 = (n1 + nl)
3523 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
3524
3525 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003526 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003527
Dave Cheneya4be24c2016-03-23 13:27:49 +11003528 Nodconst(&nc, Types[TUINT], int64(m.S))
3529 n = conv(Nod(ORSH, n2, &nc), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003530 } else {
3531 // n = n1 >> m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003532 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003533
Dave Cheneya4be24c2016-03-23 13:27:49 +11003534 Nodconst(&nc, Types[TUINT], int64(m.S))
3535 n = Nod(ORSH, n1, &nc)
Russ Cox79f727a2015-03-02 12:35:15 -05003536 }
3537
3538 // n1 = nl * magic >> w
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003539 case TINT8, TINT16, TINT32:
Dave Cheneya4be24c2016-03-23 13:27:49 +11003540 var nc Node
Russ Cox79f727a2015-03-02 12:35:15 -05003541
Dave Cheneya4be24c2016-03-23 13:27:49 +11003542 Nodconst(&nc, nl.Type, m.Sm)
3543 n1 := Nod(OHMUL, nl, &nc)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003544 n1 = typecheck(n1, Erv)
Russ Cox79f727a2015-03-02 12:35:15 -05003545 if m.Sm < 0 {
3546 // add the numerator.
3547 n1 = Nod(OADD, n1, nl)
3548 }
3549
3550 // shift by m.s
Dave Cheneya4be24c2016-03-23 13:27:49 +11003551 var ns Node
Russ Cox79f727a2015-03-02 12:35:15 -05003552
Dave Cheneya4be24c2016-03-23 13:27:49 +11003553 Nodconst(&ns, Types[TUINT], int64(m.S))
3554 n2 := conv(Nod(ORSH, n1, &ns), nl.Type)
Russ Cox79f727a2015-03-02 12:35:15 -05003555
3556 // add 1 iff n1 is negative.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003557 var nneg Node
Russ Cox79f727a2015-03-02 12:35:15 -05003558
Dave Cheneya4be24c2016-03-23 13:27:49 +11003559 Nodconst(&nneg, Types[TUINT], int64(w)-1)
3560 n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative.
Russ Cox79f727a2015-03-02 12:35:15 -05003561 n = Nod(OSUB, n2, n3)
3562
3563 // apply sign.
3564 if m.Sd < 0 {
3565 n = Nod(OMINUS, n, nil)
3566 }
3567 }
3568
3569 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -05003570 }
3571
3572 switch pow {
3573 case 0:
3574 if n.Op == OMOD {
3575 // nl % 1 is zero.
3576 Nodconst(n, n.Type, 0)
3577 } else if s != 0 {
3578 // divide by -1
3579 n.Op = OMINUS
3580
3581 n.Right = nil
3582 } else {
3583 // divide by 1
3584 n = nl
3585 }
3586
3587 default:
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003588 if n.Type.IsSigned() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003589 if n.Op == OMOD {
3590 // signed modulo 2^pow is like ANDing
3591 // with the last pow bits, but if nl < 0,
3592 // nl & (2^pow-1) is (nl+1)%2^pow - 1.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003593 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003594
Dave Cheneya4be24c2016-03-23 13:27:49 +11003595 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3596 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003597 if pow == 1 {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003598 n1 = typecheck(n1, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003599 n1 = cheapexpr(n1, init)
3600
3601 // n = (nl+ε)&1 -ε where ε=1 iff nl<0.
Russ Cox382b44e2015-02-23 16:07:24 -05003602 n2 := Nod(OSUB, nl, n1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003603
Dave Cheneya4be24c2016-03-23 13:27:49 +11003604 var nc Node
3605 Nodconst(&nc, nl.Type, 1)
3606 n3 := Nod(OAND, n2, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003607 n = Nod(OADD, n3, n1)
3608 } else {
3609 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003610 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003611
Dave Cheneya4be24c2016-03-23 13:27:49 +11003612 Nodconst(&nc, nl.Type, (1<<uint(pow))-1)
3613 n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0.
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003614 n2 = typecheck(n2, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -05003615 n2 = cheapexpr(n2, init)
3616
Russ Cox382b44e2015-02-23 16:07:24 -05003617 n3 := Nod(OADD, nl, n2)
Dave Cheneya4be24c2016-03-23 13:27:49 +11003618 n4 := Nod(OAND, n3, &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003619 n = Nod(OSUB, n4, n2)
3620 }
3621
3622 break
3623 } else {
3624 // arithmetic right shift does not give the correct rounding.
3625 // if nl >= 0, nl >> n == nl / nr
3626 // if nl < 0, we want to add 2^n-1 first.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003627 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003628
Dave Cheneya4be24c2016-03-23 13:27:49 +11003629 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1)
3630 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0.
Russ Cox8c195bd2015-02-13 14:40:36 -05003631 if pow == 1 {
3632 // nl+1 is nl-(-1)
3633 n.Left = Nod(OSUB, nl, n1)
3634 } else {
3635 // Do a logical right right on -1 to keep pow bits.
Dave Cheneya4be24c2016-03-23 13:27:49 +11003636 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003637
Dave Cheneya4be24c2016-03-23 13:27:49 +11003638 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
3639 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), &nc)
Russ Cox8c195bd2015-02-13 14:40:36 -05003640 n.Left = Nod(OADD, nl, conv(n2, nl.Type))
3641 }
3642
3643 // n = (nl + 2^pow-1) >> pow
3644 n.Op = ORSH
3645
Dave Cheneya4be24c2016-03-23 13:27:49 +11003646 var n2 Node
3647 Nodconst(&n2, Types[Simtype[TUINT]], int64(pow))
3648 n.Right = &n2
Russ Cox8c195bd2015-02-13 14:40:36 -05003649 n.Typecheck = 0
3650 }
3651
3652 if s != 0 {
3653 n = Nod(OMINUS, n, nil)
3654 }
3655 break
3656 }
3657
Dave Cheneya4be24c2016-03-23 13:27:49 +11003658 var nc Node
Russ Cox8c195bd2015-02-13 14:40:36 -05003659 if n.Op == OMOD {
3660 // n = nl & (nr-1)
3661 n.Op = OAND
3662
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003663 Nodconst(&nc, nl.Type, nr.Int64()-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05003664 } else {
3665 // n = nl >> pow
3666 n.Op = ORSH
3667
Dave Cheneya4be24c2016-03-23 13:27:49 +11003668 Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
Russ Cox8c195bd2015-02-13 14:40:36 -05003669 }
3670
3671 n.Typecheck = 0
Dave Cheneya4be24c2016-03-23 13:27:49 +11003672 n.Right = &nc
Russ Cox8c195bd2015-02-13 14:40:36 -05003673 }
3674
3675 goto ret
3676
Russ Cox8c195bd2015-02-13 14:40:36 -05003677ret:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003678 n = typecheck(n, Erv)
3679 n = walkexpr(n, init)
3680 return n
Russ Cox8c195bd2015-02-13 14:40:36 -05003681}
3682
3683// return 1 if integer n must be in range [0, max), 0 otherwise
Russ Coxdc7b54b2015-02-17 22:13:49 -05003684func bounded(n *Node, max int64) bool {
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003685 if n.Type == nil || !n.Type.IsInteger() {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003686 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003687 }
3688
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003689 sign := n.Type.IsSigned()
Russ Cox382b44e2015-02-23 16:07:24 -05003690 bits := int32(8 * n.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05003691
Russ Coxdc7b54b2015-02-17 22:13:49 -05003692 if Smallintconst(n) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003693 v := n.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003694 return 0 <= v && v < max
Russ Cox8c195bd2015-02-13 14:40:36 -05003695 }
3696
3697 switch n.Op {
3698 case OAND:
Russ Cox382b44e2015-02-23 16:07:24 -05003699 v := int64(-1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05003700 if Smallintconst(n.Left) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003701 v = n.Left.Int64()
Russ Coxdc7b54b2015-02-17 22:13:49 -05003702 } else if Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003703 v = n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003704 }
3705
3706 if 0 <= v && v < max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003707 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003708 }
3709
3710 case OMOD:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003711 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003712 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003713 if 0 <= v && v <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003714 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003715 }
3716 }
3717
3718 case ODIV:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003719 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003720 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003721 for bits > 0 && v >= 2 {
3722 bits--
3723 v >>= 1
3724 }
3725 }
3726
3727 case ORSH:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003728 if !sign && Smallintconst(n.Right) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07003729 v := n.Right.Int64()
Russ Cox8c195bd2015-02-13 14:40:36 -05003730 if v > int64(bits) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003731 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003732 }
3733 bits -= int32(v)
3734 }
3735 }
3736
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00003737 if !sign && bits <= 62 && 1<<uint(bits) <= max {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003738 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003739 }
3740
Russ Coxdc7b54b2015-02-17 22:13:49 -05003741 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003742}
3743
David Crawshawcc158402016-03-10 16:15:26 -05003744// usemethod check interface method calls for uses of reflect.Type.Method.
3745func usemethod(n *Node) {
3746 t := n.Left.Type
3747
3748 // Looking for either of:
3749 // Method(int) reflect.Method
3750 // MethodByName(string) (reflect.Method, bool)
3751 //
3752 // TODO(crawshaw): improve precision of match by working out
3753 // how to check the method name.
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003754 if n := t.Params().NumFields(); n != 1 {
David Crawshawcc158402016-03-10 16:15:26 -05003755 return
3756 }
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003757 if n := t.Results().NumFields(); n != 1 && n != 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003758 return
3759 }
3760 p0 := t.Params().Field(0)
3761 res0 := t.Results().Field(0)
Matthew Dempsky2e936902016-03-14 01:20:49 -07003762 var res1 *Field
Matthew Dempskydbed1c62016-03-17 13:26:08 -07003763 if t.Results().NumFields() == 2 {
David Crawshawcc158402016-03-10 16:15:26 -05003764 res1 = t.Results().Field(1)
3765 }
3766
3767 if res1 == nil {
3768 if p0.Type.Etype != TINT {
3769 return
3770 }
3771 } else {
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003772 if !p0.Type.IsString() {
David Crawshawcc158402016-03-10 16:15:26 -05003773 return
3774 }
Matthew Dempsky3efefd92016-03-30 14:56:08 -07003775 if !res1.Type.IsBoolean() {
David Crawshawcc158402016-03-10 16:15:26 -05003776 return
3777 }
3778 }
Matthew Dempsky2e936902016-03-14 01:20:49 -07003779 if Tconv(res0.Type, 0) != "reflect.Method" {
David Crawshawcc158402016-03-10 16:15:26 -05003780 return
3781 }
3782
3783 Curfn.Func.ReflectMethod = true
3784}
3785
Russ Cox8c195bd2015-02-13 14:40:36 -05003786func usefield(n *Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003787 if obj.Fieldtrack_enabled == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003788 return
3789 }
3790
3791 switch n.Op {
3792 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08003793 Fatalf("usefield %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -05003794
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003795 case ODOT, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -05003796 break
3797 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003798 if n.Sym == nil {
Keith Randall71d13a82016-03-02 20:54:41 -08003799 // No field name. This DOTPTR was built by the compiler for access
3800 // to runtime data structures. Ignore.
3801 return
3802 }
Russ Cox8c195bd2015-02-13 14:40:36 -05003803
Russ Cox496ad0a2015-05-26 21:49:31 -04003804 t := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003805 if t.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003806 t = t.Elem()
Russ Cox496ad0a2015-05-26 21:49:31 -04003807 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003808 field := dotField[typeSym{t.Orig, n.Sym}]
Russ Cox8c195bd2015-02-13 14:40:36 -05003809 if field == nil {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07003810 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05003811 }
Russ Coxbed1f902015-03-02 16:03:26 -05003812 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
Russ Cox8c195bd2015-02-13 14:40:36 -05003813 return
3814 }
3815
Matthew Dempskya2a48062016-03-10 16:15:44 -08003816 outer := n.Left.Type
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07003817 if outer.IsPtr() {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003818 outer = outer.Elem()
Russ Cox8c195bd2015-02-13 14:40:36 -05003819 }
Matthew Dempskya2a48062016-03-10 16:15:44 -08003820 if outer.Sym == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05003821 Yyerror("tracked field must be in named struct type")
3822 }
3823 if !exportname(field.Sym.Name) {
3824 Yyerror("tracked field must be exported (upper case)")
3825 }
3826
Matthew Dempskya2a48062016-03-10 16:15:44 -08003827 sym := tracksym(outer, field)
3828 if Curfn.Func.FieldTrack == nil {
3829 Curfn.Func.FieldTrack = make(map[*Sym]struct{})
3830 }
3831 Curfn.Func.FieldTrack[sym] = struct{}{}
Russ Cox8c195bd2015-02-13 14:40:36 -05003832}
3833
Ian Lance Taylorc4012b62016-03-08 10:26:20 -08003834func candiscardlist(l Nodes) bool {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003835 for _, n := range l.Slice() {
3836 if !candiscard(n) {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -08003837 return false
3838 }
3839 }
3840 return true
3841}
3842
Russ Coxdc7b54b2015-02-17 22:13:49 -05003843func candiscard(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05003844 if n == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -05003845 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003846 }
3847
3848 switch n.Op {
3849 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003850 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003851
3852 // Discardable as long as the subpieces are.
3853 case ONAME,
3854 ONONAME,
3855 OTYPE,
3856 OPACK,
3857 OLITERAL,
3858 OADD,
3859 OSUB,
3860 OOR,
3861 OXOR,
3862 OADDSTR,
3863 OADDR,
3864 OANDAND,
3865 OARRAYBYTESTR,
3866 OARRAYRUNESTR,
3867 OSTRARRAYBYTE,
3868 OSTRARRAYRUNE,
3869 OCAP,
3870 OCMPIFACE,
3871 OCMPSTR,
3872 OCOMPLIT,
3873 OMAPLIT,
3874 OSTRUCTLIT,
3875 OARRAYLIT,
3876 OPTRLIT,
3877 OCONV,
3878 OCONVIFACE,
3879 OCONVNOP,
3880 ODOT,
3881 OEQ,
3882 ONE,
3883 OLT,
3884 OLE,
3885 OGT,
3886 OGE,
3887 OKEY,
3888 OLEN,
3889 OMUL,
3890 OLSH,
3891 ORSH,
3892 OAND,
3893 OANDNOT,
3894 ONEW,
3895 ONOT,
3896 OCOM,
3897 OPLUS,
3898 OMINUS,
3899 OOROR,
3900 OPAREN,
3901 ORUNESTR,
3902 OREAL,
3903 OIMAG,
3904 OCOMPLEX:
3905 break
3906
3907 // Discardable as long as we know it's not division by zero.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003908 case ODIV, OMOD:
Matthew Dempskyd3253872016-03-20 13:55:42 -07003909 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003910 break
3911 }
Matthew Dempskyd3253872016-03-20 13:55:42 -07003912 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003913 break
3914 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003915 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003916
3917 // Discardable as long as we know it won't fail because of a bad size.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07003918 case OMAKECHAN, OMAKEMAP:
Matthew Dempskyd3253872016-03-20 13:55:42 -07003919 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05003920 break
3921 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05003922 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003923
3924 // Difficult to tell what sizes are okay.
3925 case OMAKESLICE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05003926 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003927 }
3928
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003929 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 -05003930 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05003931 }
3932
Russ Coxdc7b54b2015-02-17 22:13:49 -05003933 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05003934}
3935
3936// rewrite
3937// print(x, y, z)
3938// into
3939// func(a1, a2, a3) {
3940// print(a1, a2, a3)
3941// }(x, y, z)
3942// and same for println.
3943
3944var walkprintfunc_prgen int
3945
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003946// The result of walkprintfunc MUST be assigned back to n, e.g.
3947// n.Left = walkprintfunc(n.Left, init)
3948func walkprintfunc(n *Node, init *Nodes) *Node {
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003949 if n.Ninit.Len() != 0 {
Ian Lance Taylore28a8902016-03-07 22:54:46 -08003950 walkstmtlist(n.Ninit.Slice())
3951 init.AppendNodes(&n.Ninit)
Russ Cox8c195bd2015-02-13 14:40:36 -05003952 }
3953
Russ Cox382b44e2015-02-23 16:07:24 -05003954 t := Nod(OTFUNC, nil, nil)
3955 num := 0
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003956 var printargs []*Node
Russ Cox382b44e2015-02-23 16:07:24 -05003957 var a *Node
3958 var buf string
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003959 for _, n1 := range n.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -05003960 buf = fmt.Sprintf("a%d", num)
3961 num++
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003962 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
3963 t.List.Append(a)
Ian Lance Taylor132ebea2016-03-03 20:48:00 -08003964 printargs = append(printargs, a.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -05003965 }
3966
Russ Cox382b44e2015-02-23 16:07:24 -05003967 fn := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -05003968 walkprintfunc_prgen++
3969 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
Russ Coxbd4fff62015-05-27 10:42:55 -04003970 fn.Func.Nname = newname(Lookup(buf))
3971 fn.Func.Nname.Name.Defn = fn
3972 fn.Func.Nname.Name.Param.Ntype = t
3973 declare(fn.Func.Nname, PFUNC)
Russ Cox8c195bd2015-02-13 14:40:36 -05003974
Russ Cox382b44e2015-02-23 16:07:24 -05003975 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -05003976 Curfn = nil
3977 funchdr(fn)
3978
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02003979 a = Nod(n.Op, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003980 a.List.Set(printargs)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003981 a = typecheck(a, Etop)
3982 a = walkstmt(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003983
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -08003984 fn.Nbody.Set1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -05003985
3986 funcbody(fn)
3987
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003988 fn = typecheck(fn, Etop)
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -07003989 typecheckslice(fn.Nbody.Slice(), Etop)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -08003990 xtop = append(xtop, fn)
Russ Cox8c195bd2015-02-13 14:40:36 -05003991 Curfn = oldfn
3992
3993 a = Nod(OCALL, nil, nil)
Russ Coxbd4fff62015-05-27 10:42:55 -04003994 a.Left = fn.Func.Nname
Ian Lance Taylor38921b32016-03-08 15:10:26 -08003995 a.List.Set(n.List.Slice())
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -07003996 a = typecheck(a, Etop)
3997 a = walkexpr(a, init)
3998 return a
Russ Cox8c195bd2015-02-13 14:40:36 -05003999}