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