blob: 2db253184ca61df866923a81b8475ffcbaf4ec44 [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
Robert Griesemerdef9c0b2016-03-10 20:35:27 -08005// Portable half of code generator; mainly statements and control flow.
6
Russ Cox8c195bd2015-02-13 14:40:36 -05007package gc
8
9import (
10 "cmd/internal/obj"
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -070011 "cmd/internal/sys"
Russ Cox8c195bd2015-02-13 14:40:36 -050012 "fmt"
13)
14
Robert Griesemerdef9c0b2016-03-10 20:35:27 -080015// TODO: labellist should become part of a "compilation state" for functions.
16var labellist []*Label
Russ Cox8c195bd2015-02-13 14:40:36 -050017
18func Sysfunc(name string) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -050019 n := newname(Pkglookup(name, Runtimepkg))
Russ Cox8c195bd2015-02-13 14:40:36 -050020 n.Class = PFUNC
21 return n
22}
23
David Chase7fbb1b32015-03-26 16:36:15 -040024// addrescapes tags node n as having had its address taken
25// by "increasing" the "value" of n.Esc to EscHeap.
26// Storage is allocated as necessary to allow the address
27// to be taken.
Russ Cox8c195bd2015-02-13 14:40:36 -050028func addrescapes(n *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -050029 switch n.Op {
30 // probably a type error already.
31 // dump("addrescapes", n);
32 default:
33 break
34
35 case ONAME:
36 if n == nodfp {
37 break
38 }
39
40 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
41 // on PPARAM it means something different.
42 if n.Class == PAUTO && n.Esc == EscNever {
43 break
44 }
45
Russ Coxb6dc3e62016-05-25 01:33:24 -040046 // A PPARAMREF is a closure reference.
47 // Mark the thing it refers to as escaping.
48 if n.Class == PPARAMREF {
Russ Cox4fdd5362015-05-26 22:19:27 -040049 addrescapes(n.Name.Defn)
Russ Coxb6dc3e62016-05-25 01:33:24 -040050 break
Russ Cox8c195bd2015-02-13 14:40:36 -050051 }
52
Russ Coxb6dc3e62016-05-25 01:33:24 -040053 if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
54 break
55 }
56
57 // This is a plain parameter or local variable that needs to move to the heap,
58 // but possibly for the function outside the one we're compiling.
59 // That is, if we have:
60 //
61 // func f(x int) {
62 // func() {
63 // global = &x
64 // }
65 // }
66 //
67 // then we're analyzing the inner closure but we need to move x to the
68 // heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
69 oldfn := Curfn
70 Curfn = n.Name.Curfn
71 if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
72 Curfn = Curfn.Func.Closure
73 }
74 ln := lineno
75 lineno = Curfn.Lineno
76 moveToHeap(n)
77 Curfn = oldfn
78 lineno = ln
79
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -070080 case OIND, ODOTPTR:
Russ Cox8c195bd2015-02-13 14:40:36 -050081 break
82
David Chase7fbb1b32015-03-26 16:36:15 -040083 // ODOTPTR has already been introduced,
Russ Cox8c195bd2015-02-13 14:40:36 -050084 // so these are the non-pointer ODOT and OINDEX.
85 // In &x[0], if x is a slice, then x does not
86 // escape--the pointer inside x does, but that
87 // is always a heap pointer anyway.
David Chase7fbb1b32015-03-26 16:36:15 -040088 case ODOT, OINDEX, OPAREN, OCONVNOP:
Matthew Dempsky1624a9c2016-03-30 14:45:47 -070089 if !n.Left.Type.IsSlice() {
Russ Cox8c195bd2015-02-13 14:40:36 -050090 addrescapes(n.Left)
91 }
92 }
93}
94
Russ Coxb6dc3e62016-05-25 01:33:24 -040095// isParamStackCopy reports whether this is the on-stack copy of a
96// function parameter that moved to the heap.
97func (n *Node) isParamStackCopy() bool {
98 return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Heapaddr != nil
99}
100
101// isParamHeapCopy reports whether this is the on-heap copy of
102// a function parameter that moved to the heap.
103func (n *Node) isParamHeapCopy() bool {
104 return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil
105}
106
107// paramClass reports the parameter class (PPARAM or PPARAMOUT)
108// of the node, which may be an unmoved on-stack parameter
109// or the on-heap or on-stack copy of a parameter that moved to the heap.
110// If the node is not a parameter, paramClass returns Pxxx.
111func (n *Node) paramClass() Class {
112 if n.Op != ONAME {
113 return Pxxx
114 }
115 if n.Class == PPARAM || n.Class == PPARAMOUT {
116 return n.Class
117 }
118 if n.isParamHeapCopy() {
119 return n.Name.Param.Stackcopy.Class
120 }
121 return Pxxx
122}
123
124// moveToHeap records the parameter or local variable n as moved to the heap.
125func moveToHeap(n *Node) {
126 if Debug['r'] != 0 {
127 Dump("MOVE", n)
128 }
129 if compiling_runtime {
130 Yyerror("%v escapes to heap, not allowed in runtime.", n)
131 }
132 if n.Class == PAUTOHEAP {
133 Dump("n", n)
134 Fatalf("double move to heap")
135 }
136
137 // Allocate a local stack variable to hold the pointer to the heap copy.
138 // temp will add it to the function declaration list automatically.
139 heapaddr := temp(Ptrto(n.Type))
140 heapaddr.Sym = Lookup("&" + n.Sym.Name)
141 heapaddr.Orig.Sym = heapaddr.Sym
142
143 // Parameters have a local stack copy used at function start/end
144 // in addition to the copy in the heap that may live longer than
145 // the function.
146 if n.Class == PPARAM || n.Class == PPARAMOUT {
147 if n.Xoffset == BADWIDTH {
148 Fatalf("addrescapes before param assignment")
149 }
150
151 // We rewrite n below to be a heap variable (indirection of heapaddr).
152 // Preserve a copy so we can still write code referring to the original,
153 // and substitute that copy into the function declaration list
154 // so that analyses of the local (on-stack) variables use it.
155 stackcopy := Nod(ONAME, nil, nil)
156 stackcopy.Sym = n.Sym
157 stackcopy.Type = n.Type
158 stackcopy.Xoffset = n.Xoffset
159 stackcopy.Class = n.Class
160 stackcopy.Name.Heapaddr = heapaddr
161 if n.Class == PPARAM {
162 stackcopy.SetNotLiveAtEnd(true)
163 }
164 n.Name.Param.Stackcopy = stackcopy
165
166 // Substitute the stackcopy into the function variable list so that
167 // liveness and other analyses use the underlying stack slot
168 // and not the now-pseudo-variable n.
169 found := false
170 for i, d := range Curfn.Func.Dcl {
171 if d == n {
172 Curfn.Func.Dcl[i] = stackcopy
173 found = true
174 break
175 }
176 // Parameters are before locals, so can stop early.
177 // This limits the search even in functions with many local variables.
178 if d.Class == PAUTO {
179 break
180 }
181 }
182 if !found {
183 Fatalf("cannot find %v in local variable list", n)
184 }
185 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
186 }
187
188 // Modify n in place so that uses of n now mean indirection of the heapaddr.
189 n.Class = PAUTOHEAP
190 n.Ullman = 2
191 n.Xoffset = 0
192 n.Name.Heapaddr = heapaddr
193 n.Esc = EscHeap
194 if Debug['m'] != 0 {
195 fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
196 }
197}
198
Russ Cox8c195bd2015-02-13 14:40:36 -0500199func clearlabels() {
Robert Griesemerdef9c0b2016-03-10 20:35:27 -0800200 for _, l := range labellist {
Russ Cox8c195bd2015-02-13 14:40:36 -0500201 l.Sym.Label = nil
202 }
Robert Griesemerdef9c0b2016-03-10 20:35:27 -0800203 labellist = labellist[:0]
Russ Cox8c195bd2015-02-13 14:40:36 -0500204}
205
206func newlab(n *Node) *Label {
Russ Cox382b44e2015-02-23 16:07:24 -0500207 s := n.Left.Sym
208 lab := s.Label
Russ Cox8c195bd2015-02-13 14:40:36 -0500209 if lab == nil {
210 lab = new(Label)
Russ Cox8c195bd2015-02-13 14:40:36 -0500211 lab.Sym = s
212 s.Label = lab
Robert Griesemerdef9c0b2016-03-10 20:35:27 -0800213 labellist = append(labellist, lab)
Russ Cox8c195bd2015-02-13 14:40:36 -0500214 }
215
216 if n.Op == OLABEL {
217 if lab.Def != nil {
Russ Cox17228f42015-04-17 12:03:22 -0400218 Yyerror("label %v already defined at %v", s, lab.Def.Line())
Russ Cox8c195bd2015-02-13 14:40:36 -0500219 } else {
220 lab.Def = n
221 }
222 } else {
Håvard Haugendd42eff2015-08-30 22:24:53 +0200223 lab.Use = append(lab.Use, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500224 }
225
226 return lab
227}
228
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700229// There is a copy of checkgoto in the new SSA backend.
230// Please keep them in sync.
Russ Cox8c195bd2015-02-13 14:40:36 -0500231func checkgoto(from *Node, to *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500232 if from.Sym == to.Sym {
233 return
234 }
235
Russ Cox382b44e2015-02-23 16:07:24 -0500236 nf := 0
237 for fs := from.Sym; fs != nil; fs = fs.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500238 nf++
239 }
Russ Cox382b44e2015-02-23 16:07:24 -0500240 nt := 0
241 for fs := to.Sym; fs != nil; fs = fs.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500242 nt++
243 }
Russ Cox382b44e2015-02-23 16:07:24 -0500244 fs := from.Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500245 for ; nf > nt; nf-- {
246 fs = fs.Link
247 }
248 if fs != to.Sym {
Robert Griesemerc41608f2016-03-02 17:34:42 -0800249 lno := lineno
Russ Cox8c195bd2015-02-13 14:40:36 -0500250 setlineno(from)
251
252 // decide what to complain about.
253 // prefer to complain about 'into block' over declarations,
254 // so scan backward to find most recent block or else dcl.
Russ Cox175929b2015-03-02 14:22:05 -0500255 var block *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500256
Russ Cox175929b2015-03-02 14:22:05 -0500257 var dcl *Sym
Brad Fitzpatrick97494a42015-05-15 16:35:43 +0000258 ts := to.Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500259 for ; nt > nf; nt-- {
260 if ts.Pkg == nil {
261 block = ts
Brad Fitzpatrick97494a42015-05-15 16:35:43 +0000262 } else {
Russ Cox8c195bd2015-02-13 14:40:36 -0500263 dcl = ts
264 }
265 ts = ts.Link
266 }
267
268 for ts != fs {
269 if ts.Pkg == nil {
270 block = ts
Brad Fitzpatrick97494a42015-05-15 16:35:43 +0000271 } else {
Russ Cox8c195bd2015-02-13 14:40:36 -0500272 dcl = ts
273 }
274 ts = ts.Link
275 fs = fs.Link
276 }
277
278 if block != nil {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800279 Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
Russ Cox8c195bd2015-02-13 14:40:36 -0500280 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800281 Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
Russ Cox8c195bd2015-02-13 14:40:36 -0500282 }
Robert Griesemerc41608f2016-03-02 17:34:42 -0800283 lineno = lno
Russ Cox8c195bd2015-02-13 14:40:36 -0500284 }
285}
286
287func stmtlabel(n *Node) *Label {
Russ Cox8c195bd2015-02-13 14:40:36 -0500288 if n.Sym != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500289 lab := n.Sym.Label
Russ Cox8c195bd2015-02-13 14:40:36 -0500290 if lab != nil {
291 if lab.Def != nil {
Russ Cox4fdd5362015-05-26 22:19:27 -0400292 if lab.Def.Name.Defn == n {
Russ Cox8c195bd2015-02-13 14:40:36 -0500293 return lab
294 }
295 }
296 }
297 }
298 return nil
299}
300
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900301// compile statements
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800302func Genlist(l Nodes) {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800303 for _, n := range l.Slice() {
304 gen(n)
Ian Lance Taylor188e3d22016-02-26 14:28:48 -0800305 }
306}
307
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900308// generate code to start new proc running call n.
Russ Cox8c195bd2015-02-13 14:40:36 -0500309func cgen_proc(n *Node, proc int) {
310 switch n.Left.Op {
311 default:
Dave Cheneyd3c79d32016-04-27 15:10:10 +1000312 Fatalf("cgen_proc: unknown call %v", n.Left.Op)
Russ Cox8c195bd2015-02-13 14:40:36 -0500313
314 case OCALLMETH:
Russ Coxb115c352015-03-18 17:26:36 -0400315 cgen_callmeth(n.Left, proc)
Russ Cox8c195bd2015-02-13 14:40:36 -0500316
317 case OCALLINTER:
Russ Coxb115c352015-03-18 17:26:36 -0400318 cgen_callinter(n.Left, nil, proc)
Russ Cox8c195bd2015-02-13 14:40:36 -0500319
320 case OCALLFUNC:
Russ Coxb115c352015-03-18 17:26:36 -0400321 cgen_call(n.Left, proc)
Russ Cox8c195bd2015-02-13 14:40:36 -0500322 }
323}
324
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900325// generate declaration.
326// have to allocate heap copy
327// for escaped variables.
Russ Cox8c195bd2015-02-13 14:40:36 -0500328func cgen_dcl(n *Node) {
329 if Debug['g'] != 0 {
330 Dump("\ncgen-dcl", n)
331 }
332 if n.Op != ONAME {
333 Dump("cgen_dcl", n)
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200334 Fatalf("cgen_dcl")
Russ Cox8c195bd2015-02-13 14:40:36 -0500335 }
336
Russ Coxb6dc3e62016-05-25 01:33:24 -0400337 if n.Class == PAUTOHEAP {
338 Fatalf("cgen_dcl %v", n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500339 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500340}
341
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900342// generate discard of value
Russ Cox8c195bd2015-02-13 14:40:36 -0500343func cgen_discard(nr *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500344 if nr == nil {
345 return
346 }
347
348 switch nr.Op {
349 case ONAME:
Russ Coxb6dc3e62016-05-25 01:33:24 -0400350 if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF {
Russ Cox8c195bd2015-02-13 14:40:36 -0500351 gused(nr)
352 }
353
354 // unary
355 case OADD,
356 OAND,
357 ODIV,
358 OEQ,
359 OGE,
360 OGT,
361 OLE,
362 OLSH,
363 OLT,
364 OMOD,
365 OMUL,
366 ONE,
367 OOR,
368 ORSH,
369 OSUB,
370 OXOR:
371 cgen_discard(nr.Left)
372
373 cgen_discard(nr.Right)
374
375 // binary
376 case OCAP,
377 OCOM,
378 OLEN,
379 OMINUS,
380 ONOT,
381 OPLUS:
382 cgen_discard(nr.Left)
383
384 case OIND:
385 Cgen_checknil(nr.Left)
386
387 // special enough to just evaluate
388 default:
Russ Cox382b44e2015-02-23 16:07:24 -0500389 var tmp Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500390 Tempname(&tmp, nr.Type)
391
392 Cgen_as(&tmp, nr)
393 gused(&tmp)
394 }
395}
396
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900397// clearslim generates code to zero a slim node.
Russ Cox8c195bd2015-02-13 14:40:36 -0500398func Clearslim(n *Node) {
Russ Cox175929b2015-03-02 14:22:05 -0500399 var z Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500400 z.Op = OLITERAL
401 z.Type = n.Type
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700402 z.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500403
404 switch Simtype[n.Type.Etype] {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700405 case TCOMPLEX64, TCOMPLEX128:
Russ Cox81d58102015-05-27 00:47:05 -0400406 z.SetVal(Val{new(Mpcplx)})
Matthew Dempskyd3253872016-03-20 13:55:42 -0700407 z.Val().U.(*Mpcplx).Real.SetFloat64(0.0)
408 z.Val().U.(*Mpcplx).Imag.SetFloat64(0.0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500409
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700410 case TFLOAT32, TFLOAT64:
Russ Cox382b44e2015-02-23 16:07:24 -0500411 var zero Mpflt
Matthew Dempskyd3253872016-03-20 13:55:42 -0700412 zero.SetFloat64(0.0)
Russ Cox81d58102015-05-27 00:47:05 -0400413 z.SetVal(Val{&zero})
Russ Cox8c195bd2015-02-13 14:40:36 -0500414
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700415 case TPTR32, TPTR64, TCHAN, TMAP:
Russ Cox81d58102015-05-27 00:47:05 -0400416 z.SetVal(Val{new(NilVal)})
Russ Cox8c195bd2015-02-13 14:40:36 -0500417
418 case TBOOL:
Russ Cox81d58102015-05-27 00:47:05 -0400419 z.SetVal(Val{false})
Russ Cox8c195bd2015-02-13 14:40:36 -0500420
421 case TINT8,
422 TINT16,
423 TINT32,
424 TINT64,
425 TUINT8,
426 TUINT16,
427 TUINT32,
428 TUINT64:
Russ Cox81d58102015-05-27 00:47:05 -0400429 z.SetVal(Val{new(Mpint)})
Matthew Dempskyd3253872016-03-20 13:55:42 -0700430 z.Val().U.(*Mpint).SetInt64(0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500431
432 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200433 Fatalf("clearslim called on type %v", n.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500434 }
435
436 ullmancalc(&z)
Russ Coxb115c352015-03-18 17:26:36 -0400437 Cgen(&z, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500438}
439
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900440// generate:
441// res = iface{typ, data}
442// n->left is typ
443// n->right is data
Russ Cox8c195bd2015-02-13 14:40:36 -0500444func Cgen_eface(n *Node, res *Node) {
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900445 // the right node of an eface may contain function calls that uses res as an argument,
446 // so it's important that it is done first
Russ Cox8c195bd2015-02-13 14:40:36 -0500447
Russ Cox382b44e2015-02-23 16:07:24 -0500448 tmp := temp(Types[Tptr])
Russ Coxb115c352015-03-18 17:26:36 -0400449 Cgen(n.Right, tmp)
Russ Cox8c195bd2015-02-13 14:40:36 -0500450
451 Gvardef(res)
452
Russ Cox382b44e2015-02-23 16:07:24 -0500453 dst := *res
Russ Cox8c195bd2015-02-13 14:40:36 -0500454 dst.Type = Types[Tptr]
455 dst.Xoffset += int64(Widthptr)
Russ Coxb115c352015-03-18 17:26:36 -0400456 Cgen(tmp, &dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500457
458 dst.Xoffset -= int64(Widthptr)
Russ Coxb115c352015-03-18 17:26:36 -0400459 Cgen(n.Left, &dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500460}
461
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900462// generate one of:
463// res, resok = x.(T)
464// res = x.(T) (when resok == nil)
465// n.Left is x
466// n.Type is T
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400467func cgen_dottype(n *Node, res, resok *Node, wb bool) {
Russ Cox4224d812015-03-20 00:06:10 -0400468 if Debug_typeassert > 0 {
469 Warn("type assertion inlined")
470 }
471 // iface := n.Left
472 // r1 := iword(iface)
473 // if n.Left is non-empty interface {
474 // r1 = *r1
475 // }
476 // if r1 == T {
477 // res = idata(iface)
478 // resok = true
479 // } else {
480 // assert[EI]2T(x, T, nil) // (when resok == nil; does not return)
481 // resok = false // (when resok != nil)
482 // }
483 //
484 var iface Node
485 Igen(n.Left, &iface, res)
486 var r1, r2 Node
487 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
488 Regalloc(&r1, byteptr, nil)
489 iface.Type = byteptr
490 Cgen(&iface, &r1)
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700491 if !n.Left.Type.IsEmptyInterface() {
Russ Cox4224d812015-03-20 00:06:10 -0400492 // Holding itab, want concrete type in second word.
Russ Coxf8d14fc2015-05-06 12:28:19 -0400493 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
Russ Cox4224d812015-03-20 00:06:10 -0400494 r2 = r1
495 r2.Op = OINDREG
496 r2.Xoffset = int64(Widthptr)
497 Cgen(&r2, &r1)
498 Patch(p, Pc)
499 }
500 Regalloc(&r2, byteptr, nil)
501 Cgen(typename(n.Type), &r2)
Russ Coxf8d14fc2015-05-06 12:28:19 -0400502 p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400503 Regfree(&r2) // not needed for success path; reclaimed on one failure path
Russ Cox4224d812015-03-20 00:06:10 -0400504 iface.Xoffset += int64(Widthptr)
505 Cgen(&iface, &r1)
506 Regfree(&iface)
507
508 if resok == nil {
509 r1.Type = res.Type
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400510 cgen_wb(&r1, res, wb)
Russ Cox4224d812015-03-20 00:06:10 -0400511 q := Gbranch(obj.AJMP, nil, 0)
512 Patch(p, Pc)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400513 Regrealloc(&r2) // reclaim from above, for this failure path
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800514 fn := syslook("panicdottype")
Russ Cox4224d812015-03-20 00:06:10 -0400515 dowidth(fn.Type)
516 call := Nod(OCALLFUNC, fn, nil)
517 r1.Type = byteptr
518 r2.Type = byteptr
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -0800519 call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800520 call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
Russ Cox4224d812015-03-20 00:06:10 -0400521 gen(call)
522 Regfree(&r1)
523 Regfree(&r2)
524 Thearch.Gins(obj.AUNDEF, nil, nil)
525 Patch(q, Pc)
526 } else {
527 // This half is handling the res, resok = x.(T) case,
528 // which is called from gen, not cgen, and is consequently fussier
529 // about blank assignments. We have to avoid calling cgen for those.
Russ Cox4224d812015-03-20 00:06:10 -0400530 r1.Type = res.Type
531 if !isblank(res) {
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400532 cgen_wb(&r1, res, wb)
Russ Cox4224d812015-03-20 00:06:10 -0400533 }
534 Regfree(&r1)
535 if !isblank(resok) {
536 Cgen(Nodbool(true), resok)
537 }
538 q := Gbranch(obj.AJMP, nil, 0)
539 Patch(p, Pc)
540 if !isblank(res) {
541 n := nodnil()
542 n.Type = res.Type
543 Cgen(n, res)
544 }
545 if !isblank(resok) {
546 Cgen(Nodbool(false), resok)
547 }
548 Patch(q, Pc)
549 }
550}
551
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900552// generate:
553// res, resok = x.(T)
554// n.Left is x
555// n.Type is T
Russ Cox4224d812015-03-20 00:06:10 -0400556func Cgen_As2dottype(n, res, resok *Node) {
557 if Debug_typeassert > 0 {
558 Warn("type assertion inlined")
559 }
560 // iface := n.Left
561 // r1 := iword(iface)
562 // if n.Left is non-empty interface {
563 // r1 = *r1
564 // }
565 // if r1 == T {
566 // res = idata(iface)
567 // resok = true
568 // } else {
569 // res = nil
570 // resok = false
571 // }
572 //
573 var iface Node
574 Igen(n.Left, &iface, nil)
575 var r1, r2 Node
576 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
577 Regalloc(&r1, byteptr, res)
578 iface.Type = byteptr
579 Cgen(&iface, &r1)
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700580 if !n.Left.Type.IsEmptyInterface() {
Russ Cox4224d812015-03-20 00:06:10 -0400581 // Holding itab, want concrete type in second word.
Russ Coxf8d14fc2015-05-06 12:28:19 -0400582 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
Russ Cox4224d812015-03-20 00:06:10 -0400583 r2 = r1
584 r2.Op = OINDREG
585 r2.Xoffset = int64(Widthptr)
586 Cgen(&r2, &r1)
587 Patch(p, Pc)
588 }
589 Regalloc(&r2, byteptr, nil)
590 Cgen(typename(n.Type), &r2)
Russ Coxf8d14fc2015-05-06 12:28:19 -0400591 p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
Russ Cox4224d812015-03-20 00:06:10 -0400592 iface.Type = n.Type
593 iface.Xoffset += int64(Widthptr)
594 Cgen(&iface, &r1)
595 if iface.Op != 0 {
596 Regfree(&iface)
597 }
598 Cgen(&r1, res)
599 q := Gbranch(obj.AJMP, nil, 0)
600 Patch(p, Pc)
601
Matthew Dempskydafbcf62016-03-04 15:19:06 -0800602 fn := syslook("panicdottype")
Russ Cox4224d812015-03-20 00:06:10 -0400603 dowidth(fn.Type)
604 call := Nod(OCALLFUNC, fn, nil)
Ian Lance Taylorf444b8a2016-03-09 20:29:21 -0800605 call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
Matthew Dempskyd20b92e2016-03-09 19:32:10 -0800606 call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
Russ Cox4224d812015-03-20 00:06:10 -0400607 gen(call)
608 Regfree(&r1)
609 Regfree(&r2)
610 Thearch.Gins(obj.AUNDEF, nil, nil)
611 Patch(q, Pc)
612}
613
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900614// gather series of offsets
615// >=0 is direct addressed field
616// <0 is pointer to next field (+1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500617func Dotoffset(n *Node, oary []int64, nn **Node) int {
618 var i int
619
620 switch n.Op {
621 case ODOT:
622 if n.Xoffset == BADWIDTH {
623 Dump("bad width in dotoffset", n)
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200624 Fatalf("bad width in dotoffset")
Russ Cox8c195bd2015-02-13 14:40:36 -0500625 }
626
627 i = Dotoffset(n.Left, oary, nn)
628 if i > 0 {
629 if oary[i-1] >= 0 {
630 oary[i-1] += n.Xoffset
631 } else {
632 oary[i-1] -= n.Xoffset
633 }
634 break
635 }
636
637 if i < 10 {
638 oary[i] = n.Xoffset
639 i++
640 }
641
642 case ODOTPTR:
643 if n.Xoffset == BADWIDTH {
644 Dump("bad width in dotoffset", n)
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200645 Fatalf("bad width in dotoffset")
Russ Cox8c195bd2015-02-13 14:40:36 -0500646 }
647
648 i = Dotoffset(n.Left, oary, nn)
649 if i < 10 {
650 oary[i] = -(n.Xoffset + 1)
651 i++
652 }
653
654 default:
655 *nn = n
656 return 0
657 }
658
659 if i >= 10 {
660 *nn = nil
661 }
662 return i
663}
664
Jeremy Jackins6327e8d2015-10-22 09:51:12 +0900665// make a new off the books
Russ Cox8c195bd2015-02-13 14:40:36 -0500666func Tempname(nn *Node, t *Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500667 if Curfn == nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200668 Fatalf("no curfn for tempname")
Russ Cox8c195bd2015-02-13 14:40:36 -0500669 }
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800670 if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
671 Dump("Tempname", Curfn)
672 Fatalf("adding tempname to wrong closure function")
673 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500674
675 if t == nil {
676 Yyerror("tempname called with nil type")
677 t = Types[TINT32]
678 }
679
680 // give each tmp a different name so that there
681 // a chance to registerizer them
Brad Fitzpatrick060a6912016-03-19 18:17:58 -0700682 s := LookupN("autotmp_", statuniqgen)
Russ Cox8c195bd2015-02-13 14:40:36 -0500683 statuniqgen++
Russ Cox382b44e2015-02-23 16:07:24 -0500684 n := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500685 n.Sym = s
686 s.Def = n
687 n.Type = t
688 n.Class = PAUTO
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700689 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500690 n.Ullman = 1
691 n.Esc = EscNever
Russ Coxfd2154f2015-05-27 07:31:56 -0400692 n.Name.Curfn = Curfn
Ian Lance Taylorb66a8922016-02-25 10:35:19 -0800693 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500694
695 dowidth(t)
696 n.Xoffset = 0
697 *nn = *n
698}
699
700func temp(t *Type) *Node {
Dave Cheneyedca4cd2016-03-23 16:01:15 +1100701 var n Node
702 Tempname(&n, t)
Dave Cheney44e90312015-03-06 21:18:41 +1100703 n.Sym.Def.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500704 return n.Orig
705}
706
707func gen(n *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500708 //dump("gen", n);
709
Russ Cox382b44e2015-02-23 16:07:24 -0500710 lno := setlineno(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500711
Russ Coxb115c352015-03-18 17:26:36 -0400712 wasregalloc := Anyregalloc()
Russ Cox8c195bd2015-02-13 14:40:36 -0500713
714 if n == nil {
715 goto ret
716 }
717
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800718 if n.Ninit.Len() > 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500719 Genlist(n.Ninit)
720 }
721
722 setlineno(n)
723
724 switch n.Op {
725 default:
Matthew Dempsky63142022016-03-15 13:06:58 -0700726 Fatalf("gen: unknown op %v", Nconv(n, FmtShort|FmtSign))
Russ Cox8c195bd2015-02-13 14:40:36 -0500727
728 case OCASE,
729 OFALL,
730 OXCASE,
731 OXFALL,
732 ODCLCONST,
733 ODCLFUNC,
734 ODCLTYPE:
735 break
736
737 case OEMPTY:
738 break
739
740 case OBLOCK:
741 Genlist(n.List)
742
743 case OLABEL:
744 if isblanksym(n.Left.Sym) {
745 break
746 }
747
Russ Cox382b44e2015-02-23 16:07:24 -0500748 lab := newlab(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500749
750 // if there are pending gotos, resolve them all to the current pc.
Russ Cox382b44e2015-02-23 16:07:24 -0500751 var p2 *obj.Prog
752 for p1 := lab.Gotopc; p1 != nil; p1 = p2 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500753 p2 = unpatch(p1)
754 Patch(p1, Pc)
755 }
756
757 lab.Gotopc = nil
758 if lab.Labelpc == nil {
759 lab.Labelpc = Pc
760 }
761
Russ Cox4fdd5362015-05-26 22:19:27 -0400762 if n.Name.Defn != nil {
763 switch n.Name.Defn.Op {
Russ Cox8c195bd2015-02-13 14:40:36 -0500764 // so stmtlabel can find the label
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700765 case OFOR, OSWITCH, OSELECT:
Russ Cox4fdd5362015-05-26 22:19:27 -0400766 n.Name.Defn.Sym = lab.Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500767 }
768 }
769
770 // if label is defined, emit jump to it.
771 // otherwise save list of pending gotos in lab->gotopc.
772 // the list is linked through the normal jump target field
773 // to avoid a second list. (the jumps are actually still
774 // valid code, since they're just going to another goto
775 // to the same label. we'll unwind it when we learn the pc
776 // of the label in the OLABEL case above.)
777 case OGOTO:
Russ Cox382b44e2015-02-23 16:07:24 -0500778 lab := newlab(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500779
780 if lab.Labelpc != nil {
781 gjmp(lab.Labelpc)
782 } else {
783 lab.Gotopc = gjmp(lab.Gotopc)
784 }
785
786 case OBREAK:
787 if n.Left != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500788 lab := n.Left.Sym.Label
Russ Cox8c195bd2015-02-13 14:40:36 -0500789 if lab == nil {
Russ Cox17228f42015-04-17 12:03:22 -0400790 Yyerror("break label not defined: %v", n.Left.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500791 break
792 }
793
Dave Cheney8712e182015-09-07 11:11:14 +1000794 lab.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 if lab.Breakpc == nil {
Russ Cox17228f42015-04-17 12:03:22 -0400796 Yyerror("invalid break label %v", n.Left.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500797 break
798 }
799
800 gjmp(lab.Breakpc)
801 break
802 }
803
804 if breakpc == nil {
805 Yyerror("break is not in a loop")
806 break
807 }
808
809 gjmp(breakpc)
810
811 case OCONTINUE:
812 if n.Left != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500813 lab := n.Left.Sym.Label
Russ Cox8c195bd2015-02-13 14:40:36 -0500814 if lab == nil {
Russ Cox17228f42015-04-17 12:03:22 -0400815 Yyerror("continue label not defined: %v", n.Left.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500816 break
817 }
818
Dave Cheney8712e182015-09-07 11:11:14 +1000819 lab.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500820 if lab.Continpc == nil {
Russ Cox17228f42015-04-17 12:03:22 -0400821 Yyerror("invalid continue label %v", n.Left.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500822 break
823 }
824
825 gjmp(lab.Continpc)
826 break
827 }
828
829 if continpc == nil {
830 Yyerror("continue is not in a loop")
831 break
832 }
833
834 gjmp(continpc)
835
836 case OFOR:
Russ Cox382b44e2015-02-23 16:07:24 -0500837 sbreak := breakpc
838 p1 := gjmp(nil) // goto test
Russ Cox8c195bd2015-02-13 14:40:36 -0500839 breakpc = gjmp(nil) // break: goto done
Russ Cox382b44e2015-02-23 16:07:24 -0500840 scontin := continpc
Russ Cox8c195bd2015-02-13 14:40:36 -0500841 continpc = Pc
842
843 // define break and continue labels
Russ Cox382b44e2015-02-23 16:07:24 -0500844 lab := stmtlabel(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500845 if lab != nil {
846 lab.Breakpc = breakpc
847 lab.Continpc = continpc
848 }
849
Russ Cox66be1482015-05-26 21:30:20 -0400850 gen(n.Right) // contin: incr
851 Patch(p1, Pc) // test:
852 Bgen(n.Left, false, -1, breakpc) // if(!test) goto break
Ian Lance Taylorbf390982016-03-03 15:08:25 -0800853 Genlist(n.Nbody) // body
Russ Cox8c195bd2015-02-13 14:40:36 -0500854 gjmp(continpc)
855 Patch(breakpc, Pc) // done:
856 continpc = scontin
857 breakpc = sbreak
858 if lab != nil {
859 lab.Breakpc = nil
860 lab.Continpc = nil
861 }
862
863 case OIF:
Russ Cox66be1482015-05-26 21:30:20 -0400864 p1 := gjmp(nil) // goto test
865 p2 := gjmp(nil) // p2: goto else
866 Patch(p1, Pc) // test:
867 Bgen(n.Left, false, int(-n.Likely), p2) // if(!test) goto p2
Ian Lance Taylorbf390982016-03-03 15:08:25 -0800868 Genlist(n.Nbody) // then
Russ Cox66be1482015-05-26 21:30:20 -0400869 p3 := gjmp(nil) // goto done
870 Patch(p2, Pc) // else:
871 Genlist(n.Rlist) // else
872 Patch(p3, Pc) // done:
Russ Cox8c195bd2015-02-13 14:40:36 -0500873
874 case OSWITCH:
Russ Cox382b44e2015-02-23 16:07:24 -0500875 sbreak := breakpc
876 p1 := gjmp(nil) // goto test
Russ Cox8c195bd2015-02-13 14:40:36 -0500877 breakpc = gjmp(nil) // break: goto done
878
879 // define break label
Russ Cox382b44e2015-02-23 16:07:24 -0500880 lab := stmtlabel(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500881 if lab != nil {
882 lab.Breakpc = breakpc
883 }
884
Ian Lance Taylorbf390982016-03-03 15:08:25 -0800885 Patch(p1, Pc) // test:
886 Genlist(n.Nbody) // switch(test) body
887 Patch(breakpc, Pc) // done:
Russ Cox8c195bd2015-02-13 14:40:36 -0500888 breakpc = sbreak
889 if lab != nil {
890 lab.Breakpc = nil
891 }
892
893 case OSELECT:
Russ Cox382b44e2015-02-23 16:07:24 -0500894 sbreak := breakpc
895 p1 := gjmp(nil) // goto test
Russ Cox8c195bd2015-02-13 14:40:36 -0500896 breakpc = gjmp(nil) // break: goto done
897
898 // define break label
Russ Cox382b44e2015-02-23 16:07:24 -0500899 lab := stmtlabel(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500900 if lab != nil {
901 lab.Breakpc = breakpc
902 }
903
Ian Lance Taylorbf390982016-03-03 15:08:25 -0800904 Patch(p1, Pc) // test:
905 Genlist(n.Nbody) // select() body
906 Patch(breakpc, Pc) // done:
Russ Cox8c195bd2015-02-13 14:40:36 -0500907 breakpc = sbreak
908 if lab != nil {
909 lab.Breakpc = nil
910 }
911
912 case ODCL:
913 cgen_dcl(n.Left)
914
915 case OAS:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700916 if gen_as_init(n, false) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500917 break
918 }
919 Cgen_as(n.Left, n.Right)
920
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400921 case OASWB:
922 Cgen_as_wb(n.Left, n.Right, true)
923
Russ Cox4224d812015-03-20 00:06:10 -0400924 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800925 cgen_dottype(n.Rlist.First(), n.List.First(), n.List.Second(), needwritebarrier(n.List.First(), n.Rlist.First()))
Russ Cox4224d812015-03-20 00:06:10 -0400926
Russ Cox8c195bd2015-02-13 14:40:36 -0500927 case OCALLMETH:
Russ Coxb115c352015-03-18 17:26:36 -0400928 cgen_callmeth(n, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500929
930 case OCALLINTER:
Russ Coxb115c352015-03-18 17:26:36 -0400931 cgen_callinter(n, nil, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500932
933 case OCALLFUNC:
Russ Coxb115c352015-03-18 17:26:36 -0400934 cgen_call(n, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500935
936 case OPROC:
937 cgen_proc(n, 1)
938
939 case ODEFER:
940 cgen_proc(n, 2)
941
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700942 case ORETURN, ORETJMP:
Russ Coxb115c352015-03-18 17:26:36 -0400943 cgen_ret(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500944
Russ Cox92c826b2015-04-03 12:23:28 -0400945 // Function calls turned into compiler intrinsics.
946 // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
947 case OGETG:
948 // nothing
Russ Cox92dba0d2015-04-01 16:02:34 -0400949 case OSQRT:
950 cgen_discard(n.Left)
951
Russ Cox8c195bd2015-02-13 14:40:36 -0500952 case OCHECKNIL:
953 Cgen_checknil(n.Left)
954
955 case OVARKILL:
Michael Pratta4e31d42016-03-12 14:07:40 -0800956 Gvarkill(n.Left)
Russ Cox1ac637c2016-01-13 00:46:28 -0500957
958 case OVARLIVE:
Michael Pratta4e31d42016-03-12 14:07:40 -0800959 Gvarlive(n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500960 }
961
962ret:
Russ Coxb115c352015-03-18 17:26:36 -0400963 if Anyregalloc() != wasregalloc {
Russ Cox8c195bd2015-02-13 14:40:36 -0500964 Dump("node", n)
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200965 Fatalf("registers left allocated")
Russ Cox8c195bd2015-02-13 14:40:36 -0500966 }
967
968 lineno = lno
969}
970
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400971func Cgen_as(nl, nr *Node) {
972 Cgen_as_wb(nl, nr, false)
973}
974
975func Cgen_as_wb(nl, nr *Node, wb bool) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500976 if Debug['g'] != 0 {
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400977 op := "cgen_as"
978 if wb {
979 op = "cgen_as_wb"
980 }
981 Dump(op, nl)
982 Dump(op+" = ", nr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500983 }
984
985 for nr != nil && nr.Op == OCONVNOP {
986 nr = nr.Left
987 }
988
989 if nl == nil || isblank(nl) {
990 cgen_discard(nr)
991 return
992 }
993
Russ Coxdc7b54b2015-02-17 22:13:49 -0500994 if nr == nil || iszero(nr) {
Russ Cox382b44e2015-02-23 16:07:24 -0500995 tl := nl.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500996 if tl == nil {
997 return
998 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500999 if Isfat(tl) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001000 if nl.Op == ONAME {
1001 Gvardef(nl)
1002 }
1003 Thearch.Clearfat(nl)
1004 return
1005 }
1006
1007 Clearslim(nl)
1008 return
1009 }
1010
Russ Cox382b44e2015-02-23 16:07:24 -05001011 tl := nl.Type
Russ Cox8c195bd2015-02-13 14:40:36 -05001012 if tl == nil {
1013 return
1014 }
1015
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001016 cgen_wb(nr, nl, wb)
Russ Cox8c195bd2015-02-13 14:40:36 -05001017}
1018
Russ Coxb115c352015-03-18 17:26:36 -04001019func cgen_callmeth(n *Node, proc int) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001020 // generate a rewrite in n2 for the method call
1021 // (p.f)(...) goes to (f)(p,...)
1022
Russ Cox382b44e2015-02-23 16:07:24 -05001023 l := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -05001024
1025 if l.Op != ODOTMETH {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001026 Fatalf("cgen_callmeth: not dotmethod: %v", l)
Russ Cox8c195bd2015-02-13 14:40:36 -05001027 }
1028
Russ Cox382b44e2015-02-23 16:07:24 -05001029 n2 := *n
Russ Cox8c195bd2015-02-13 14:40:36 -05001030 n2.Op = OCALLFUNC
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07001031 n2.Left = newname(l.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05001032 n2.Left.Type = l.Type
1033
1034 if n2.Left.Op == ONAME {
1035 n2.Left.Class = PFUNC
1036 }
Russ Coxb115c352015-03-18 17:26:36 -04001037 cgen_call(&n2, proc)
Russ Cox8c195bd2015-02-13 14:40:36 -05001038}
1039
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001040// CgenTemp creates a temporary node, assigns n to it, and returns it.
1041func CgenTemp(n *Node) *Node {
1042 var tmp Node
1043 Tempname(&tmp, n.Type)
1044 Cgen(n, &tmp)
1045 return &tmp
1046}
1047
Russ Cox8c195bd2015-02-13 14:40:36 -05001048func checklabels() {
Robert Griesemerdef9c0b2016-03-10 20:35:27 -08001049 for _, lab := range labellist {
Russ Cox8c195bd2015-02-13 14:40:36 -05001050 if lab.Def == nil {
Håvard Haugendd42eff2015-08-30 22:24:53 +02001051 for _, n := range lab.Use {
Robert Griesemerb83f3972016-03-02 11:01:25 -08001052 yyerrorl(n.Lineno, "label %v not defined", lab.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05001053 }
1054 continue
1055 }
1056
Dave Cheney8712e182015-09-07 11:11:14 +10001057 if lab.Use == nil && !lab.Used {
Robert Griesemerb83f3972016-03-02 11:01:25 -08001058 yyerrorl(lab.Def.Lineno, "label %v defined and not used", lab.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05001059 continue
1060 }
1061
1062 if lab.Gotopc != nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001063 Fatalf("label %v never resolved", lab.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -05001064 }
Håvard Haugendd42eff2015-08-30 22:24:53 +02001065 for _, n := range lab.Use {
1066 checkgoto(n, lab.Def)
Russ Cox8c195bd2015-02-13 14:40:36 -05001067 }
1068 }
1069}
Russ Coxb9602632015-03-18 12:29:40 -04001070
Dave Cheney4b21be42015-04-09 20:10:16 +10001071// Componentgen copies a composite value by moving its individual components.
1072// Slices, strings and interfaces are supported. Small structs or arrays with
1073// elements of basic type are also supported.
1074// nr is nil when assigning a zero value.
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001075func Componentgen(nr, nl *Node) bool {
1076 return componentgen_wb(nr, nl, false)
1077}
1078
1079// componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
1080func componentgen_wb(nr, nl *Node, wb bool) bool {
1081 // Don't generate any code for complete copy of a variable into itself.
1082 // It's useless, and the VARDEF will incorrectly mark the old value as dead.
1083 // (This check assumes that the arguments passed to componentgen did not
1084 // themselves come from Igen, or else we could have Op==ONAME but
1085 // with a Type and Xoffset describing an individual field, not the entire
1086 // variable.)
1087 if nl.Op == ONAME && nl == nr {
1088 return true
1089 }
1090
Russ Cox35b1dcc2015-04-16 16:22:30 -04001091 // Count number of moves required to move components.
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001092 // If using write barrier, can only emit one pointer.
1093 // TODO(rsc): Allow more pointers, for reflect.Value.
Russ Cox35b1dcc2015-04-16 16:22:30 -04001094 const maxMoves = 8
1095 n := 0
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001096 numPtr := 0
Russ Cox35b1dcc2015-04-16 16:22:30 -04001097 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
1098 n++
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001099 if Simtype[t.Etype] == Tptr && t != itable {
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001100 numPtr++
1101 }
1102 return n <= maxMoves && (!wb || numPtr <= 1)
Russ Cox35b1dcc2015-04-16 16:22:30 -04001103 })
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001104 if n > maxMoves || wb && numPtr > 1 {
Dave Cheney4b21be42015-04-09 20:10:16 +10001105 return false
Russ Coxb9602632015-03-18 12:29:40 -04001106 }
1107
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001108 // Must call emitVardef after evaluating rhs but before writing to lhs.
Russ Cox35b1dcc2015-04-16 16:22:30 -04001109 emitVardef := func() {
1110 // Emit vardef if needed.
1111 if nl.Op == ONAME {
1112 switch nl.Type.Etype {
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07001113 case TARRAY, TSLICE, TSTRING, TINTER, TSTRUCT:
Russ Cox35b1dcc2015-04-16 16:22:30 -04001114 Gvardef(nl)
1115 }
Russ Coxb9602632015-03-18 12:29:40 -04001116 }
Russ Cox35b1dcc2015-04-16 16:22:30 -04001117 }
1118
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001119 isConstString := Isconst(nr, CTSTR)
1120
1121 if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
1122 return false
1123 }
1124
1125 var nodl Node
1126 if cadable(nl) {
1127 nodl = *nl
1128 } else {
1129 if nr != nil && !cadable(nr) && !isConstString {
1130 return false
1131 }
1132 if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
1133 Igen(nl, &nodl, nil)
1134 defer Regfree(&nodl)
1135 }
1136 }
1137 lbase := nodl.Xoffset
1138
Russ Cox35b1dcc2015-04-16 16:22:30 -04001139 // Special case: zeroing.
1140 var nodr Node
1141 if nr == nil {
Russ Coxb9602632015-03-18 12:29:40 -04001142 // When zeroing, prepare a register containing zero.
Russ Cox35b1dcc2015-04-16 16:22:30 -04001143 // TODO(rsc): Check that this is actually generating the best code.
Dave Cheney888d44d2015-04-09 21:25:48 +10001144 if Thearch.REGZERO != 0 {
1145 // cpu has a dedicated zero register
1146 Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
1147 } else {
1148 // no dedicated zero register
Russ Cox35b1dcc2015-04-16 16:22:30 -04001149 var zero Node
1150 Nodconst(&zero, nl.Type, 0)
Dave Cheney888d44d2015-04-09 21:25:48 +10001151 Regalloc(&nodr, Types[TUINT], nil)
Russ Cox35b1dcc2015-04-16 16:22:30 -04001152 Thearch.Gmove(&zero, &nodr)
Dave Cheney888d44d2015-04-09 21:25:48 +10001153 defer Regfree(&nodr)
1154 }
Russ Coxb9602632015-03-18 12:29:40 -04001155
Russ Cox35b1dcc2015-04-16 16:22:30 -04001156 emitVardef()
1157 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
1158 nodl.Type = t
1159 nodl.Xoffset = lbase + offset
1160 nodr.Type = t
Matthew Dempskye76fc1b2016-03-30 15:09:25 -07001161 if t.IsFloat() {
Russ Cox35b1dcc2015-04-16 16:22:30 -04001162 // TODO(rsc): Cache zero register like we do for integers?
1163 Clearslim(&nodl)
1164 } else {
1165 Thearch.Gmove(&nodr, &nodl)
1166 }
1167 return true
1168 })
Dave Cheney4b21be42015-04-09 20:10:16 +10001169 return true
Russ Coxb9602632015-03-18 12:29:40 -04001170 }
1171
Russ Cox35b1dcc2015-04-16 16:22:30 -04001172 // Special case: assignment of string constant.
1173 if isConstString {
1174 emitVardef()
Dave Cheney4b21be42015-04-09 20:10:16 +10001175
Russ Cox35b1dcc2015-04-16 16:22:30 -04001176 // base
1177 nodl.Type = Ptrto(Types[TUINT8])
1178 Regalloc(&nodr, Types[Tptr], nil)
1179 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
Russ Cox81d58102015-05-27 00:47:05 -04001180 Datastring(nr.Val().U.(string), &p.From)
Russ Cox35b1dcc2015-04-16 16:22:30 -04001181 p.From.Type = obj.TYPE_ADDR
Russ Coxb9602632015-03-18 12:29:40 -04001182 Thearch.Gmove(&nodr, &nodl)
Russ Cox35b1dcc2015-04-16 16:22:30 -04001183 Regfree(&nodr)
Russ Coxb9602632015-03-18 12:29:40 -04001184
Russ Cox35b1dcc2015-04-16 16:22:30 -04001185 // length
1186 nodl.Type = Types[Simtype[TUINT]]
Russ Coxb9602632015-03-18 12:29:40 -04001187 nodl.Xoffset += int64(Array_nel) - int64(Array_array)
Russ Cox81d58102015-05-27 00:47:05 -04001188 Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string))))
Russ Coxb9602632015-03-18 12:29:40 -04001189 Thearch.Gmove(&nodr, &nodl)
Russ Cox35b1dcc2015-04-16 16:22:30 -04001190 return true
1191 }
Russ Coxb9602632015-03-18 12:29:40 -04001192
Russ Cox35b1dcc2015-04-16 16:22:30 -04001193 // General case: copy nl = nr.
1194 nodr = *nr
1195 if !cadable(nr) {
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001196 if nr.Ullman >= UINF && nodl.Op == OINDREG {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001197 Fatalf("miscompile")
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001198 }
Russ Cox35b1dcc2015-04-16 16:22:30 -04001199 Igen(nr, &nodr, nil)
1200 defer Regfree(&nodr)
1201 }
1202 rbase := nodr.Xoffset
Russ Coxb9602632015-03-18 12:29:40 -04001203
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001204 if nodl.Op == 0 {
1205 Igen(nl, &nodl, nil)
1206 defer Regfree(&nodl)
1207 lbase = nodl.Xoffset
Russ Cox35b1dcc2015-04-16 16:22:30 -04001208 }
Russ Coxb9602632015-03-18 12:29:40 -04001209
Russ Cox35b1dcc2015-04-16 16:22:30 -04001210 emitVardef()
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001211 var (
1212 ptrType *Type
1213 ptrOffset int64
1214 )
Russ Cox35b1dcc2015-04-16 16:22:30 -04001215 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +02001216 if wb && Simtype[t.Etype] == Tptr && t != itable {
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001217 if ptrType != nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001218 Fatalf("componentgen_wb %v", Tconv(nl.Type, 0))
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001219 }
1220 ptrType = t
1221 ptrOffset = offset
1222 return true
1223 }
Russ Cox35b1dcc2015-04-16 16:22:30 -04001224 nodl.Type = t
1225 nodl.Xoffset = lbase + offset
1226 nodr.Type = t
1227 nodr.Xoffset = rbase + offset
Russ Coxb9602632015-03-18 12:29:40 -04001228 Thearch.Gmove(&nodr, &nodl)
Dave Cheney4b21be42015-04-09 20:10:16 +10001229 return true
Russ Cox35b1dcc2015-04-16 16:22:30 -04001230 })
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001231 if ptrType != nil {
1232 nodl.Type = ptrType
1233 nodl.Xoffset = lbase + ptrOffset
1234 nodr.Type = ptrType
1235 nodr.Xoffset = rbase + ptrOffset
1236 cgen_wbptr(&nodr, &nodl)
1237 }
Russ Cox35b1dcc2015-04-16 16:22:30 -04001238 return true
1239}
1240
1241// visitComponents walks the individual components of the type t,
1242// walking into array elements, struct fields, the real and imaginary
1243// parts of complex numbers, and on 32-bit systems the high and
1244// low halves of 64-bit integers.
1245// It calls f for each such component, passing the component (aka element)
1246// type and memory offset, assuming t starts at startOffset.
1247// If f ever returns false, visitComponents returns false without any more
1248// calls to f. Otherwise visitComponents returns true.
1249func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
1250 switch t.Etype {
1251 case TINT64:
1252 if Widthreg == 8 {
1253 break
1254 }
1255 // NOTE: Assuming little endian (signed top half at offset 4).
1256 // We don't have any 32-bit big-endian systems.
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07001257 if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001258 Fatalf("unknown 32-bit architecture")
Russ Cox35b1dcc2015-04-16 16:22:30 -04001259 }
1260 return f(Types[TUINT32], startOffset) &&
1261 f(Types[TINT32], startOffset+4)
1262
1263 case TUINT64:
1264 if Widthreg == 8 {
1265 break
1266 }
1267 return f(Types[TUINT32], startOffset) &&
1268 f(Types[TUINT32], startOffset+4)
1269
1270 case TCOMPLEX64:
1271 return f(Types[TFLOAT32], startOffset) &&
1272 f(Types[TFLOAT32], startOffset+4)
1273
1274 case TCOMPLEX128:
1275 return f(Types[TFLOAT64], startOffset) &&
1276 f(Types[TFLOAT64], startOffset+8)
1277
1278 case TINTER:
Russ Cox0ad4f8b2015-04-17 00:25:10 -04001279 return f(itable, startOffset) &&
Russ Cox35b1dcc2015-04-16 16:22:30 -04001280 f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
Russ Coxb9602632015-03-18 12:29:40 -04001281
1282 case TSTRING:
Russ Cox35b1dcc2015-04-16 16:22:30 -04001283 return f(Ptrto(Types[TUINT8]), startOffset) &&
1284 f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
Russ Coxb9602632015-03-18 12:29:40 -04001285
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07001286 case TSLICE:
1287 return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
1288 f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
1289 f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
Russ Coxb9602632015-03-18 12:29:40 -04001290
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07001291 case TARRAY:
Russ Cox35b1dcc2015-04-16 16:22:30 -04001292 // Short-circuit [1e6]struct{}.
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001293 if t.Elem().Width == 0 {
Russ Cox35b1dcc2015-04-16 16:22:30 -04001294 return true
Russ Coxb9602632015-03-18 12:29:40 -04001295 }
1296
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001297 for i := int64(0); i < t.NumElem(); i++ {
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001298 if !visitComponents(t.Elem(), startOffset+i*t.Elem().Width, f) {
Russ Cox35b1dcc2015-04-16 16:22:30 -04001299 return false
1300 }
Russ Coxb9602632015-03-18 12:29:40 -04001301 }
Dave Cheney4b21be42015-04-09 20:10:16 +10001302 return true
Russ Coxb9602632015-03-18 12:29:40 -04001303
1304 case TSTRUCT:
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07001305 for _, field := range t.Fields().Slice() {
Matthew Dempsky62dddd42016-03-28 09:40:53 -07001306 if !visitComponents(field.Type, startOffset+field.Offset, f) {
Russ Cox35b1dcc2015-04-16 16:22:30 -04001307 return false
Russ Coxb9602632015-03-18 12:29:40 -04001308 }
1309 }
Dave Cheney4b21be42015-04-09 20:10:16 +10001310 return true
Russ Coxb9602632015-03-18 12:29:40 -04001311 }
Russ Cox35b1dcc2015-04-16 16:22:30 -04001312 return f(t, startOffset)
Russ Coxb9602632015-03-18 12:29:40 -04001313}
1314
1315func cadable(n *Node) bool {
Russ Cox35b1dcc2015-04-16 16:22:30 -04001316 // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
1317 return n.Addable && n.Op == ONAME
Russ Coxb9602632015-03-18 12:29:40 -04001318}