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