github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/gc/gen.c (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  /*
     6   * portable half of code generator.
     7   * mainly statements and control flow.
     8   */
     9  
    10  #include <u.h>
    11  #include <libc.h>
    12  #include "go.h"
    13  
    14  static void	cgen_dcl(Node *n);
    15  static void	cgen_proc(Node *n, int proc);
    16  static void	checkgoto(Node*, Node*);
    17  
    18  static Label *labellist;
    19  static Label *lastlabel;
    20  
    21  Node*
    22  sysfunc(char *name)
    23  {
    24  	Node *n;
    25  
    26  	n = newname(pkglookup(name, runtimepkg));
    27  	n->class = PFUNC;
    28  	return n;
    29  }
    30  
    31  /*
    32   * the address of n has been taken and might be used after
    33   * the current function returns.  mark any local vars
    34   * as needing to move to the heap.
    35   */
    36  void
    37  addrescapes(Node *n)
    38  {
    39  	char buf[100];
    40  	Node *oldfn;
    41  
    42  	switch(n->op) {
    43  	default:
    44  		// probably a type error already.
    45  		// dump("addrescapes", n);
    46  		break;
    47  
    48  	case ONAME:
    49  		if(n == nodfp)
    50  			break;
    51  
    52  		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
    53  		// on PPARAM it means something different.
    54  		if(n->class == PAUTO && n->esc == EscNever)
    55  			break;
    56  
    57  		if(debug['N'] && n->esc != EscUnknown)
    58  			fatal("without escape analysis, only PAUTO's should have esc: %N", n);
    59  
    60  		switch(n->class) {
    61  		case PPARAMREF:
    62  			addrescapes(n->defn);
    63  			break;
    64  		case PPARAM:
    65  		case PPARAMOUT:
    66  			// if func param, need separate temporary
    67  			// to hold heap pointer.
    68  			// the function type has already been checked
    69  			// (we're in the function body)
    70  			// so the param already has a valid xoffset.
    71  
    72  			// expression to refer to stack copy
    73  			n->stackparam = nod(OPARAM, n, N);
    74  			n->stackparam->type = n->type;
    75  			n->stackparam->addable = 1;
    76  			if(n->xoffset == BADWIDTH)
    77  				fatal("addrescapes before param assignment");
    78  			n->stackparam->xoffset = n->xoffset;
    79  			// fallthrough
    80  
    81  		case PAUTO:
    82  			n->class |= PHEAP;
    83  			n->addable = 0;
    84  			n->ullman = 2;
    85  			n->xoffset = 0;
    86  
    87  			// create stack variable to hold pointer to heap
    88  			oldfn = curfn;
    89  			curfn = n->curfn;
    90  			n->heapaddr = temp(ptrto(n->type));
    91  			snprint(buf, sizeof buf, "&%S", n->sym);
    92  			n->heapaddr->sym = lookup(buf);
    93  			n->heapaddr->orig->sym = n->heapaddr->sym;
    94  			if(!debug['N'])
    95  				n->esc = EscHeap;
    96  			if(debug['m'])
    97  				print("%L: moved to heap: %N\n", n->lineno, n);
    98  			curfn = oldfn;
    99  			break;
   100  		}
   101  		break;
   102  
   103  	case OIND:
   104  	case ODOTPTR:
   105  		break;
   106  
   107  	case ODOT:
   108  	case OINDEX:
   109  		// ODOTPTR has already been introduced,
   110  		// so these are the non-pointer ODOT and OINDEX.
   111  		// In &x[0], if x is a slice, then x does not
   112  		// escape--the pointer inside x does, but that
   113  		// is always a heap pointer anyway.
   114  		if(!isslice(n->left->type))
   115  			addrescapes(n->left);
   116  		break;
   117  	}
   118  }
   119  
   120  void
   121  clearlabels(void)
   122  {
   123  	Label *l;
   124  
   125  	for(l=labellist; l!=L; l=l->link)
   126  		l->sym->label = L;
   127  	
   128  	labellist = L;
   129  	lastlabel = L;
   130  }
   131  
   132  static Label*
   133  newlab(Node *n)
   134  {
   135  	Sym *s;
   136  	Label *lab;
   137  	
   138  	s = n->left->sym;
   139  	if((lab = s->label) == L) {
   140  		lab = mal(sizeof(*lab));
   141  		if(lastlabel == nil)
   142  			labellist = lab;
   143  		else
   144  			lastlabel->link = lab;
   145  		lastlabel = lab;
   146  		lab->sym = s;
   147  		s->label = lab;
   148  	}
   149  	
   150  	if(n->op == OLABEL) {
   151  		if(lab->def != N)
   152  			yyerror("label %S already defined at %L", s, lab->def->lineno);
   153  		else
   154  			lab->def = n;
   155  	} else
   156  		lab->use = list(lab->use, n);
   157  
   158  	return lab;
   159  }
   160  
   161  void
   162  checklabels(void)
   163  {
   164  	Label *lab;
   165  	NodeList *l;
   166  
   167  	for(lab=labellist; lab!=L; lab=lab->link) {
   168  		if(lab->def == N) {
   169  			for(l=lab->use; l; l=l->next)
   170  				yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
   171  			continue;
   172  		}
   173  		if(lab->use == nil && !lab->used) {
   174  			yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
   175  			continue;
   176  		}
   177  		if(lab->gotopc != P)
   178  			fatal("label %S never resolved", lab->sym);
   179  		for(l=lab->use; l; l=l->next)
   180  			checkgoto(l->n, lab->def);
   181  	}
   182  }
   183  
   184  static void
   185  checkgoto(Node *from, Node *to)
   186  {
   187  	int nf, nt;
   188  	Sym *block, *dcl, *fs, *ts;
   189  	int lno;
   190  
   191  	if(from->sym == to->sym)
   192  		return;
   193  
   194  	nf = 0;
   195  	for(fs=from->sym; fs; fs=fs->link)
   196  		nf++;
   197  	nt = 0;
   198  	for(fs=to->sym; fs; fs=fs->link)
   199  		nt++;
   200  	fs = from->sym;
   201  	for(; nf > nt; nf--)
   202  		fs = fs->link;
   203  	if(fs != to->sym) {
   204  		lno = lineno;
   205  		setlineno(from);
   206  
   207  		// decide what to complain about.
   208  		// prefer to complain about 'into block' over declarations,
   209  		// so scan backward to find most recent block or else dcl.
   210  		block = S;
   211  		dcl = S;
   212  		ts = to->sym;
   213  		for(; nt > nf; nt--) {
   214  			if(ts->pkg == nil)
   215  				block = ts;
   216  			else
   217  				dcl = ts;
   218  			ts = ts->link;
   219  		}
   220  		while(ts != fs) {
   221  			if(ts->pkg == nil)
   222  				block = ts;
   223  			else
   224  				dcl = ts;
   225  			ts = ts->link;
   226  			fs = fs->link;
   227  		}
   228  
   229  		if(block)
   230  			yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
   231  		else
   232  			yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
   233  		lineno = lno;
   234  	}
   235  }
   236  
   237  static Label*
   238  stmtlabel(Node *n)
   239  {
   240  	Label *lab;
   241  
   242  	if(n->sym != S)
   243  	if((lab = n->sym->label) != L)
   244  	if(lab->def != N)
   245  	if(lab->def->defn == n)
   246  		return lab;
   247  	return L;
   248  }
   249  
   250  /*
   251   * compile statements
   252   */
   253  void
   254  genlist(NodeList *l)
   255  {
   256  	for(; l; l=l->next)
   257  		gen(l->n);
   258  }
   259  
   260  void
   261  gen(Node *n)
   262  {
   263  	int32 lno;
   264  	Prog *scontin, *sbreak;
   265  	Prog *p1, *p2, *p3;
   266  	Label *lab;
   267  	int32 wasregalloc;
   268  
   269  //dump("gen", n);
   270  
   271  	lno = setlineno(n);
   272  	wasregalloc = anyregalloc();
   273  
   274  	if(n == N)
   275  		goto ret;
   276  
   277  	if(n->ninit)
   278  		genlist(n->ninit);
   279  
   280  	setlineno(n);
   281  
   282  	switch(n->op) {
   283  	default:
   284  		fatal("gen: unknown op %+hN", n);
   285  		break;
   286  
   287  	case OCASE:
   288  	case OFALL:
   289  	case OXCASE:
   290  	case OXFALL:
   291  	case ODCLCONST:
   292  	case ODCLFUNC:
   293  	case ODCLTYPE:
   294  		break;
   295  
   296  	case OEMPTY:
   297  		break;
   298  
   299  	case OBLOCK:
   300  		genlist(n->list);
   301  		break;
   302  
   303  	case OLABEL:
   304  		if(isblanksym(n->left->sym))
   305  			break;
   306  		
   307  		lab = newlab(n);
   308  
   309  		// if there are pending gotos, resolve them all to the current pc.
   310  		for(p1=lab->gotopc; p1; p1=p2) {
   311  			p2 = unpatch(p1);
   312  			patch(p1, pc);
   313  		}
   314  		lab->gotopc = P;
   315  		if(lab->labelpc == P)
   316  			lab->labelpc = pc;
   317  
   318  		if(n->defn) {
   319  			switch(n->defn->op) {
   320  			case OFOR:
   321  			case OSWITCH:
   322  			case OSELECT:
   323  				// so stmtlabel can find the label
   324  				n->defn->sym = lab->sym;
   325  			}
   326  		}
   327  		break;
   328  
   329  	case OGOTO:
   330  		// if label is defined, emit jump to it.
   331  		// otherwise save list of pending gotos in lab->gotopc.
   332  		// the list is linked through the normal jump target field
   333  		// to avoid a second list.  (the jumps are actually still
   334  		// valid code, since they're just going to another goto
   335  		// to the same label.  we'll unwind it when we learn the pc
   336  		// of the label in the OLABEL case above.)
   337  		lab = newlab(n);
   338  		if(lab->labelpc != P)
   339  			gjmp(lab->labelpc);
   340  		else
   341  			lab->gotopc = gjmp(lab->gotopc);
   342  		break;
   343  
   344  	case OBREAK:
   345  		if(n->left != N) {
   346  			lab = n->left->sym->label;
   347  			if(lab == L) {
   348  				yyerror("break label not defined: %S", n->left->sym);
   349  				break;
   350  			}
   351  			lab->used = 1;
   352  			if(lab->breakpc == P) {
   353  				yyerror("invalid break label %S", n->left->sym);
   354  				break;
   355  			}
   356  			gjmp(lab->breakpc);
   357  			break;
   358  		}
   359  		if(breakpc == P) {
   360  			yyerror("break is not in a loop");
   361  			break;
   362  		}
   363  		gjmp(breakpc);
   364  		break;
   365  
   366  	case OCONTINUE:
   367  		if(n->left != N) {
   368  			lab = n->left->sym->label;
   369  			if(lab == L) {
   370  				yyerror("continue label not defined: %S", n->left->sym);
   371  				break;
   372  			}
   373  			lab->used = 1;
   374  			if(lab->continpc == P) {
   375  				yyerror("invalid continue label %S", n->left->sym);
   376  				break;
   377  			}
   378  			gjmp(lab->continpc);
   379  			break;
   380  		}
   381  		if(continpc == P) {
   382  			yyerror("continue is not in a loop");
   383  			break;
   384  		}
   385  		gjmp(continpc);
   386  		break;
   387  
   388  	case OFOR:
   389  		sbreak = breakpc;
   390  		p1 = gjmp(P);			//		goto test
   391  		breakpc = gjmp(P);		// break:	goto done
   392  		scontin = continpc;
   393  		continpc = pc;
   394  
   395  		// define break and continue labels
   396  		if((lab = stmtlabel(n)) != L) {
   397  			lab->breakpc = breakpc;
   398  			lab->continpc = continpc;
   399  		}
   400  		gen(n->nincr);				// contin:	incr
   401  		patch(p1, pc);				// test:
   402  		bgen(n->ntest, 0, -1, breakpc);		//		if(!test) goto break
   403  		genlist(n->nbody);				//		body
   404  		gjmp(continpc);
   405  		patch(breakpc, pc);			// done:
   406  		continpc = scontin;
   407  		breakpc = sbreak;
   408  		if(lab) {
   409  			lab->breakpc = P;
   410  			lab->continpc = P;
   411  		}
   412  		break;
   413  
   414  	case OIF:
   415  		p1 = gjmp(P);			//		goto test
   416  		p2 = gjmp(P);			// p2:		goto else
   417  		patch(p1, pc);				// test:
   418  		bgen(n->ntest, 0, -n->likely, p2);		//		if(!test) goto p2
   419  		genlist(n->nbody);				//		then
   420  		p3 = gjmp(P);			//		goto done
   421  		patch(p2, pc);				// else:
   422  		genlist(n->nelse);				//		else
   423  		patch(p3, pc);				// done:
   424  		break;
   425  
   426  	case OSWITCH:
   427  		sbreak = breakpc;
   428  		p1 = gjmp(P);			//		goto test
   429  		breakpc = gjmp(P);		// break:	goto done
   430  
   431  		// define break label
   432  		if((lab = stmtlabel(n)) != L)
   433  			lab->breakpc = breakpc;
   434  
   435  		patch(p1, pc);				// test:
   436  		genlist(n->nbody);				//		switch(test) body
   437  		patch(breakpc, pc);			// done:
   438  		breakpc = sbreak;
   439  		if(lab != L)
   440  			lab->breakpc = P;
   441  		break;
   442  
   443  	case OSELECT:
   444  		sbreak = breakpc;
   445  		p1 = gjmp(P);			//		goto test
   446  		breakpc = gjmp(P);		// break:	goto done
   447  
   448  		// define break label
   449  		if((lab = stmtlabel(n)) != L)
   450  			lab->breakpc = breakpc;
   451  
   452  		patch(p1, pc);				// test:
   453  		genlist(n->nbody);				//		select() body
   454  		patch(breakpc, pc);			// done:
   455  		breakpc = sbreak;
   456  		if(lab != L)
   457  			lab->breakpc = P;
   458  		break;
   459  
   460  	case OASOP:
   461  		cgen_asop(n);
   462  		break;
   463  
   464  	case ODCL:
   465  		cgen_dcl(n->left);
   466  		break;
   467  
   468  	case OAS:
   469  		if(gen_as_init(n))
   470  			break;
   471  		cgen_as(n->left, n->right);
   472  		break;
   473  
   474  	case OCALLMETH:
   475  		cgen_callmeth(n, 0);
   476  		break;
   477  
   478  	case OCALLINTER:
   479  		cgen_callinter(n, N, 0);
   480  		break;
   481  
   482  	case OCALLFUNC:
   483  		cgen_call(n, 0);
   484  		break;
   485  
   486  	case OPROC:
   487  		cgen_proc(n, 1);
   488  		break;
   489  
   490  	case ODEFER:
   491  		cgen_proc(n, 2);
   492  		break;
   493  
   494  	case ORETURN:
   495  	case ORETJMP:
   496  		cgen_ret(n);
   497  		break;
   498  	
   499  	case OCHECKNIL:
   500  		cgen_checknil(n->left);
   501  		break;
   502  	
   503  	case OVARKILL:
   504  		gvarkill(n->left);
   505  		break;
   506  	}
   507  
   508  ret:
   509  	if(anyregalloc() != wasregalloc) {
   510  		dump("node", n);
   511  		fatal("registers left allocated");
   512  	}
   513  
   514  	lineno = lno;
   515  }
   516  
   517  /*
   518   * generate call to non-interface method
   519   *	proc=0	normal call
   520   *	proc=1	goroutine run in new proc
   521   *	proc=2	defer call save away stack
   522   */
   523  void
   524  cgen_callmeth(Node *n, int proc)
   525  {
   526  	Node n2;
   527  	Node *l;
   528  
   529  	// generate a rewrite in n2 for the method call
   530  	// (p.f)(...) goes to (f)(p,...)
   531  
   532  	l = n->left;
   533  	if(l->op != ODOTMETH)
   534  		fatal("cgen_callmeth: not dotmethod: %N");
   535  
   536  	n2 = *n;
   537  	n2.op = OCALLFUNC;
   538  	n2.left = l->right;
   539  	n2.left->type = l->type;
   540  
   541  	if(n2.left->op == ONAME)
   542  		n2.left->class = PFUNC;
   543  	cgen_call(&n2, proc);
   544  }
   545  
   546  /*
   547   * generate code to start new proc running call n.
   548   */
   549  static void
   550  cgen_proc(Node *n, int proc)
   551  {
   552  	switch(n->left->op) {
   553  	default:
   554  		fatal("cgen_proc: unknown call %O", n->left->op);
   555  
   556  	case OCALLMETH:
   557  		cgen_callmeth(n->left, proc);
   558  		break;
   559  
   560  	case OCALLINTER:
   561  		cgen_callinter(n->left, N, proc);
   562  		break;
   563  
   564  	case OCALLFUNC:
   565  		cgen_call(n->left, proc);
   566  		break;
   567  	}
   568  
   569  }
   570  
   571  /*
   572   * generate declaration.
   573   * have to allocate heap copy
   574   * for escaped variables.
   575   */
   576  static void
   577  cgen_dcl(Node *n)
   578  {
   579  	if(debug['g'])
   580  		dump("\ncgen-dcl", n);
   581  	if(n->op != ONAME) {
   582  		dump("cgen_dcl", n);
   583  		fatal("cgen_dcl");
   584  	}
   585  	if(!(n->class & PHEAP))
   586  		return;
   587  	if(n->alloc == nil)
   588  		n->alloc = callnew(n->type);
   589  	cgen_as(n->heapaddr, n->alloc);
   590  }
   591  
   592  /*
   593   * generate discard of value
   594   */
   595  static void
   596  cgen_discard(Node *nr)
   597  {
   598  	Node tmp;
   599  
   600  	if(nr == N)
   601  		return;
   602  
   603  	switch(nr->op) {
   604  	case ONAME:
   605  		if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
   606  			gused(nr);
   607  		break;
   608  
   609  	// unary
   610  	case OADD:
   611  	case OAND:
   612  	case ODIV:
   613  	case OEQ:
   614  	case OGE:
   615  	case OGT:
   616  	case OLE:
   617  	case OLSH:
   618  	case OLT:
   619  	case OMOD:
   620  	case OMUL:
   621  	case ONE:
   622  	case OOR:
   623  	case ORSH:
   624  	case OSUB:
   625  	case OXOR:
   626  		cgen_discard(nr->left);
   627  		cgen_discard(nr->right);
   628  		break;
   629  
   630  	// binary
   631  	case OCAP:
   632  	case OCOM:
   633  	case OLEN:
   634  	case OMINUS:
   635  	case ONOT:
   636  	case OPLUS:
   637  		cgen_discard(nr->left);
   638  		break;
   639  	
   640  	case OIND:
   641  		cgen_checknil(nr->left);
   642  		break;
   643  
   644  	// special enough to just evaluate
   645  	default:
   646  		tempname(&tmp, nr->type);
   647  		cgen_as(&tmp, nr);
   648  		gused(&tmp);
   649  	}
   650  }
   651  
   652  /*
   653   * clearslim generates code to zero a slim node.
   654   */
   655  void
   656  clearslim(Node *n)
   657  {
   658  	Node z;
   659  	Mpflt zero;
   660  
   661  	memset(&z, 0, sizeof(z));
   662  	z.op = OLITERAL;
   663  	z.type = n->type;
   664  	z.addable = 1;
   665  
   666  	switch(simtype[n->type->etype]) {
   667  	case TCOMPLEX64:
   668  	case TCOMPLEX128:
   669  		z.val.u.cval = mal(sizeof(*z.val.u.cval));
   670  		mpmovecflt(&z.val.u.cval->real, 0.0);
   671  		mpmovecflt(&z.val.u.cval->imag, 0.0);
   672  		break;
   673  
   674  	case TFLOAT32:
   675  	case TFLOAT64:
   676  		mpmovecflt(&zero, 0.0);
   677  		z.val.ctype = CTFLT;
   678  		z.val.u.fval = &zero;
   679  		break;
   680  
   681  	case TPTR32:
   682  	case TPTR64:
   683  	case TCHAN:
   684  	case TMAP:
   685  		z.val.ctype = CTNIL;
   686  		break;
   687  
   688  	case TBOOL:
   689  		z.val.ctype = CTBOOL;
   690  		break;
   691  
   692  	case TINT8:
   693  	case TINT16:
   694  	case TINT32:
   695  	case TINT64:
   696  	case TUINT8:
   697  	case TUINT16:
   698  	case TUINT32:
   699  	case TUINT64:
   700  		z.val.ctype = CTINT;
   701  		z.val.u.xval = mal(sizeof(*z.val.u.xval));
   702  		mpmovecfix(z.val.u.xval, 0);
   703  		break;
   704  
   705  	default:
   706  		fatal("clearslim called on type %T", n->type);
   707  	}
   708  
   709  	ullmancalc(&z);
   710  	cgen(&z, n);
   711  }
   712  
   713  /*
   714   * generate assignment:
   715   *	nl = nr
   716   * nr == N means zero nl.
   717   */
   718  void
   719  cgen_as(Node *nl, Node *nr)
   720  {
   721  	Type *tl;
   722  
   723  	if(debug['g']) {
   724  		dump("cgen_as", nl);
   725  		dump("cgen_as = ", nr);
   726  	}
   727  
   728  	while(nr != N && nr->op == OCONVNOP)
   729  		nr = nr->left;
   730  
   731  	if(nl == N || isblank(nl)) {
   732  		cgen_discard(nr);
   733  		return;
   734  	}
   735  
   736  	if(nr == N || isnil(nr)) {
   737  		// externals and heaps should already be clear
   738  		if(nr == N) {
   739  			if(nl->class == PEXTERN)
   740  				return;
   741  			if(nl->class & PHEAP)
   742  				return;
   743  		}
   744  
   745  		tl = nl->type;
   746  		if(tl == T)
   747  			return;
   748  		if(isfat(tl)) {
   749  			if(nl->op == ONAME)
   750  				gvardef(nl);
   751  			clearfat(nl);
   752  			return;
   753  		}
   754  		clearslim(nl);
   755  		return;
   756  	}
   757  
   758  	tl = nl->type;
   759  	if(tl == T)
   760  		return;
   761  
   762  	cgen(nr, nl);
   763  }
   764  
   765  /*
   766   * generate:
   767   *	res = iface{typ, data}
   768   * n->left is typ
   769   * n->right is data
   770   */
   771  void
   772  cgen_eface(Node *n, Node *res)
   773  {
   774  	/* 
   775  	 * the right node of an eface may contain function calls that uses res as an argument,
   776  	 * so it's important that it is done first
   777  	 */
   778  	Node dst;
   779  	Node *tmp;
   780  
   781  	tmp = temp(types[tptr]);
   782  	cgen(n->right, tmp);
   783  
   784  	gvardef(res);
   785  
   786  	dst = *res;
   787  	dst.type = types[tptr];
   788  	dst.xoffset += widthptr;
   789  	cgen(tmp, &dst);
   790  
   791  	dst.xoffset -= widthptr;
   792  	cgen(n->left, &dst);
   793  }
   794  
   795  /*
   796   * generate:
   797   *	res = s[lo, hi];
   798   * n->left is s
   799   * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
   800   * caller (cgen) guarantees res is an addable ONAME.
   801   *
   802   * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
   803   */
   804  void
   805  cgen_slice(Node *n, Node *res)
   806  {
   807  	Node src, dst, *cap, *len, *offs, *add, *base;
   808  
   809  	cap = n->list->n;
   810  	len = n->list->next->n;
   811  	offs = N;
   812  	if(n->list->next->next)
   813  		offs = n->list->next->next->n;
   814  
   815  	// evaluate base pointer first, because it is the only
   816  	// possibly complex expression. once that is evaluated
   817  	// and stored, updating the len and cap can be done
   818  	// without making any calls, so without doing anything that
   819  	// might cause preemption or garbage collection.
   820  	// this makes the whole slice update atomic as far as the
   821  	// garbage collector can see.
   822  	
   823  	base = temp(types[TUINTPTR]);
   824  
   825  	if(isnil(n->left)) {
   826  		tempname(&src, n->left->type);
   827  		cgen(n->left, &src);
   828  	} else
   829  		src = *n->left;
   830  	if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
   831  		src.xoffset += Array_array;
   832  
   833  	if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
   834  		if(!isptr[n->left->type->etype])
   835  			fatal("slicearr is supposed to work on pointer: %+N\n", n);
   836  		cgen(&src, base);
   837  		cgen_checknil(base);
   838  		if(offs != N) {
   839  			add = nod(OADD, base, offs);
   840  			typecheck(&add, Erv);
   841  			cgen(add, base);
   842  		}
   843  	} else if(offs == N) {
   844  		src.type = types[tptr];
   845  		cgen(&src, base);
   846  	} else {
   847  		src.type = types[tptr];
   848  		add = nod(OADDPTR, &src, offs);
   849  		typecheck(&add, Erv);
   850  		cgen(add, base);
   851  	}
   852  	
   853  	// committed to the update
   854  	gvardef(res);
   855  
   856  	// dst.array = src.array  [ + lo *width ]
   857  	dst = *res;
   858  	dst.xoffset += Array_array;
   859  	dst.type = types[tptr];
   860  	
   861  	cgen(base, &dst);
   862  
   863  	// dst.len = hi [ - lo ]
   864  	dst = *res;
   865  	dst.xoffset += Array_nel;
   866  	dst.type = types[simtype[TUINT]];
   867  	cgen(len, &dst);
   868  
   869  	if(n->op != OSLICESTR) {
   870  		// dst.cap = cap [ - lo ]
   871  		dst = *res;
   872  		dst.xoffset += Array_cap;
   873  		dst.type = types[simtype[TUINT]];
   874  		cgen(cap, &dst);
   875  	}
   876  }
   877  
   878  /*
   879   * gather series of offsets
   880   * >=0 is direct addressed field
   881   * <0 is pointer to next field (+1)
   882   */
   883  int
   884  dotoffset(Node *n, int64 *oary, Node **nn)
   885  {
   886  	int i;
   887  
   888  	switch(n->op) {
   889  	case ODOT:
   890  		if(n->xoffset == BADWIDTH) {
   891  			dump("bad width in dotoffset", n);
   892  			fatal("bad width in dotoffset");
   893  		}
   894  		i = dotoffset(n->left, oary, nn);
   895  		if(i > 0) {
   896  			if(oary[i-1] >= 0)
   897  				oary[i-1] += n->xoffset;
   898  			else
   899  				oary[i-1] -= n->xoffset;
   900  			break;
   901  		}
   902  		if(i < 10)
   903  			oary[i++] = n->xoffset;
   904  		break;
   905  
   906  	case ODOTPTR:
   907  		if(n->xoffset == BADWIDTH) {
   908  			dump("bad width in dotoffset", n);
   909  			fatal("bad width in dotoffset");
   910  		}
   911  		i = dotoffset(n->left, oary, nn);
   912  		if(i < 10)
   913  			oary[i++] = -(n->xoffset+1);
   914  		break;
   915  
   916  	default:
   917  		*nn = n;
   918  		return 0;
   919  	}
   920  	if(i >= 10)
   921  		*nn = N;
   922  	return i;
   923  }
   924  
   925  /*
   926   * make a new off the books
   927   */
   928  void
   929  tempname(Node *nn, Type *t)
   930  {
   931  	Node *n;
   932  	Sym *s;
   933  
   934  	if(curfn == N)
   935  		fatal("no curfn for tempname");
   936  
   937  	if(t == T) {
   938  		yyerror("tempname called with nil type");
   939  		t = types[TINT32];
   940  	}
   941  
   942  	// give each tmp a different name so that there
   943  	// a chance to registerizer them
   944  	snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
   945  	statuniqgen++;
   946  	s = lookup(namebuf);
   947  	n = nod(ONAME, N, N);
   948  	n->sym = s;
   949  	s->def = n;
   950  	n->type = t;
   951  	n->class = PAUTO;
   952  	n->addable = 1;
   953  	n->ullman = 1;
   954  	n->esc = EscNever;
   955  	n->curfn = curfn;
   956  	curfn->dcl = list(curfn->dcl, n);
   957  
   958  	dowidth(t);
   959  	n->xoffset = 0;
   960  	*nn = *n;
   961  }
   962  
   963  Node*
   964  temp(Type *t)
   965  {
   966  	Node *n;
   967  	
   968  	n = nod(OXXX, N, N);
   969  	tempname(n, t);
   970  	n->sym->def->used = 1;
   971  	return n->orig;
   972  }