github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/gen.go (about)

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