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