github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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  		lab = newlab(n);
   305  
   306  		// if there are pending gotos, resolve them all to the current pc.
   307  		for(p1=lab->gotopc; p1; p1=p2) {
   308  			p2 = unpatch(p1);
   309  			patch(p1, pc);
   310  		}
   311  		lab->gotopc = P;
   312  		if(lab->labelpc == P)
   313  			lab->labelpc = pc;
   314  
   315  		if(n->defn) {
   316  			switch(n->defn->op) {
   317  			case OFOR:
   318  			case OSWITCH:
   319  			case OSELECT:
   320  				// so stmtlabel can find the label
   321  				n->defn->sym = lab->sym;
   322  			}
   323  		}
   324  		break;
   325  
   326  	case OGOTO:
   327  		// if label is defined, emit jump to it.
   328  		// otherwise save list of pending gotos in lab->gotopc.
   329  		// the list is linked through the normal jump target field
   330  		// to avoid a second list.  (the jumps are actually still
   331  		// valid code, since they're just going to another goto
   332  		// to the same label.  we'll unwind it when we learn the pc
   333  		// of the label in the OLABEL case above.)
   334  		lab = newlab(n);
   335  		if(lab->labelpc != P)
   336  			gjmp(lab->labelpc);
   337  		else
   338  			lab->gotopc = gjmp(lab->gotopc);
   339  		break;
   340  
   341  	case OBREAK:
   342  		if(n->left != N) {
   343  			lab = n->left->sym->label;
   344  			if(lab == L) {
   345  				yyerror("break label not defined: %S", n->left->sym);
   346  				break;
   347  			}
   348  			lab->used = 1;
   349  			if(lab->breakpc == P) {
   350  				yyerror("invalid break label %S", n->left->sym);
   351  				break;
   352  			}
   353  			gjmp(lab->breakpc);
   354  			break;
   355  		}
   356  		if(breakpc == P) {
   357  			yyerror("break is not in a loop");
   358  			break;
   359  		}
   360  		gjmp(breakpc);
   361  		break;
   362  
   363  	case OCONTINUE:
   364  		if(n->left != N) {
   365  			lab = n->left->sym->label;
   366  			if(lab == L) {
   367  				yyerror("continue label not defined: %S", n->left->sym);
   368  				break;
   369  			}
   370  			lab->used = 1;
   371  			if(lab->continpc == P) {
   372  				yyerror("invalid continue label %S", n->left->sym);
   373  				break;
   374  			}
   375  			gjmp(lab->continpc);
   376  			break;
   377  		}
   378  		if(continpc == P) {
   379  			yyerror("continue is not in a loop");
   380  			break;
   381  		}
   382  		gjmp(continpc);
   383  		break;
   384  
   385  	case OFOR:
   386  		sbreak = breakpc;
   387  		p1 = gjmp(P);			//		goto test
   388  		breakpc = gjmp(P);		// break:	goto done
   389  		scontin = continpc;
   390  		continpc = pc;
   391  
   392  		// define break and continue labels
   393  		if((lab = stmtlabel(n)) != L) {
   394  			lab->breakpc = breakpc;
   395  			lab->continpc = continpc;
   396  		}
   397  		gen(n->nincr);				// contin:	incr
   398  		patch(p1, pc);				// test:
   399  		bgen(n->ntest, 0, -1, breakpc);		//		if(!test) goto break
   400  		genlist(n->nbody);				//		body
   401  		gjmp(continpc);
   402  		patch(breakpc, pc);			// done:
   403  		continpc = scontin;
   404  		breakpc = sbreak;
   405  		if(lab) {
   406  			lab->breakpc = P;
   407  			lab->continpc = P;
   408  		}
   409  		break;
   410  
   411  	case OIF:
   412  		p1 = gjmp(P);			//		goto test
   413  		p2 = gjmp(P);			// p2:		goto else
   414  		patch(p1, pc);				// test:
   415  		bgen(n->ntest, 0, -n->likely, p2);		//		if(!test) goto p2
   416  		genlist(n->nbody);				//		then
   417  		p3 = gjmp(P);			//		goto done
   418  		patch(p2, pc);				// else:
   419  		genlist(n->nelse);				//		else
   420  		patch(p3, pc);				// done:
   421  		break;
   422  
   423  	case OSWITCH:
   424  		sbreak = breakpc;
   425  		p1 = gjmp(P);			//		goto test
   426  		breakpc = gjmp(P);		// break:	goto done
   427  
   428  		// define break label
   429  		if((lab = stmtlabel(n)) != L)
   430  			lab->breakpc = breakpc;
   431  
   432  		patch(p1, pc);				// test:
   433  		genlist(n->nbody);				//		switch(test) body
   434  		patch(breakpc, pc);			// done:
   435  		breakpc = sbreak;
   436  		if(lab != L)
   437  			lab->breakpc = P;
   438  		break;
   439  
   440  	case OSELECT:
   441  		sbreak = breakpc;
   442  		p1 = gjmp(P);			//		goto test
   443  		breakpc = gjmp(P);		// break:	goto done
   444  
   445  		// define break label
   446  		if((lab = stmtlabel(n)) != L)
   447  			lab->breakpc = breakpc;
   448  
   449  		patch(p1, pc);				// test:
   450  		genlist(n->nbody);				//		select() body
   451  		patch(breakpc, pc);			// done:
   452  		breakpc = sbreak;
   453  		if(lab != L)
   454  			lab->breakpc = P;
   455  		break;
   456  
   457  	case OASOP:
   458  		cgen_asop(n);
   459  		break;
   460  
   461  	case ODCL:
   462  		cgen_dcl(n->left);
   463  		break;
   464  
   465  	case OAS:
   466  		if(gen_as_init(n))
   467  			break;
   468  		cgen_as(n->left, n->right);
   469  		break;
   470  
   471  	case OCALLMETH:
   472  		cgen_callmeth(n, 0);
   473  		break;
   474  
   475  	case OCALLINTER:
   476  		cgen_callinter(n, N, 0);
   477  		break;
   478  
   479  	case OCALLFUNC:
   480  		cgen_call(n, 0);
   481  		break;
   482  
   483  	case OPROC:
   484  		cgen_proc(n, 1);
   485  		break;
   486  
   487  	case ODEFER:
   488  		cgen_proc(n, 2);
   489  		break;
   490  
   491  	case ORETURN:
   492  	case ORETJMP:
   493  		cgen_ret(n);
   494  		break;
   495  	
   496  	case OCHECKNIL:
   497  		cgen_checknil(n->left);
   498  	}
   499  
   500  ret:
   501  	if(anyregalloc() != wasregalloc) {
   502  		dump("node", n);
   503  		fatal("registers left allocated");
   504  	}
   505  
   506  	lineno = lno;
   507  }
   508  
   509  /*
   510   * generate call to non-interface method
   511   *	proc=0	normal call
   512   *	proc=1	goroutine run in new proc
   513   *	proc=2	defer call save away stack
   514   */
   515  void
   516  cgen_callmeth(Node *n, int proc)
   517  {
   518  	Node n2;
   519  	Node *l;
   520  
   521  	// generate a rewrite in n2 for the method call
   522  	// (p.f)(...) goes to (f)(p,...)
   523  
   524  	l = n->left;
   525  	if(l->op != ODOTMETH)
   526  		fatal("cgen_callmeth: not dotmethod: %N");
   527  
   528  	n2 = *n;
   529  	n2.op = OCALLFUNC;
   530  	n2.left = l->right;
   531  	n2.left->type = l->type;
   532  
   533  	if(n2.left->op == ONAME)
   534  		n2.left->class = PFUNC;
   535  	cgen_call(&n2, proc);
   536  }
   537  
   538  /*
   539   * generate code to start new proc running call n.
   540   */
   541  static void
   542  cgen_proc(Node *n, int proc)
   543  {
   544  	switch(n->left->op) {
   545  	default:
   546  		fatal("cgen_proc: unknown call %O", n->left->op);
   547  
   548  	case OCALLMETH:
   549  		cgen_callmeth(n->left, proc);
   550  		break;
   551  
   552  	case OCALLINTER:
   553  		cgen_callinter(n->left, N, proc);
   554  		break;
   555  
   556  	case OCALLFUNC:
   557  		cgen_call(n->left, proc);
   558  		break;
   559  	}
   560  
   561  }
   562  
   563  /*
   564   * generate declaration.
   565   * nothing to do for on-stack automatics,
   566   * but might have to allocate heap copy
   567   * for escaped variables.
   568   */
   569  static void
   570  cgen_dcl(Node *n)
   571  {
   572  	if(debug['g'])
   573  		dump("\ncgen-dcl", n);
   574  	if(n->op != ONAME) {
   575  		dump("cgen_dcl", n);
   576  		fatal("cgen_dcl");
   577  	}
   578  	if(!(n->class & PHEAP))
   579  		return;
   580  	if(n->alloc == nil)
   581  		n->alloc = callnew(n->type);
   582  	cgen_as(n->heapaddr, n->alloc);
   583  }
   584  
   585  /*
   586   * generate discard of value
   587   */
   588  static void
   589  cgen_discard(Node *nr)
   590  {
   591  	Node tmp;
   592  
   593  	if(nr == N)
   594  		return;
   595  
   596  	switch(nr->op) {
   597  	case ONAME:
   598  		if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
   599  			gused(nr);
   600  		break;
   601  
   602  	// unary
   603  	case OADD:
   604  	case OAND:
   605  	case ODIV:
   606  	case OEQ:
   607  	case OGE:
   608  	case OGT:
   609  	case OLE:
   610  	case OLSH:
   611  	case OLT:
   612  	case OMOD:
   613  	case OMUL:
   614  	case ONE:
   615  	case OOR:
   616  	case ORSH:
   617  	case OSUB:
   618  	case OXOR:
   619  		cgen_discard(nr->left);
   620  		cgen_discard(nr->right);
   621  		break;
   622  
   623  	// binary
   624  	case OCAP:
   625  	case OCOM:
   626  	case OLEN:
   627  	case OMINUS:
   628  	case ONOT:
   629  	case OPLUS:
   630  		cgen_discard(nr->left);
   631  		break;
   632  	
   633  	case OIND:
   634  		cgen_checknil(nr->left);
   635  		break;
   636  
   637  	// special enough to just evaluate
   638  	default:
   639  		tempname(&tmp, nr->type);
   640  		cgen_as(&tmp, nr);
   641  		gused(&tmp);
   642  	}
   643  }
   644  
   645  /*
   646   * clearslim generates code to zero a slim node.
   647   */
   648  void
   649  clearslim(Node *n)
   650  {
   651  	Node z;
   652  	Mpflt zero;
   653  
   654  	memset(&z, 0, sizeof(z));
   655  	z.op = OLITERAL;
   656  	z.type = n->type;
   657  	z.addable = 1;
   658  
   659  	switch(simtype[n->type->etype]) {
   660  	case TCOMPLEX64:
   661  	case TCOMPLEX128:
   662  		z.val.u.cval = mal(sizeof(*z.val.u.cval));
   663  		mpmovecflt(&z.val.u.cval->real, 0.0);
   664  		mpmovecflt(&z.val.u.cval->imag, 0.0);
   665  		break;
   666  
   667  	case TFLOAT32:
   668  	case TFLOAT64:
   669  		mpmovecflt(&zero, 0.0);
   670  		z.val.ctype = CTFLT;
   671  		z.val.u.fval = &zero;
   672  		break;
   673  
   674  	case TPTR32:
   675  	case TPTR64:
   676  	case TCHAN:
   677  	case TMAP:
   678  		z.val.ctype = CTNIL;
   679  		break;
   680  
   681  	case TBOOL:
   682  		z.val.ctype = CTBOOL;
   683  		break;
   684  
   685  	case TINT8:
   686  	case TINT16:
   687  	case TINT32:
   688  	case TINT64:
   689  	case TUINT8:
   690  	case TUINT16:
   691  	case TUINT32:
   692  	case TUINT64:
   693  		z.val.ctype = CTINT;
   694  		z.val.u.xval = mal(sizeof(*z.val.u.xval));
   695  		mpmovecfix(z.val.u.xval, 0);
   696  		break;
   697  
   698  	default:
   699  		fatal("clearslim called on type %T", n->type);
   700  	}
   701  
   702  	ullmancalc(&z);
   703  	cgen(&z, n);
   704  }
   705  
   706  /*
   707   * generate assignment:
   708   *	nl = nr
   709   * nr == N means zero nl.
   710   */
   711  void
   712  cgen_as(Node *nl, Node *nr)
   713  {
   714  	Type *tl;
   715  
   716  	if(debug['g']) {
   717  		dump("cgen_as", nl);
   718  		dump("cgen_as = ", nr);
   719  	}
   720  
   721  	while(nr != N && nr->op == OCONVNOP)
   722  		nr = nr->left;
   723  
   724  	if(nl == N || isblank(nl)) {
   725  		cgen_discard(nr);
   726  		return;
   727  	}
   728  
   729  	if(nr == N || isnil(nr)) {
   730  		// externals and heaps should already be clear
   731  		if(nr == N) {
   732  			if(nl->class == PEXTERN)
   733  				return;
   734  			if(nl->class & PHEAP)
   735  				return;
   736  		}
   737  
   738  		tl = nl->type;
   739  		if(tl == T)
   740  			return;
   741  		if(isfat(tl)) {
   742  			clearfat(nl);
   743  			return;
   744  		}
   745  		clearslim(nl);
   746  		return;
   747  	}
   748  
   749  	tl = nl->type;
   750  	if(tl == T)
   751  		return;
   752  
   753  	cgen(nr, nl);
   754  }
   755  
   756  /*
   757   * generate:
   758   *	res = iface{typ, data}
   759   * n->left is typ
   760   * n->right is data
   761   */
   762  void
   763  cgen_eface(Node *n, Node *res)
   764  {
   765  	/* 
   766  	 * the right node of an eface may contain function calls that uses res as an argument,
   767  	 * so it's important that it is done first
   768  	 */
   769  	Node dst;
   770  	dst = *res;
   771  	dst.type = types[tptr];
   772  	dst.xoffset += widthptr;
   773  	cgen(n->right, &dst);
   774  	dst.xoffset -= widthptr;
   775  	cgen(n->left, &dst);
   776  }
   777  
   778  /*
   779   * generate:
   780   *	res = s[lo, hi];
   781   * n->left is s
   782   * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
   783   * caller (cgen) guarantees res is an addable ONAME.
   784   *
   785   * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
   786   */
   787  void
   788  cgen_slice(Node *n, Node *res)
   789  {
   790  	Node src, dst, *cap, *len, *offs, *add;
   791  
   792  	cap = n->list->n;
   793  	len = n->list->next->n;
   794  	offs = N;
   795  	if(n->list->next->next)
   796  		offs = n->list->next->next->n;
   797  
   798  	// dst.len = hi [ - lo ]
   799  	dst = *res;
   800  	dst.xoffset += Array_nel;
   801  	dst.type = types[simtype[TUINT]];
   802  	cgen(len, &dst);
   803  
   804  	if(n->op != OSLICESTR) {
   805  		// dst.cap = cap [ - lo ]
   806  		dst = *res;
   807  		dst.xoffset += Array_cap;
   808  		dst.type = types[simtype[TUINT]];
   809  		cgen(cap, &dst);
   810  	}
   811  
   812  	// dst.array = src.array  [ + lo *width ]
   813  	dst = *res;
   814  	dst.xoffset += Array_array;
   815  	dst.type = types[TUINTPTR];
   816  
   817  	if(isnil(n->left)) {
   818  		tempname(&src, n->left->type);
   819  		cgen(n->left, &src);
   820  	} else
   821  		src = *n->left;
   822  	if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
   823  		src.xoffset += Array_array;
   824  	src.type = types[TUINTPTR];
   825  
   826  	if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
   827  		if(!isptr[n->left->type->etype])
   828  			fatal("slicearr is supposed to work on pointer: %+N\n", n);
   829  		cgen(&src, &dst);
   830  		cgen_checknil(&dst);
   831  		if(offs != N) {
   832  			add = nod(OADD, &dst, offs);
   833  			typecheck(&add, Erv);
   834  			cgen(add, &dst);
   835  		}
   836  	} else if(offs == N) {
   837  		cgen(&src, &dst);
   838  	} else {
   839  		add = nod(OADD, &src, offs);
   840  		typecheck(&add, Erv);
   841  		cgen(add, &dst);
   842  	}
   843  }
   844  
   845  /*
   846   * gather series of offsets
   847   * >=0 is direct addressed field
   848   * <0 is pointer to next field (+1)
   849   */
   850  int
   851  dotoffset(Node *n, int64 *oary, Node **nn)
   852  {
   853  	int i;
   854  
   855  	switch(n->op) {
   856  	case ODOT:
   857  		if(n->xoffset == BADWIDTH) {
   858  			dump("bad width in dotoffset", n);
   859  			fatal("bad width in dotoffset");
   860  		}
   861  		i = dotoffset(n->left, oary, nn);
   862  		if(i > 0) {
   863  			if(oary[i-1] >= 0)
   864  				oary[i-1] += n->xoffset;
   865  			else
   866  				oary[i-1] -= n->xoffset;
   867  			break;
   868  		}
   869  		if(i < 10)
   870  			oary[i++] = n->xoffset;
   871  		break;
   872  
   873  	case ODOTPTR:
   874  		if(n->xoffset == BADWIDTH) {
   875  			dump("bad width in dotoffset", n);
   876  			fatal("bad width in dotoffset");
   877  		}
   878  		i = dotoffset(n->left, oary, nn);
   879  		if(i < 10)
   880  			oary[i++] = -(n->xoffset+1);
   881  		break;
   882  
   883  	default:
   884  		*nn = n;
   885  		return 0;
   886  	}
   887  	if(i >= 10)
   888  		*nn = N;
   889  	return i;
   890  }
   891  
   892  /*
   893   * make a new off the books
   894   */
   895  void
   896  tempname(Node *nn, Type *t)
   897  {
   898  	Node *n;
   899  	Sym *s;
   900  
   901  	if(curfn == N)
   902  		fatal("no curfn for tempname");
   903  
   904  	if(t == T) {
   905  		yyerror("tempname called with nil type");
   906  		t = types[TINT32];
   907  	}
   908  
   909  	// give each tmp a different name so that there
   910  	// a chance to registerizer them
   911  	snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
   912  	statuniqgen++;
   913  	s = lookup(namebuf);
   914  	n = nod(ONAME, N, N);
   915  	n->sym = s;
   916  	s->def = n;
   917  	n->type = t;
   918  	n->class = PAUTO;
   919  	n->addable = 1;
   920  	n->ullman = 1;
   921  	n->esc = EscNever;
   922  	n->curfn = curfn;
   923  	curfn->dcl = list(curfn->dcl, n);
   924  
   925  	dowidth(t);
   926  	n->xoffset = 0;
   927  	*nn = *n;
   928  }
   929  
   930  Node*
   931  temp(Type *t)
   932  {
   933  	Node *n;
   934  	
   935  	n = nod(OXXX, N, N);
   936  	tempname(n, t);
   937  	n->sym->def->used = 1;
   938  	return n;
   939  }