github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/gen.go (about)

     1  // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/gen.go
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package gc
     8  
     9  import (
    10  	"rsc.io/tmp/bootstrap/internal/obj"
    11  	"fmt"
    12  )
    13  
    14  /*
    15   * portable half of code generator.
    16   * mainly statements and control flow.
    17   */
    18  var labellist *Label
    19  
    20  var lastlabel *Label
    21  
    22  func Sysfunc(name string) *Node {
    23  	n := newname(Pkglookup(name, Runtimepkg))
    24  	n.Class = PFUNC
    25  	return n
    26  }
    27  
    28  /*
    29   * the address of n has been taken and might be used after
    30   * the current function returns.  mark any local vars
    31   * as needing to move to the heap.
    32   */
    33  func addrescapes(n *Node) {
    34  	switch n.Op {
    35  	// probably a type error already.
    36  	// dump("addrescapes", n);
    37  	default:
    38  		break
    39  
    40  	case ONAME:
    41  		if n == nodfp {
    42  			break
    43  		}
    44  
    45  		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
    46  		// on PPARAM it means something different.
    47  		if n.Class == PAUTO && n.Esc == EscNever {
    48  			break
    49  		}
    50  
    51  		switch n.Class {
    52  		case PPARAMREF:
    53  			addrescapes(n.Defn)
    54  
    55  			// if func param, need separate temporary
    56  		// to hold heap pointer.
    57  		// the function type has already been checked
    58  		// (we're in the function body)
    59  		// so the param already has a valid xoffset.
    60  
    61  		// expression to refer to stack copy
    62  		case PPARAM, PPARAMOUT:
    63  			n.Stackparam = Nod(OPARAM, n, nil)
    64  
    65  			n.Stackparam.Type = n.Type
    66  			n.Stackparam.Addable = true
    67  			if n.Xoffset == BADWIDTH {
    68  				Fatal("addrescapes before param assignment")
    69  			}
    70  			n.Stackparam.Xoffset = n.Xoffset
    71  			fallthrough
    72  
    73  		case PAUTO:
    74  			n.Class |= PHEAP
    75  
    76  			n.Addable = false
    77  			n.Ullman = 2
    78  			n.Xoffset = 0
    79  
    80  			// create stack variable to hold pointer to heap
    81  			oldfn := Curfn
    82  
    83  			Curfn = n.Curfn
    84  			n.Heapaddr = temp(Ptrto(n.Type))
    85  			buf := fmt.Sprintf("&%v", n.Sym)
    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(), n)
    91  			}
    92  			Curfn = oldfn
    93  		}
    94  
    95  	case OIND, ODOTPTR:
    96  		break
    97  
    98  		// ODOTPTR has already been introduced,
    99  	// so these are the non-pointer ODOT and OINDEX.
   100  	// In &x[0], if x is a slice, then x does not
   101  	// escape--the pointer inside x does, but that
   102  	// is always a heap pointer anyway.
   103  	case ODOT, OINDEX:
   104  		if !Isslice(n.Left.Type) {
   105  			addrescapes(n.Left)
   106  		}
   107  	}
   108  }
   109  
   110  func clearlabels() {
   111  	for l := labellist; l != nil; l = l.Link {
   112  		l.Sym.Label = nil
   113  	}
   114  
   115  	labellist = nil
   116  	lastlabel = nil
   117  }
   118  
   119  func newlab(n *Node) *Label {
   120  	s := n.Left.Sym
   121  	lab := s.Label
   122  	if lab == nil {
   123  		lab = new(Label)
   124  		if lastlabel == nil {
   125  			labellist = lab
   126  		} else {
   127  			lastlabel.Link = lab
   128  		}
   129  		lastlabel = lab
   130  		lab.Sym = s
   131  		s.Label = lab
   132  	}
   133  
   134  	if n.Op == OLABEL {
   135  		if lab.Def != nil {
   136  			Yyerror("label %v already defined at %v", s, lab.Def.Line())
   137  		} else {
   138  			lab.Def = n
   139  		}
   140  	} else {
   141  		lab.Use = list(lab.Use, n)
   142  	}
   143  
   144  	return lab
   145  }
   146  
   147  func checkgoto(from *Node, to *Node) {
   148  	if from.Sym == to.Sym {
   149  		return
   150  	}
   151  
   152  	nf := 0
   153  	for fs := from.Sym; fs != nil; fs = fs.Link {
   154  		nf++
   155  	}
   156  	nt := 0
   157  	for fs := to.Sym; fs != nil; fs = fs.Link {
   158  		nt++
   159  	}
   160  	fs := from.Sym
   161  	for ; nf > nt; nf-- {
   162  		fs = fs.Link
   163  	}
   164  	if fs != to.Sym {
   165  		lno := int(lineno)
   166  		setlineno(from)
   167  
   168  		// decide what to complain about.
   169  		// prefer to complain about 'into block' over declarations,
   170  		// so scan backward to find most recent block or else dcl.
   171  		var block *Sym
   172  
   173  		var dcl *Sym
   174  		ts := to.Sym
   175  		for ; nt > nf; nt-- {
   176  			if ts.Pkg == nil {
   177  				block = ts
   178  			} else {
   179  				dcl = ts
   180  			}
   181  			ts = ts.Link
   182  		}
   183  
   184  		for ts != fs {
   185  			if ts.Pkg == nil {
   186  				block = ts
   187  			} else {
   188  				dcl = ts
   189  			}
   190  			ts = ts.Link
   191  			fs = fs.Link
   192  		}
   193  
   194  		if block != nil {
   195  			Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
   196  		} else {
   197  			Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
   198  		}
   199  		lineno = int32(lno)
   200  	}
   201  }
   202  
   203  func stmtlabel(n *Node) *Label {
   204  	if n.Sym != nil {
   205  		lab := n.Sym.Label
   206  		if lab != nil {
   207  			if lab.Def != nil {
   208  				if lab.Def.Defn == n {
   209  					return lab
   210  				}
   211  			}
   212  		}
   213  	}
   214  	return nil
   215  }
   216  
   217  /*
   218   * compile statements
   219   */
   220  func Genlist(l *NodeList) {
   221  	for ; l != nil; l = l.Next {
   222  		gen(l.N)
   223  	}
   224  }
   225  
   226  /*
   227   * generate code to start new proc running call n.
   228   */
   229  func cgen_proc(n *Node, proc int) {
   230  	switch n.Left.Op {
   231  	default:
   232  		Fatal("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0))
   233  
   234  	case OCALLMETH:
   235  		cgen_callmeth(n.Left, proc)
   236  
   237  	case OCALLINTER:
   238  		cgen_callinter(n.Left, nil, proc)
   239  
   240  	case OCALLFUNC:
   241  		cgen_call(n.Left, proc)
   242  	}
   243  }
   244  
   245  /*
   246   * generate declaration.
   247   * have to allocate heap copy
   248   * for escaped variables.
   249   */
   250  func cgen_dcl(n *Node) {
   251  	if Debug['g'] != 0 {
   252  		Dump("\ncgen-dcl", n)
   253  	}
   254  	if n.Op != ONAME {
   255  		Dump("cgen_dcl", n)
   256  		Fatal("cgen_dcl")
   257  	}
   258  
   259  	if n.Class&PHEAP == 0 {
   260  		return
   261  	}
   262  	if compiling_runtime != 0 {
   263  		Yyerror("%v escapes to heap, not allowed in runtime.", n)
   264  	}
   265  	if 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", n.Type)
   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, wb bool) {
   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  	Regfree(&r2) // not needed for success path; reclaimed on one failure path
   447  	iface.Xoffset += int64(Widthptr)
   448  	Cgen(&iface, &r1)
   449  	Regfree(&iface)
   450  
   451  	if resok == nil {
   452  		r1.Type = res.Type
   453  		cgen_wb(&r1, res, wb)
   454  		q := Gbranch(obj.AJMP, nil, 0)
   455  		Patch(p, Pc)
   456  		Regrealloc(&r2) // reclaim from above, for this failure path
   457  		fn := syslook("panicdottype", 0)
   458  		dowidth(fn.Type)
   459  		call := Nod(OCALLFUNC, fn, nil)
   460  		r1.Type = byteptr
   461  		r2.Type = byteptr
   462  		call.List = list(list(list1(&r1), &r2), typename(n.Left.Type))
   463  		call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil)
   464  		gen(call)
   465  		Regfree(&r1)
   466  		Regfree(&r2)
   467  		Thearch.Gins(obj.AUNDEF, nil, nil)
   468  		Patch(q, Pc)
   469  	} else {
   470  		// This half is handling the res, resok = x.(T) case,
   471  		// which is called from gen, not cgen, and is consequently fussier
   472  		// about blank assignments. We have to avoid calling cgen for those.
   473  		r1.Type = res.Type
   474  		if !isblank(res) {
   475  			cgen_wb(&r1, res, wb)
   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", n.Left.Sym)
   854  				break
   855  			}
   856  
   857  			lab.Used = 1
   858  			if lab.Breakpc == nil {
   859  				Yyerror("invalid break label %v", n.Left.Sym)
   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", n.Left.Sym)
   879  				break
   880  			}
   881  
   882  			lab.Used = 1
   883  			if lab.Continpc == nil {
   884  				Yyerror("invalid continue label %v", n.Left.Sym)
   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 OASWB:
   985  		Cgen_as_wb(n.Left, n.Right, true)
   986  
   987  	case OAS2DOTTYPE:
   988  		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
   989  
   990  	case OCALLMETH:
   991  		cgen_callmeth(n, 0)
   992  
   993  	case OCALLINTER:
   994  		cgen_callinter(n, nil, 0)
   995  
   996  	case OCALLFUNC:
   997  		cgen_call(n, 0)
   998  
   999  	case OPROC:
  1000  		cgen_proc(n, 1)
  1001  
  1002  	case ODEFER:
  1003  		cgen_proc(n, 2)
  1004  
  1005  	case ORETURN, ORETJMP:
  1006  		cgen_ret(n)
  1007  
  1008  	// Function calls turned into compiler intrinsics.
  1009  	// At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
  1010  	case OGETG:
  1011  		// nothing
  1012  	case OSQRT:
  1013  		cgen_discard(n.Left)
  1014  
  1015  	case OCHECKNIL:
  1016  		Cgen_checknil(n.Left)
  1017  
  1018  	case OVARKILL:
  1019  		gvarkill(n.Left)
  1020  	}
  1021  
  1022  ret:
  1023  	if Anyregalloc() != wasregalloc {
  1024  		Dump("node", n)
  1025  		Fatal("registers left allocated")
  1026  	}
  1027  
  1028  	lineno = lno
  1029  }
  1030  
  1031  func Cgen_as(nl, nr *Node) {
  1032  	Cgen_as_wb(nl, nr, false)
  1033  }
  1034  
  1035  func Cgen_as_wb(nl, nr *Node, wb bool) {
  1036  	if Debug['g'] != 0 {
  1037  		op := "cgen_as"
  1038  		if wb {
  1039  			op = "cgen_as_wb"
  1040  		}
  1041  		Dump(op, nl)
  1042  		Dump(op+" = ", nr)
  1043  	}
  1044  
  1045  	for nr != nil && nr.Op == OCONVNOP {
  1046  		nr = nr.Left
  1047  	}
  1048  
  1049  	if nl == nil || isblank(nl) {
  1050  		cgen_discard(nr)
  1051  		return
  1052  	}
  1053  
  1054  	if nr == nil || iszero(nr) {
  1055  		// heaps should already be clear
  1056  		if nr == nil && (nl.Class&PHEAP != 0) {
  1057  			return
  1058  		}
  1059  
  1060  		tl := nl.Type
  1061  		if tl == nil {
  1062  			return
  1063  		}
  1064  		if Isfat(tl) {
  1065  			if nl.Op == ONAME {
  1066  				Gvardef(nl)
  1067  			}
  1068  			Thearch.Clearfat(nl)
  1069  			return
  1070  		}
  1071  
  1072  		Clearslim(nl)
  1073  		return
  1074  	}
  1075  
  1076  	tl := nl.Type
  1077  	if tl == nil {
  1078  		return
  1079  	}
  1080  
  1081  	cgen_wb(nr, nl, wb)
  1082  }
  1083  
  1084  func cgen_callmeth(n *Node, proc int) {
  1085  	// generate a rewrite in n2 for the method call
  1086  	// (p.f)(...) goes to (f)(p,...)
  1087  
  1088  	l := n.Left
  1089  
  1090  	if l.Op != ODOTMETH {
  1091  		Fatal("cgen_callmeth: not dotmethod: %v")
  1092  	}
  1093  
  1094  	n2 := *n
  1095  	n2.Op = OCALLFUNC
  1096  	n2.Left = l.Right
  1097  	n2.Left.Type = l.Type
  1098  
  1099  	if n2.Left.Op == ONAME {
  1100  		n2.Left.Class = PFUNC
  1101  	}
  1102  	cgen_call(&n2, proc)
  1103  }
  1104  
  1105  // CgenTemp creates a temporary node, assigns n to it, and returns it.
  1106  func CgenTemp(n *Node) *Node {
  1107  	var tmp Node
  1108  	Tempname(&tmp, n.Type)
  1109  	Cgen(n, &tmp)
  1110  	return &tmp
  1111  }
  1112  
  1113  func checklabels() {
  1114  	var l *NodeList
  1115  
  1116  	for lab := labellist; lab != nil; lab = lab.Link {
  1117  		if lab.Def == nil {
  1118  			for l = lab.Use; l != nil; l = l.Next {
  1119  				yyerrorl(int(l.N.Lineno), "label %v not defined", lab.Sym)
  1120  			}
  1121  			continue
  1122  		}
  1123  
  1124  		if lab.Use == nil && lab.Used == 0 {
  1125  			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
  1126  			continue
  1127  		}
  1128  
  1129  		if lab.Gotopc != nil {
  1130  			Fatal("label %v never resolved", lab.Sym)
  1131  		}
  1132  		for l = lab.Use; l != nil; l = l.Next {
  1133  			checkgoto(l.N, lab.Def)
  1134  		}
  1135  	}
  1136  }
  1137  
  1138  // Componentgen copies a composite value by moving its individual components.
  1139  // Slices, strings and interfaces are supported. Small structs or arrays with
  1140  // elements of basic type are also supported.
  1141  // nr is nil when assigning a zero value.
  1142  func Componentgen(nr, nl *Node) bool {
  1143  	return componentgen_wb(nr, nl, false)
  1144  }
  1145  
  1146  // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
  1147  func componentgen_wb(nr, nl *Node, wb bool) bool {
  1148  	// Don't generate any code for complete copy of a variable into itself.
  1149  	// It's useless, and the VARDEF will incorrectly mark the old value as dead.
  1150  	// (This check assumes that the arguments passed to componentgen did not
  1151  	// themselves come from Igen, or else we could have Op==ONAME but
  1152  	// with a Type and Xoffset describing an individual field, not the entire
  1153  	// variable.)
  1154  	if nl.Op == ONAME && nl == nr {
  1155  		return true
  1156  	}
  1157  
  1158  	// Count number of moves required to move components.
  1159  	// If using write barrier, can only emit one pointer.
  1160  	// TODO(rsc): Allow more pointers, for reflect.Value.
  1161  	const maxMoves = 8
  1162  	n := 0
  1163  	numPtr := 0
  1164  	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1165  		n++
  1166  		if int(Simtype[t.Etype]) == Tptr && t != itable {
  1167  			numPtr++
  1168  		}
  1169  		return n <= maxMoves && (!wb || numPtr <= 1)
  1170  	})
  1171  	if n > maxMoves || wb && numPtr > 1 {
  1172  		return false
  1173  	}
  1174  
  1175  	// Must call emitVardef after evaluating rhs but before writing to lhs.
  1176  	emitVardef := func() {
  1177  		// Emit vardef if needed.
  1178  		if nl.Op == ONAME {
  1179  			switch nl.Type.Etype {
  1180  			case TARRAY, TSTRING, TINTER, TSTRUCT:
  1181  				Gvardef(nl)
  1182  			}
  1183  		}
  1184  	}
  1185  
  1186  	isConstString := Isconst(nr, CTSTR)
  1187  
  1188  	if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
  1189  		return false
  1190  	}
  1191  
  1192  	var nodl Node
  1193  	if cadable(nl) {
  1194  		nodl = *nl
  1195  	} else {
  1196  		if nr != nil && !cadable(nr) && !isConstString {
  1197  			return false
  1198  		}
  1199  		if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
  1200  			Igen(nl, &nodl, nil)
  1201  			defer Regfree(&nodl)
  1202  		}
  1203  	}
  1204  	lbase := nodl.Xoffset
  1205  
  1206  	// Special case: zeroing.
  1207  	var nodr Node
  1208  	if nr == nil {
  1209  		// When zeroing, prepare a register containing zero.
  1210  		// TODO(rsc): Check that this is actually generating the best code.
  1211  		if Thearch.REGZERO != 0 {
  1212  			// cpu has a dedicated zero register
  1213  			Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
  1214  		} else {
  1215  			// no dedicated zero register
  1216  			var zero Node
  1217  			Nodconst(&zero, nl.Type, 0)
  1218  			Regalloc(&nodr, Types[TUINT], nil)
  1219  			Thearch.Gmove(&zero, &nodr)
  1220  			defer Regfree(&nodr)
  1221  		}
  1222  
  1223  		emitVardef()
  1224  		visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1225  			nodl.Type = t
  1226  			nodl.Xoffset = lbase + offset
  1227  			nodr.Type = t
  1228  			if Isfloat[t.Etype] {
  1229  				// TODO(rsc): Cache zero register like we do for integers?
  1230  				Clearslim(&nodl)
  1231  			} else {
  1232  				Thearch.Gmove(&nodr, &nodl)
  1233  			}
  1234  			return true
  1235  		})
  1236  		return true
  1237  	}
  1238  
  1239  	// Special case: assignment of string constant.
  1240  	if isConstString {
  1241  		emitVardef()
  1242  
  1243  		// base
  1244  		nodl.Type = Ptrto(Types[TUINT8])
  1245  		Regalloc(&nodr, Types[Tptr], nil)
  1246  		p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
  1247  		Datastring(nr.Val.U.Sval, &p.From)
  1248  		p.From.Type = obj.TYPE_ADDR
  1249  		Thearch.Gmove(&nodr, &nodl)
  1250  		Regfree(&nodr)
  1251  
  1252  		// length
  1253  		nodl.Type = Types[Simtype[TUINT]]
  1254  		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
  1255  		Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
  1256  		Thearch.Gmove(&nodr, &nodl)
  1257  		return true
  1258  	}
  1259  
  1260  	// General case: copy nl = nr.
  1261  	nodr = *nr
  1262  	if !cadable(nr) {
  1263  		if nr.Ullman >= UINF && nodl.Op == OINDREG {
  1264  			Fatal("miscompile")
  1265  		}
  1266  		Igen(nr, &nodr, nil)
  1267  		defer Regfree(&nodr)
  1268  	}
  1269  	rbase := nodr.Xoffset
  1270  
  1271  	if nodl.Op == 0 {
  1272  		Igen(nl, &nodl, nil)
  1273  		defer Regfree(&nodl)
  1274  		lbase = nodl.Xoffset
  1275  	}
  1276  
  1277  	emitVardef()
  1278  	var (
  1279  		ptrType   *Type
  1280  		ptrOffset int64
  1281  	)
  1282  	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
  1283  		if wb && int(Simtype[t.Etype]) == Tptr && t != itable {
  1284  			if ptrType != nil {
  1285  				Fatal("componentgen_wb %v", Tconv(nl.Type, 0))
  1286  			}
  1287  			ptrType = t
  1288  			ptrOffset = offset
  1289  			return true
  1290  		}
  1291  		nodl.Type = t
  1292  		nodl.Xoffset = lbase + offset
  1293  		nodr.Type = t
  1294  		nodr.Xoffset = rbase + offset
  1295  		Thearch.Gmove(&nodr, &nodl)
  1296  		return true
  1297  	})
  1298  	if ptrType != nil {
  1299  		nodl.Type = ptrType
  1300  		nodl.Xoffset = lbase + ptrOffset
  1301  		nodr.Type = ptrType
  1302  		nodr.Xoffset = rbase + ptrOffset
  1303  		cgen_wbptr(&nodr, &nodl)
  1304  	}
  1305  	return true
  1306  }
  1307  
  1308  // visitComponents walks the individual components of the type t,
  1309  // walking into array elements, struct fields, the real and imaginary
  1310  // parts of complex numbers, and on 32-bit systems the high and
  1311  // low halves of 64-bit integers.
  1312  // It calls f for each such component, passing the component (aka element)
  1313  // type and memory offset, assuming t starts at startOffset.
  1314  // If f ever returns false, visitComponents returns false without any more
  1315  // calls to f. Otherwise visitComponents returns true.
  1316  func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
  1317  	switch t.Etype {
  1318  	case TINT64:
  1319  		if Widthreg == 8 {
  1320  			break
  1321  		}
  1322  		// NOTE: Assuming little endian (signed top half at offset 4).
  1323  		// We don't have any 32-bit big-endian systems.
  1324  		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
  1325  			Fatal("unknown 32-bit architecture")
  1326  		}
  1327  		return f(Types[TUINT32], startOffset) &&
  1328  			f(Types[TINT32], startOffset+4)
  1329  
  1330  	case TUINT64:
  1331  		if Widthreg == 8 {
  1332  			break
  1333  		}
  1334  		return f(Types[TUINT32], startOffset) &&
  1335  			f(Types[TUINT32], startOffset+4)
  1336  
  1337  	case TCOMPLEX64:
  1338  		return f(Types[TFLOAT32], startOffset) &&
  1339  			f(Types[TFLOAT32], startOffset+4)
  1340  
  1341  	case TCOMPLEX128:
  1342  		return f(Types[TFLOAT64], startOffset) &&
  1343  			f(Types[TFLOAT64], startOffset+8)
  1344  
  1345  	case TINTER:
  1346  		return f(itable, startOffset) &&
  1347  			f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
  1348  		return true
  1349  
  1350  	case TSTRING:
  1351  		return f(Ptrto(Types[TUINT8]), startOffset) &&
  1352  			f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
  1353  
  1354  	case TARRAY:
  1355  		if Isslice(t) {
  1356  			return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
  1357  				f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
  1358  				f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
  1359  		}
  1360  
  1361  		// Short-circuit [1e6]struct{}.
  1362  		if t.Type.Width == 0 {
  1363  			return true
  1364  		}
  1365  
  1366  		for i := int64(0); i < t.Bound; i++ {
  1367  			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
  1368  				return false
  1369  			}
  1370  		}
  1371  		return true
  1372  
  1373  	case TSTRUCT:
  1374  		if t.Type != nil && t.Type.Width != 0 {
  1375  			// NOTE(rsc): If this happens, the right thing to do is to say
  1376  			//	startOffset -= t.Type.Width
  1377  			// but I want to see if it does.
  1378  			// The old version of componentgen handled this,
  1379  			// in code introduced in CL 6932045 to fix issue #4518.
  1380  			// But the test case in issue 4518 does not trigger this anymore,
  1381  			// so maybe this complication is no longer needed.
  1382  			Fatal("struct not at offset 0")
  1383  		}
  1384  
  1385  		for field := t.Type; field != nil; field = field.Down {
  1386  			if field.Etype != TFIELD {
  1387  				Fatal("bad struct")
  1388  			}
  1389  			if !visitComponents(field.Type, startOffset+field.Width, f) {
  1390  				return false
  1391  			}
  1392  		}
  1393  		return true
  1394  	}
  1395  	return f(t, startOffset)
  1396  }
  1397  
  1398  func cadable(n *Node) bool {
  1399  	// Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
  1400  	return n.Addable && n.Op == ONAME
  1401  }