github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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  /*
    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  				Fatalf("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 = append(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  		Fatalf("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  		Fatalf("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  		Fatalf("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  			Fatalf("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  			Fatalf("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  		Fatalf("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  		Fatalf("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 = true
   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 = true
   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  		Fatalf("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  		Fatalf("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  	for lab := labellist; lab != nil; lab = lab.Link {
   990  		if lab.Def == nil {
   991  			for _, n := range lab.Use {
   992  				yyerrorl(int(n.Lineno), "label %v not defined", lab.Sym)
   993  			}
   994  			continue
   995  		}
   996  
   997  		if lab.Use == nil && !lab.Used {
   998  			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
   999  			continue
  1000  		}
  1001  
  1002  		if lab.Gotopc != nil {
  1003  			Fatalf("label %v never resolved", lab.Sym)
  1004  		}
  1005  		for _, n := range lab.Use {
  1006  			checkgoto(n, lab.Def)
  1007  		}
  1008  	}
  1009  }
  1010  
  1011  // Componentgen copies a composite value by moving its individual components.
  1012  // Slices, strings and interfaces are supported. Small structs or arrays with
  1013  // elements of basic type are also supported.
  1014  // nr is nil when assigning a zero value.
  1015  func Componentgen(nr, nl *Node) bool {
  1016  	return componentgen_wb(nr, nl, false)
  1017  }
  1018  
  1019  // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
  1020  func componentgen_wb(nr, nl *Node, wb bool) bool {
  1021  	// Don't generate any code for complete copy of a variable into itself.
  1022  	// It's useless, and the VARDEF will incorrectly mark the old value as dead.
  1023  	// (This check assumes that the arguments passed to componentgen did not
  1024  	// themselves come from Igen, or else we could have Op==ONAME but
  1025  	// with a Type and Xoffset describing an individual field, not the entire
  1026  	// variable.)
  1027  	if nl.Op == ONAME && nl == nr {
  1028  		return true
  1029  	}
  1030  
  1031  	// Count number of moves required to move components.
  1032  	// If using write barrier, can only emit one pointer.
  1033  	// TODO(rsc): Allow more pointers, for reflect.Value.
  1034  	const maxMoves = 8
  1035  	n := 0
  1036  	numPtr := 0
  1037  	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1038  		n++
  1039  		if int(Simtype[t.Etype]) == Tptr && t != itable {
  1040  			numPtr++
  1041  		}
  1042  		return n <= maxMoves && (!wb || numPtr <= 1)
  1043  	})
  1044  	if n > maxMoves || wb && numPtr > 1 {
  1045  		return false
  1046  	}
  1047  
  1048  	// Must call emitVardef after evaluating rhs but before writing to lhs.
  1049  	emitVardef := func() {
  1050  		// Emit vardef if needed.
  1051  		if nl.Op == ONAME {
  1052  			switch nl.Type.Etype {
  1053  			case TARRAY, TSTRING, TINTER, TSTRUCT:
  1054  				Gvardef(nl)
  1055  			}
  1056  		}
  1057  	}
  1058  
  1059  	isConstString := Isconst(nr, CTSTR)
  1060  
  1061  	if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
  1062  		return false
  1063  	}
  1064  
  1065  	var nodl Node
  1066  	if cadable(nl) {
  1067  		nodl = *nl
  1068  	} else {
  1069  		if nr != nil && !cadable(nr) && !isConstString {
  1070  			return false
  1071  		}
  1072  		if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
  1073  			Igen(nl, &nodl, nil)
  1074  			defer Regfree(&nodl)
  1075  		}
  1076  	}
  1077  	lbase := nodl.Xoffset
  1078  
  1079  	// Special case: zeroing.
  1080  	var nodr Node
  1081  	if nr == nil {
  1082  		// When zeroing, prepare a register containing zero.
  1083  		// TODO(rsc): Check that this is actually generating the best code.
  1084  		if Thearch.REGZERO != 0 {
  1085  			// cpu has a dedicated zero register
  1086  			Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
  1087  		} else {
  1088  			// no dedicated zero register
  1089  			var zero Node
  1090  			Nodconst(&zero, nl.Type, 0)
  1091  			Regalloc(&nodr, Types[TUINT], nil)
  1092  			Thearch.Gmove(&zero, &nodr)
  1093  			defer Regfree(&nodr)
  1094  		}
  1095  
  1096  		emitVardef()
  1097  		visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1098  			nodl.Type = t
  1099  			nodl.Xoffset = lbase + offset
  1100  			nodr.Type = t
  1101  			if Isfloat[t.Etype] {
  1102  				// TODO(rsc): Cache zero register like we do for integers?
  1103  				Clearslim(&nodl)
  1104  			} else {
  1105  				Thearch.Gmove(&nodr, &nodl)
  1106  			}
  1107  			return true
  1108  		})
  1109  		return true
  1110  	}
  1111  
  1112  	// Special case: assignment of string constant.
  1113  	if isConstString {
  1114  		emitVardef()
  1115  
  1116  		// base
  1117  		nodl.Type = Ptrto(Types[TUINT8])
  1118  		Regalloc(&nodr, Types[Tptr], nil)
  1119  		p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
  1120  		Datastring(nr.Val().U.(string), &p.From)
  1121  		p.From.Type = obj.TYPE_ADDR
  1122  		Thearch.Gmove(&nodr, &nodl)
  1123  		Regfree(&nodr)
  1124  
  1125  		// length
  1126  		nodl.Type = Types[Simtype[TUINT]]
  1127  		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
  1128  		Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string))))
  1129  		Thearch.Gmove(&nodr, &nodl)
  1130  		return true
  1131  	}
  1132  
  1133  	// General case: copy nl = nr.
  1134  	nodr = *nr
  1135  	if !cadable(nr) {
  1136  		if nr.Ullman >= UINF && nodl.Op == OINDREG {
  1137  			Fatalf("miscompile")
  1138  		}
  1139  		Igen(nr, &nodr, nil)
  1140  		defer Regfree(&nodr)
  1141  	}
  1142  	rbase := nodr.Xoffset
  1143  
  1144  	if nodl.Op == 0 {
  1145  		Igen(nl, &nodl, nil)
  1146  		defer Regfree(&nodl)
  1147  		lbase = nodl.Xoffset
  1148  	}
  1149  
  1150  	emitVardef()
  1151  	var (
  1152  		ptrType   *Type
  1153  		ptrOffset int64
  1154  	)
  1155  	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1156  		if wb && int(Simtype[t.Etype]) == Tptr && t != itable {
  1157  			if ptrType != nil {
  1158  				Fatalf("componentgen_wb %v", Tconv(nl.Type, 0))
  1159  			}
  1160  			ptrType = t
  1161  			ptrOffset = offset
  1162  			return true
  1163  		}
  1164  		nodl.Type = t
  1165  		nodl.Xoffset = lbase + offset
  1166  		nodr.Type = t
  1167  		nodr.Xoffset = rbase + offset
  1168  		Thearch.Gmove(&nodr, &nodl)
  1169  		return true
  1170  	})
  1171  	if ptrType != nil {
  1172  		nodl.Type = ptrType
  1173  		nodl.Xoffset = lbase + ptrOffset
  1174  		nodr.Type = ptrType
  1175  		nodr.Xoffset = rbase + ptrOffset
  1176  		cgen_wbptr(&nodr, &nodl)
  1177  	}
  1178  	return true
  1179  }
  1180  
  1181  // visitComponents walks the individual components of the type t,
  1182  // walking into array elements, struct fields, the real and imaginary
  1183  // parts of complex numbers, and on 32-bit systems the high and
  1184  // low halves of 64-bit integers.
  1185  // It calls f for each such component, passing the component (aka element)
  1186  // type and memory offset, assuming t starts at startOffset.
  1187  // If f ever returns false, visitComponents returns false without any more
  1188  // calls to f. Otherwise visitComponents returns true.
  1189  func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
  1190  	switch t.Etype {
  1191  	case TINT64:
  1192  		if Widthreg == 8 {
  1193  			break
  1194  		}
  1195  		// NOTE: Assuming little endian (signed top half at offset 4).
  1196  		// We don't have any 32-bit big-endian systems.
  1197  		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
  1198  			Fatalf("unknown 32-bit architecture")
  1199  		}
  1200  		return f(Types[TUINT32], startOffset) &&
  1201  			f(Types[TINT32], startOffset+4)
  1202  
  1203  	case TUINT64:
  1204  		if Widthreg == 8 {
  1205  			break
  1206  		}
  1207  		return f(Types[TUINT32], startOffset) &&
  1208  			f(Types[TUINT32], startOffset+4)
  1209  
  1210  	case TCOMPLEX64:
  1211  		return f(Types[TFLOAT32], startOffset) &&
  1212  			f(Types[TFLOAT32], startOffset+4)
  1213  
  1214  	case TCOMPLEX128:
  1215  		return f(Types[TFLOAT64], startOffset) &&
  1216  			f(Types[TFLOAT64], startOffset+8)
  1217  
  1218  	case TINTER:
  1219  		return f(itable, startOffset) &&
  1220  			f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
  1221  
  1222  	case TSTRING:
  1223  		return f(Ptrto(Types[TUINT8]), startOffset) &&
  1224  			f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
  1225  
  1226  	case TARRAY:
  1227  		if Isslice(t) {
  1228  			return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
  1229  				f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
  1230  				f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
  1231  		}
  1232  
  1233  		// Short-circuit [1e6]struct{}.
  1234  		if t.Type.Width == 0 {
  1235  			return true
  1236  		}
  1237  
  1238  		for i := int64(0); i < t.Bound; i++ {
  1239  			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
  1240  				return false
  1241  			}
  1242  		}
  1243  		return true
  1244  
  1245  	case TSTRUCT:
  1246  		if t.Type != nil && t.Type.Width != 0 {
  1247  			// NOTE(rsc): If this happens, the right thing to do is to say
  1248  			//	startOffset -= t.Type.Width
  1249  			// but I want to see if it does.
  1250  			// The old version of componentgen handled this,
  1251  			// in code introduced in CL 6932045 to fix issue #4518.
  1252  			// But the test case in issue 4518 does not trigger this anymore,
  1253  			// so maybe this complication is no longer needed.
  1254  			Fatalf("struct not at offset 0")
  1255  		}
  1256  
  1257  		for field := t.Type; field != nil; field = field.Down {
  1258  			if field.Etype != TFIELD {
  1259  				Fatalf("bad struct")
  1260  			}
  1261  			if !visitComponents(field.Type, startOffset+field.Width, f) {
  1262  				return false
  1263  			}
  1264  		}
  1265  		return true
  1266  	}
  1267  	return f(t, startOffset)
  1268  }
  1269  
  1270  func cadable(n *Node) bool {
  1271  	// Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
  1272  	return n.Addable && n.Op == ONAME
  1273  }