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