]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/gen.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
[gostls13.git] / src / cmd / compile / internal / gc / gen.go
1 // 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
5 package gc
6
7 import (
8         "cmd/internal/obj"
9         "fmt"
10 )
11
12 // portable half of code generator.
13 // mainly statements and control flow.
14 var labellist *Label
15
16 var lastlabel *Label
17
18 func Sysfunc(name string) *Node {
19         n := newname(Pkglookup(name, Runtimepkg))
20         n.Class = PFUNC
21         return n
22 }
23
24 // 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.
28 func addrescapes(n *Node) {
29         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
46                 switch n.Class {
47                 case PPARAMREF:
48                         addrescapes(n.Name.Defn)
49
50                 // if func param, need separate temporary
51                 // to hold heap pointer.
52                 // the function type has already been checked
53                 // (we're in the function body)
54                 // so the param already has a valid xoffset.
55
56                 // expression to refer to stack copy
57                 case PPARAM, PPARAMOUT:
58                         n.Name.Param.Stackparam = Nod(OPARAM, n, nil)
59
60                         n.Name.Param.Stackparam.Type = n.Type
61                         n.Name.Param.Stackparam.Addable = true
62                         if n.Xoffset == BADWIDTH {
63                                 Fatalf("addrescapes before param assignment")
64                         }
65                         n.Name.Param.Stackparam.Xoffset = n.Xoffset
66                         fallthrough
67
68                 case PAUTO:
69                         n.Class |= PHEAP
70
71                         n.Addable = false
72                         n.Ullman = 2
73                         n.Xoffset = 0
74
75                         // create stack variable to hold pointer to heap
76                         oldfn := Curfn
77
78                         Curfn = n.Name.Curfn
79                         n.Name.Heapaddr = temp(Ptrto(n.Type))
80                         buf := fmt.Sprintf("&%v", n.Sym)
81                         n.Name.Heapaddr.Sym = Lookup(buf)
82                         n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym
83                         n.Esc = EscHeap
84                         if Debug['m'] != 0 {
85                                 fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
86                         }
87                         Curfn = oldfn
88                 }
89
90         case OIND, ODOTPTR:
91                 break
92
93         // ODOTPTR has already been introduced,
94         // so these are the non-pointer ODOT and OINDEX.
95         // In &x[0], if x is a slice, then x does not
96         // escape--the pointer inside x does, but that
97         // is always a heap pointer anyway.
98         case ODOT, OINDEX, OPAREN, OCONVNOP:
99                 if !Isslice(n.Left.Type) {
100                         addrescapes(n.Left)
101                 }
102         }
103 }
104
105 func clearlabels() {
106         for l := labellist; l != nil; l = l.Link {
107                 l.Sym.Label = nil
108         }
109
110         labellist = nil
111         lastlabel = nil
112 }
113
114 func newlab(n *Node) *Label {
115         s := n.Left.Sym
116         lab := s.Label
117         if lab == nil {
118                 lab = new(Label)
119                 if lastlabel == nil {
120                         labellist = lab
121                 } else {
122                         lastlabel.Link = lab
123                 }
124                 lastlabel = lab
125                 lab.Sym = s
126                 s.Label = lab
127         }
128
129         if n.Op == OLABEL {
130                 if lab.Def != nil {
131                         Yyerror("label %v already defined at %v", s, lab.Def.Line())
132                 } else {
133                         lab.Def = n
134                 }
135         } else {
136                 lab.Use = append(lab.Use, n)
137         }
138
139         return lab
140 }
141
142 // There is a copy of checkgoto in the new SSA backend.
143 // Please keep them in sync.
144 func checkgoto(from *Node, to *Node) {
145         if from.Sym == to.Sym {
146                 return
147         }
148
149         nf := 0
150         for fs := from.Sym; fs != nil; fs = fs.Link {
151                 nf++
152         }
153         nt := 0
154         for fs := to.Sym; fs != nil; fs = fs.Link {
155                 nt++
156         }
157         fs := from.Sym
158         for ; nf > nt; nf-- {
159                 fs = fs.Link
160         }
161         if fs != to.Sym {
162                 lno := int(lineno)
163                 setlineno(from)
164
165                 // decide what to complain about.
166                 // prefer to complain about 'into block' over declarations,
167                 // so scan backward to find most recent block or else dcl.
168                 var block *Sym
169
170                 var dcl *Sym
171                 ts := to.Sym
172                 for ; nt > nf; nt-- {
173                         if ts.Pkg == nil {
174                                 block = ts
175                         } else {
176                                 dcl = ts
177                         }
178                         ts = ts.Link
179                 }
180
181                 for ts != fs {
182                         if ts.Pkg == nil {
183                                 block = ts
184                         } else {
185                                 dcl = ts
186                         }
187                         ts = ts.Link
188                         fs = fs.Link
189                 }
190
191                 if block != nil {
192                         Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
193                 } else {
194                         Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
195                 }
196                 lineno = int32(lno)
197         }
198 }
199
200 func stmtlabel(n *Node) *Label {
201         if n.Sym != nil {
202                 lab := n.Sym.Label
203                 if lab != nil {
204                         if lab.Def != nil {
205                                 if lab.Def.Name.Defn == n {
206                                         return lab
207                                 }
208                         }
209                 }
210         }
211         return nil
212 }
213
214 // compile statements
215 func Genlist(l *NodeList) {
216         for ; l != nil; l = l.Next {
217                 gen(l.N)
218         }
219 }
220
221 // generate code to start new proc running call n.
222 func cgen_proc(n *Node, proc int) {
223         switch n.Left.Op {
224         default:
225                 Fatalf("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0))
226
227         case OCALLMETH:
228                 cgen_callmeth(n.Left, proc)
229
230         case OCALLINTER:
231                 cgen_callinter(n.Left, nil, proc)
232
233         case OCALLFUNC:
234                 cgen_call(n.Left, proc)
235         }
236 }
237
238 // generate declaration.
239 // have to allocate heap copy
240 // for escaped variables.
241 func cgen_dcl(n *Node) {
242         if Debug['g'] != 0 {
243                 Dump("\ncgen-dcl", n)
244         }
245         if n.Op != ONAME {
246                 Dump("cgen_dcl", n)
247                 Fatalf("cgen_dcl")
248         }
249
250         if n.Class&PHEAP == 0 {
251                 return
252         }
253         if compiling_runtime != 0 {
254                 Yyerror("%v escapes to heap, not allowed in runtime.", n)
255         }
256         if prealloc[n] == nil {
257                 prealloc[n] = callnew(n.Type)
258         }
259         Cgen_as(n.Name.Heapaddr, prealloc[n])
260 }
261
262 // generate discard of value
263 func cgen_discard(nr *Node) {
264         if nr == nil {
265                 return
266         }
267
268         switch nr.Op {
269         case ONAME:
270                 if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF {
271                         gused(nr)
272                 }
273
274                 // unary
275         case OADD,
276                 OAND,
277                 ODIV,
278                 OEQ,
279                 OGE,
280                 OGT,
281                 OLE,
282                 OLSH,
283                 OLT,
284                 OMOD,
285                 OMUL,
286                 ONE,
287                 OOR,
288                 ORSH,
289                 OSUB,
290                 OXOR:
291                 cgen_discard(nr.Left)
292
293                 cgen_discard(nr.Right)
294
295                 // binary
296         case OCAP,
297                 OCOM,
298                 OLEN,
299                 OMINUS,
300                 ONOT,
301                 OPLUS:
302                 cgen_discard(nr.Left)
303
304         case OIND:
305                 Cgen_checknil(nr.Left)
306
307                 // special enough to just evaluate
308         default:
309                 var tmp Node
310                 Tempname(&tmp, nr.Type)
311
312                 Cgen_as(&tmp, nr)
313                 gused(&tmp)
314         }
315 }
316
317 // clearslim generates code to zero a slim node.
318 func Clearslim(n *Node) {
319         var z Node
320         z.Op = OLITERAL
321         z.Type = n.Type
322         z.Addable = true
323
324         switch Simtype[n.Type.Etype] {
325         case TCOMPLEX64, TCOMPLEX128:
326                 z.SetVal(Val{new(Mpcplx)})
327                 Mpmovecflt(&z.Val().U.(*Mpcplx).Real, 0.0)
328                 Mpmovecflt(&z.Val().U.(*Mpcplx).Imag, 0.0)
329
330         case TFLOAT32, TFLOAT64:
331                 var zero Mpflt
332                 Mpmovecflt(&zero, 0.0)
333                 z.SetVal(Val{&zero})
334
335         case TPTR32, TPTR64, TCHAN, TMAP:
336                 z.SetVal(Val{new(NilVal)})
337
338         case TBOOL:
339                 z.SetVal(Val{false})
340
341         case TINT8,
342                 TINT16,
343                 TINT32,
344                 TINT64,
345                 TUINT8,
346                 TUINT16,
347                 TUINT32,
348                 TUINT64:
349                 z.SetVal(Val{new(Mpint)})
350                 Mpmovecfix(z.Val().U.(*Mpint), 0)
351
352         default:
353                 Fatalf("clearslim called on type %v", n.Type)
354         }
355
356         ullmancalc(&z)
357         Cgen(&z, n)
358 }
359
360 // generate:
361 //      res = iface{typ, data}
362 // n->left is typ
363 // n->right is data
364 func Cgen_eface(n *Node, res *Node) {
365         // the right node of an eface may contain function calls that uses res as an argument,
366         // so it's important that it is done first
367
368         tmp := temp(Types[Tptr])
369         Cgen(n.Right, tmp)
370
371         Gvardef(res)
372
373         dst := *res
374         dst.Type = Types[Tptr]
375         dst.Xoffset += int64(Widthptr)
376         Cgen(tmp, &dst)
377
378         dst.Xoffset -= int64(Widthptr)
379         Cgen(n.Left, &dst)
380 }
381
382 // generate one of:
383 //      res, resok = x.(T)
384 //      res = x.(T) (when resok == nil)
385 // n.Left is x
386 // n.Type is T
387 func cgen_dottype(n *Node, res, resok *Node, wb bool) {
388         if Debug_typeassert > 0 {
389                 Warn("type assertion inlined")
390         }
391         //      iface := n.Left
392         //      r1 := iword(iface)
393         //      if n.Left is non-empty interface {
394         //              r1 = *r1
395         //      }
396         //      if r1 == T {
397         //              res = idata(iface)
398         //              resok = true
399         //      } else {
400         //              assert[EI]2T(x, T, nil) // (when resok == nil; does not return)
401         //              resok = false // (when resok != nil)
402         //      }
403         //
404         var iface Node
405         Igen(n.Left, &iface, res)
406         var r1, r2 Node
407         byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
408         Regalloc(&r1, byteptr, nil)
409         iface.Type = byteptr
410         Cgen(&iface, &r1)
411         if !isnilinter(n.Left.Type) {
412                 // Holding itab, want concrete type in second word.
413                 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
414                 r2 = r1
415                 r2.Op = OINDREG
416                 r2.Xoffset = int64(Widthptr)
417                 Cgen(&r2, &r1)
418                 Patch(p, Pc)
419         }
420         Regalloc(&r2, byteptr, nil)
421         Cgen(typename(n.Type), &r2)
422         p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
423         Regfree(&r2) // not needed for success path; reclaimed on one failure path
424         iface.Xoffset += int64(Widthptr)
425         Cgen(&iface, &r1)
426         Regfree(&iface)
427
428         if resok == nil {
429                 r1.Type = res.Type
430                 cgen_wb(&r1, res, wb)
431                 q := Gbranch(obj.AJMP, nil, 0)
432                 Patch(p, Pc)
433                 Regrealloc(&r2) // reclaim from above, for this failure path
434                 fn := syslook("panicdottype", 0)
435                 dowidth(fn.Type)
436                 call := Nod(OCALLFUNC, fn, nil)
437                 r1.Type = byteptr
438                 r2.Type = byteptr
439                 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type))
440                 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil)
441                 gen(call)
442                 Regfree(&r1)
443                 Regfree(&r2)
444                 Thearch.Gins(obj.AUNDEF, nil, nil)
445                 Patch(q, Pc)
446         } else {
447                 // This half is handling the res, resok = x.(T) case,
448                 // which is called from gen, not cgen, and is consequently fussier
449                 // about blank assignments. We have to avoid calling cgen for those.
450                 r1.Type = res.Type
451                 if !isblank(res) {
452                         cgen_wb(&r1, res, wb)
453                 }
454                 Regfree(&r1)
455                 if !isblank(resok) {
456                         Cgen(Nodbool(true), resok)
457                 }
458                 q := Gbranch(obj.AJMP, nil, 0)
459                 Patch(p, Pc)
460                 if !isblank(res) {
461                         n := nodnil()
462                         n.Type = res.Type
463                         Cgen(n, res)
464                 }
465                 if !isblank(resok) {
466                         Cgen(Nodbool(false), resok)
467                 }
468                 Patch(q, Pc)
469         }
470 }
471
472 // generate:
473 //      res, resok = x.(T)
474 // n.Left is x
475 // n.Type is T
476 func Cgen_As2dottype(n, res, resok *Node) {
477         if Debug_typeassert > 0 {
478                 Warn("type assertion inlined")
479         }
480         //      iface := n.Left
481         //      r1 := iword(iface)
482         //      if n.Left is non-empty interface {
483         //              r1 = *r1
484         //      }
485         //      if r1 == T {
486         //              res = idata(iface)
487         //              resok = true
488         //      } else {
489         //              res = nil
490         //              resok = false
491         //      }
492         //
493         var iface Node
494         Igen(n.Left, &iface, nil)
495         var r1, r2 Node
496         byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
497         Regalloc(&r1, byteptr, res)
498         iface.Type = byteptr
499         Cgen(&iface, &r1)
500         if !isnilinter(n.Left.Type) {
501                 // Holding itab, want concrete type in second word.
502                 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
503                 r2 = r1
504                 r2.Op = OINDREG
505                 r2.Xoffset = int64(Widthptr)
506                 Cgen(&r2, &r1)
507                 Patch(p, Pc)
508         }
509         Regalloc(&r2, byteptr, nil)
510         Cgen(typename(n.Type), &r2)
511         p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
512         iface.Type = n.Type
513         iface.Xoffset += int64(Widthptr)
514         Cgen(&iface, &r1)
515         if iface.Op != 0 {
516                 Regfree(&iface)
517         }
518         Cgen(&r1, res)
519         q := Gbranch(obj.AJMP, nil, 0)
520         Patch(p, Pc)
521
522         fn := syslook("panicdottype", 0)
523         dowidth(fn.Type)
524         call := Nod(OCALLFUNC, fn, nil)
525         call.List = list(list(list1(&r1), &r2), typename(n.Left.Type))
526         call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil)
527         gen(call)
528         Regfree(&r1)
529         Regfree(&r2)
530         Thearch.Gins(obj.AUNDEF, nil, nil)
531         Patch(q, Pc)
532 }
533
534 // gather series of offsets
535 // >=0 is direct addressed field
536 // <0 is pointer to next field (+1)
537 func Dotoffset(n *Node, oary []int64, nn **Node) int {
538         var i int
539
540         switch n.Op {
541         case ODOT:
542                 if n.Xoffset == BADWIDTH {
543                         Dump("bad width in dotoffset", n)
544                         Fatalf("bad width in dotoffset")
545                 }
546
547                 i = Dotoffset(n.Left, oary, nn)
548                 if i > 0 {
549                         if oary[i-1] >= 0 {
550                                 oary[i-1] += n.Xoffset
551                         } else {
552                                 oary[i-1] -= n.Xoffset
553                         }
554                         break
555                 }
556
557                 if i < 10 {
558                         oary[i] = n.Xoffset
559                         i++
560                 }
561
562         case ODOTPTR:
563                 if n.Xoffset == BADWIDTH {
564                         Dump("bad width in dotoffset", n)
565                         Fatalf("bad width in dotoffset")
566                 }
567
568                 i = Dotoffset(n.Left, oary, nn)
569                 if i < 10 {
570                         oary[i] = -(n.Xoffset + 1)
571                         i++
572                 }
573
574         default:
575                 *nn = n
576                 return 0
577         }
578
579         if i >= 10 {
580                 *nn = nil
581         }
582         return i
583 }
584
585 // make a new off the books
586 func Tempname(nn *Node, t *Type) {
587         if Curfn == nil {
588                 Fatalf("no curfn for tempname")
589         }
590
591         if t == nil {
592                 Yyerror("tempname called with nil type")
593                 t = Types[TINT32]
594         }
595
596         // give each tmp a different name so that there
597         // a chance to registerizer them
598         s := Lookupf("autotmp_%.4d", statuniqgen)
599         statuniqgen++
600         n := Nod(ONAME, nil, nil)
601         n.Sym = s
602         s.Def = n
603         n.Type = t
604         n.Class = PAUTO
605         n.Addable = true
606         n.Ullman = 1
607         n.Esc = EscNever
608         n.Name.Curfn = Curfn
609         Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
610
611         dowidth(t)
612         n.Xoffset = 0
613         *nn = *n
614 }
615
616 func temp(t *Type) *Node {
617         n := Nod(OXXX, nil, nil)
618         Tempname(n, t)
619         n.Sym.Def.Used = true
620         return n.Orig
621 }
622
623 func gen(n *Node) {
624         //dump("gen", n);
625
626         lno := setlineno(n)
627
628         wasregalloc := Anyregalloc()
629
630         if n == nil {
631                 goto ret
632         }
633
634         if n.Ninit != nil {
635                 Genlist(n.Ninit)
636         }
637
638         setlineno(n)
639
640         switch n.Op {
641         default:
642                 Fatalf("gen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
643
644         case OCASE,
645                 OFALL,
646                 OXCASE,
647                 OXFALL,
648                 ODCLCONST,
649                 ODCLFUNC,
650                 ODCLTYPE:
651                 break
652
653         case OEMPTY:
654                 break
655
656         case OBLOCK:
657                 Genlist(n.List)
658
659         case OLABEL:
660                 if isblanksym(n.Left.Sym) {
661                         break
662                 }
663
664                 lab := newlab(n)
665
666                 // if there are pending gotos, resolve them all to the current pc.
667                 var p2 *obj.Prog
668                 for p1 := lab.Gotopc; p1 != nil; p1 = p2 {
669                         p2 = unpatch(p1)
670                         Patch(p1, Pc)
671                 }
672
673                 lab.Gotopc = nil
674                 if lab.Labelpc == nil {
675                         lab.Labelpc = Pc
676                 }
677
678                 if n.Name.Defn != nil {
679                         switch n.Name.Defn.Op {
680                         // so stmtlabel can find the label
681                         case OFOR, OSWITCH, OSELECT:
682                                 n.Name.Defn.Sym = lab.Sym
683                         }
684                 }
685
686                 // if label is defined, emit jump to it.
687         // otherwise save list of pending gotos in lab->gotopc.
688         // the list is linked through the normal jump target field
689         // to avoid a second list.  (the jumps are actually still
690         // valid code, since they're just going to another goto
691         // to the same label.  we'll unwind it when we learn the pc
692         // of the label in the OLABEL case above.)
693         case OGOTO:
694                 lab := newlab(n)
695
696                 if lab.Labelpc != nil {
697                         gjmp(lab.Labelpc)
698                 } else {
699                         lab.Gotopc = gjmp(lab.Gotopc)
700                 }
701
702         case OBREAK:
703                 if n.Left != nil {
704                         lab := n.Left.Sym.Label
705                         if lab == nil {
706                                 Yyerror("break label not defined: %v", n.Left.Sym)
707                                 break
708                         }
709
710                         lab.Used = true
711                         if lab.Breakpc == nil {
712                                 Yyerror("invalid break label %v", n.Left.Sym)
713                                 break
714                         }
715
716                         gjmp(lab.Breakpc)
717                         break
718                 }
719
720                 if breakpc == nil {
721                         Yyerror("break is not in a loop")
722                         break
723                 }
724
725                 gjmp(breakpc)
726
727         case OCONTINUE:
728                 if n.Left != nil {
729                         lab := n.Left.Sym.Label
730                         if lab == nil {
731                                 Yyerror("continue label not defined: %v", n.Left.Sym)
732                                 break
733                         }
734
735                         lab.Used = true
736                         if lab.Continpc == nil {
737                                 Yyerror("invalid continue label %v", n.Left.Sym)
738                                 break
739                         }
740
741                         gjmp(lab.Continpc)
742                         break
743                 }
744
745                 if continpc == nil {
746                         Yyerror("continue is not in a loop")
747                         break
748                 }
749
750                 gjmp(continpc)
751
752         case OFOR:
753                 sbreak := breakpc
754                 p1 := gjmp(nil)     //          goto test
755                 breakpc = gjmp(nil) // break:   goto done
756                 scontin := continpc
757                 continpc = Pc
758
759                 // define break and continue labels
760                 lab := stmtlabel(n)
761                 if lab != nil {
762                         lab.Breakpc = breakpc
763                         lab.Continpc = continpc
764                 }
765
766                 gen(n.Right)                     // contin:     incr
767                 Patch(p1, Pc)                    // test:
768                 Bgen(n.Left, false, -1, breakpc) //             if(!test) goto break
769                 Genlist(n.Nbody)                 //             body
770                 gjmp(continpc)
771                 Patch(breakpc, Pc) // done:
772                 continpc = scontin
773                 breakpc = sbreak
774                 if lab != nil {
775                         lab.Breakpc = nil
776                         lab.Continpc = nil
777                 }
778
779         case OIF:
780                 p1 := gjmp(nil)                         //              goto test
781                 p2 := gjmp(nil)                         // p2:          goto else
782                 Patch(p1, Pc)                           // test:
783                 Bgen(n.Left, false, int(-n.Likely), p2) //              if(!test) goto p2
784                 Genlist(n.Nbody)                        //              then
785                 p3 := gjmp(nil)                         //              goto done
786                 Patch(p2, Pc)                           // else:
787                 Genlist(n.Rlist)                        //              else
788                 Patch(p3, Pc)                           // done:
789
790         case OSWITCH:
791                 sbreak := breakpc
792                 p1 := gjmp(nil)     //          goto test
793                 breakpc = gjmp(nil) // break:   goto done
794
795                 // define break label
796                 lab := stmtlabel(n)
797                 if lab != nil {
798                         lab.Breakpc = breakpc
799                 }
800
801                 Patch(p1, Pc)      // test:
802                 Genlist(n.Nbody)   //           switch(test) body
803                 Patch(breakpc, Pc) // done:
804                 breakpc = sbreak
805                 if lab != nil {
806                         lab.Breakpc = nil
807                 }
808
809         case OSELECT:
810                 sbreak := breakpc
811                 p1 := gjmp(nil)     //          goto test
812                 breakpc = gjmp(nil) // break:   goto done
813
814                 // define break label
815                 lab := stmtlabel(n)
816                 if lab != nil {
817                         lab.Breakpc = breakpc
818                 }
819
820                 Patch(p1, Pc)      // test:
821                 Genlist(n.Nbody)   //           select() body
822                 Patch(breakpc, Pc) // done:
823                 breakpc = sbreak
824                 if lab != nil {
825                         lab.Breakpc = nil
826                 }
827
828         case ODCL:
829                 cgen_dcl(n.Left)
830
831         case OAS:
832                 if gen_as_init(n, false) {
833                         break
834                 }
835                 Cgen_as(n.Left, n.Right)
836
837         case OASWB:
838                 Cgen_as_wb(n.Left, n.Right, true)
839
840         case OAS2DOTTYPE:
841                 cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
842
843         case OCALLMETH:
844                 cgen_callmeth(n, 0)
845
846         case OCALLINTER:
847                 cgen_callinter(n, nil, 0)
848
849         case OCALLFUNC:
850                 cgen_call(n, 0)
851
852         case OPROC:
853                 cgen_proc(n, 1)
854
855         case ODEFER:
856                 cgen_proc(n, 2)
857
858         case ORETURN, ORETJMP:
859                 cgen_ret(n)
860
861         // Function calls turned into compiler intrinsics.
862         // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
863         case OGETG:
864                 // nothing
865         case OSQRT:
866                 cgen_discard(n.Left)
867
868         case OCHECKNIL:
869                 Cgen_checknil(n.Left)
870
871         case OVARKILL:
872                 gvarkill(n.Left)
873
874         case OVARLIVE:
875                 gvarlive(n.Left)
876         }
877
878 ret:
879         if Anyregalloc() != wasregalloc {
880                 Dump("node", n)
881                 Fatalf("registers left allocated")
882         }
883
884         lineno = lno
885 }
886
887 func Cgen_as(nl, nr *Node) {
888         Cgen_as_wb(nl, nr, false)
889 }
890
891 func Cgen_as_wb(nl, nr *Node, wb bool) {
892         if Debug['g'] != 0 {
893                 op := "cgen_as"
894                 if wb {
895                         op = "cgen_as_wb"
896                 }
897                 Dump(op, nl)
898                 Dump(op+" = ", nr)
899         }
900
901         for nr != nil && nr.Op == OCONVNOP {
902                 nr = nr.Left
903         }
904
905         if nl == nil || isblank(nl) {
906                 cgen_discard(nr)
907                 return
908         }
909
910         if nr == nil || iszero(nr) {
911                 // heaps should already be clear
912                 if nr == nil && (nl.Class&PHEAP != 0) {
913                         return
914                 }
915
916                 tl := nl.Type
917                 if tl == nil {
918                         return
919                 }
920                 if Isfat(tl) {
921                         if nl.Op == ONAME {
922                                 Gvardef(nl)
923                         }
924                         Thearch.Clearfat(nl)
925                         return
926                 }
927
928                 Clearslim(nl)
929                 return
930         }
931
932         tl := nl.Type
933         if tl == nil {
934                 return
935         }
936
937         cgen_wb(nr, nl, wb)
938 }
939
940 func cgen_callmeth(n *Node, proc int) {
941         // generate a rewrite in n2 for the method call
942         // (p.f)(...) goes to (f)(p,...)
943
944         l := n.Left
945
946         if l.Op != ODOTMETH {
947                 Fatalf("cgen_callmeth: not dotmethod: %v", l)
948         }
949
950         n2 := *n
951         n2.Op = OCALLFUNC
952         n2.Left = l.Right
953         n2.Left.Type = l.Type
954
955         if n2.Left.Op == ONAME {
956                 n2.Left.Class = PFUNC
957         }
958         cgen_call(&n2, proc)
959 }
960
961 // CgenTemp creates a temporary node, assigns n to it, and returns it.
962 func CgenTemp(n *Node) *Node {
963         var tmp Node
964         Tempname(&tmp, n.Type)
965         Cgen(n, &tmp)
966         return &tmp
967 }
968
969 func checklabels() {
970         for lab := labellist; lab != nil; lab = lab.Link {
971                 if lab.Def == nil {
972                         for _, n := range lab.Use {
973                                 yyerrorl(int(n.Lineno), "label %v not defined", lab.Sym)
974                         }
975                         continue
976                 }
977
978                 if lab.Use == nil && !lab.Used {
979                         yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
980                         continue
981                 }
982
983                 if lab.Gotopc != nil {
984                         Fatalf("label %v never resolved", lab.Sym)
985                 }
986                 for _, n := range lab.Use {
987                         checkgoto(n, lab.Def)
988                 }
989         }
990 }
991
992 // Componentgen copies a composite value by moving its individual components.
993 // Slices, strings and interfaces are supported. Small structs or arrays with
994 // elements of basic type are also supported.
995 // nr is nil when assigning a zero value.
996 func Componentgen(nr, nl *Node) bool {
997         return componentgen_wb(nr, nl, false)
998 }
999
1000 // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
1001 func componentgen_wb(nr, nl *Node, wb bool) bool {
1002         // Don't generate any code for complete copy of a variable into itself.
1003         // It's useless, and the VARDEF will incorrectly mark the old value as dead.
1004         // (This check assumes that the arguments passed to componentgen did not
1005         // themselves come from Igen, or else we could have Op==ONAME but
1006         // with a Type and Xoffset describing an individual field, not the entire
1007         // variable.)
1008         if nl.Op == ONAME && nl == nr {
1009                 return true
1010         }
1011
1012         // Count number of moves required to move components.
1013         // If using write barrier, can only emit one pointer.
1014         // TODO(rsc): Allow more pointers, for reflect.Value.
1015         const maxMoves = 8
1016         n := 0
1017         numPtr := 0
1018         visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
1019                 n++
1020                 if Simtype[t.Etype] == Tptr && t != itable {
1021                         numPtr++
1022                 }
1023                 return n <= maxMoves && (!wb || numPtr <= 1)
1024         })
1025         if n > maxMoves || wb && numPtr > 1 {
1026                 return false
1027         }
1028
1029         // Must call emitVardef after evaluating rhs but before writing to lhs.
1030         emitVardef := func() {
1031                 // Emit vardef if needed.
1032                 if nl.Op == ONAME {
1033                         switch nl.Type.Etype {
1034                         case TARRAY, TSTRING, TINTER, TSTRUCT:
1035                                 Gvardef(nl)
1036                         }
1037                 }
1038         }
1039
1040         isConstString := Isconst(nr, CTSTR)
1041
1042         if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
1043                 return false
1044         }
1045
1046         var nodl Node
1047         if cadable(nl) {
1048                 nodl = *nl
1049         } else {
1050                 if nr != nil && !cadable(nr) && !isConstString {
1051                         return false
1052                 }
1053                 if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
1054                         Igen(nl, &nodl, nil)
1055                         defer Regfree(&nodl)
1056                 }
1057         }
1058         lbase := nodl.Xoffset
1059
1060         // Special case: zeroing.
1061         var nodr Node
1062         if nr == nil {
1063                 // When zeroing, prepare a register containing zero.
1064                 // TODO(rsc): Check that this is actually generating the best code.
1065                 if Thearch.REGZERO != 0 {
1066                         // cpu has a dedicated zero register
1067                         Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
1068                 } else {
1069                         // no dedicated zero register
1070                         var zero Node
1071                         Nodconst(&zero, nl.Type, 0)
1072                         Regalloc(&nodr, Types[TUINT], nil)
1073                         Thearch.Gmove(&zero, &nodr)
1074                         defer Regfree(&nodr)
1075                 }
1076
1077                 emitVardef()
1078                 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
1079                         nodl.Type = t
1080                         nodl.Xoffset = lbase + offset
1081                         nodr.Type = t
1082                         if Isfloat[t.Etype] {
1083                                 // TODO(rsc): Cache zero register like we do for integers?
1084                                 Clearslim(&nodl)
1085                         } else {
1086                                 Thearch.Gmove(&nodr, &nodl)
1087                         }
1088                         return true
1089                 })
1090                 return true
1091         }
1092
1093         // Special case: assignment of string constant.
1094         if isConstString {
1095                 emitVardef()
1096
1097                 // base
1098                 nodl.Type = Ptrto(Types[TUINT8])
1099                 Regalloc(&nodr, Types[Tptr], nil)
1100                 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
1101                 Datastring(nr.Val().U.(string), &p.From)
1102                 p.From.Type = obj.TYPE_ADDR
1103                 Thearch.Gmove(&nodr, &nodl)
1104                 Regfree(&nodr)
1105
1106                 // length
1107                 nodl.Type = Types[Simtype[TUINT]]
1108                 nodl.Xoffset += int64(Array_nel) - int64(Array_array)
1109                 Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string))))
1110                 Thearch.Gmove(&nodr, &nodl)
1111                 return true
1112         }
1113
1114         // General case: copy nl = nr.
1115         nodr = *nr
1116         if !cadable(nr) {
1117                 if nr.Ullman >= UINF && nodl.Op == OINDREG {
1118                         Fatalf("miscompile")
1119                 }
1120                 Igen(nr, &nodr, nil)
1121                 defer Regfree(&nodr)
1122         }
1123         rbase := nodr.Xoffset
1124
1125         if nodl.Op == 0 {
1126                 Igen(nl, &nodl, nil)
1127                 defer Regfree(&nodl)
1128                 lbase = nodl.Xoffset
1129         }
1130
1131         emitVardef()
1132         var (
1133                 ptrType   *Type
1134                 ptrOffset int64
1135         )
1136         visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
1137                 if wb && Simtype[t.Etype] == Tptr && t != itable {
1138                         if ptrType != nil {
1139                                 Fatalf("componentgen_wb %v", Tconv(nl.Type, 0))
1140                         }
1141                         ptrType = t
1142                         ptrOffset = offset
1143                         return true
1144                 }
1145                 nodl.Type = t
1146                 nodl.Xoffset = lbase + offset
1147                 nodr.Type = t
1148                 nodr.Xoffset = rbase + offset
1149                 Thearch.Gmove(&nodr, &nodl)
1150                 return true
1151         })
1152         if ptrType != nil {
1153                 nodl.Type = ptrType
1154                 nodl.Xoffset = lbase + ptrOffset
1155                 nodr.Type = ptrType
1156                 nodr.Xoffset = rbase + ptrOffset
1157                 cgen_wbptr(&nodr, &nodl)
1158         }
1159         return true
1160 }
1161
1162 // visitComponents walks the individual components of the type t,
1163 // walking into array elements, struct fields, the real and imaginary
1164 // parts of complex numbers, and on 32-bit systems the high and
1165 // low halves of 64-bit integers.
1166 // It calls f for each such component, passing the component (aka element)
1167 // type and memory offset, assuming t starts at startOffset.
1168 // If f ever returns false, visitComponents returns false without any more
1169 // calls to f. Otherwise visitComponents returns true.
1170 func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
1171         switch t.Etype {
1172         case TINT64:
1173                 if Widthreg == 8 {
1174                         break
1175                 }
1176                 // NOTE: Assuming little endian (signed top half at offset 4).
1177                 // We don't have any 32-bit big-endian systems.
1178                 if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
1179                         Fatalf("unknown 32-bit architecture")
1180                 }
1181                 return f(Types[TUINT32], startOffset) &&
1182                         f(Types[TINT32], startOffset+4)
1183
1184         case TUINT64:
1185                 if Widthreg == 8 {
1186                         break
1187                 }
1188                 return f(Types[TUINT32], startOffset) &&
1189                         f(Types[TUINT32], startOffset+4)
1190
1191         case TCOMPLEX64:
1192                 return f(Types[TFLOAT32], startOffset) &&
1193                         f(Types[TFLOAT32], startOffset+4)
1194
1195         case TCOMPLEX128:
1196                 return f(Types[TFLOAT64], startOffset) &&
1197                         f(Types[TFLOAT64], startOffset+8)
1198
1199         case TINTER:
1200                 return f(itable, startOffset) &&
1201                         f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
1202
1203         case TSTRING:
1204                 return f(Ptrto(Types[TUINT8]), startOffset) &&
1205                         f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
1206
1207         case TARRAY:
1208                 if Isslice(t) {
1209                         return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
1210                                 f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
1211                                 f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
1212                 }
1213
1214                 // Short-circuit [1e6]struct{}.
1215                 if t.Type.Width == 0 {
1216                         return true
1217                 }
1218
1219                 for i := int64(0); i < t.Bound; i++ {
1220                         if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
1221                                 return false
1222                         }
1223                 }
1224                 return true
1225
1226         case TSTRUCT:
1227                 if t.Type != nil && t.Type.Width != 0 {
1228                         // NOTE(rsc): If this happens, the right thing to do is to say
1229                         //      startOffset -= t.Type.Width
1230                         // but I want to see if it does.
1231                         // The old version of componentgen handled this,
1232                         // in code introduced in CL 6932045 to fix issue #4518.
1233                         // But the test case in issue 4518 does not trigger this anymore,
1234                         // so maybe this complication is no longer needed.
1235                         Fatalf("struct not at offset 0")
1236                 }
1237
1238                 for field := t.Type; field != nil; field = field.Down {
1239                         if field.Etype != TFIELD {
1240                                 Fatalf("bad struct")
1241                         }
1242                         if !visitComponents(field.Type, startOffset+field.Width, f) {
1243                                 return false
1244                         }
1245                 }
1246                 return true
1247         }
1248         return f(t, startOffset)
1249 }
1250
1251 func cadable(n *Node) bool {
1252         // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
1253         return n.Addable && n.Op == ONAME
1254 }