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