github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/gc/pgen.c (about)

     1  // Copyright 2011 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  // "Portable" code generation.
     6  // Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
     7  // Must code to the intersection of the three back ends.
     8  
     9  #include	<u.h>
    10  #include	<libc.h>
    11  #include	"md5.h"
    12  #include	"gg.h"
    13  #include	"opt.h"
    14  #include	"../../runtime/funcdata.h"
    15  
    16  static void allocauto(Prog* p);
    17  static void emitptrargsmap(void);
    18  
    19  static Sym*
    20  makefuncdatasym(char *namefmt, int64 funcdatakind)
    21  {
    22  	Node nod;
    23  	Node *pnod;
    24  	Sym *sym;
    25  	static int32 nsym;
    26  
    27  	snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
    28  	sym = lookup(namebuf);
    29  	pnod = newname(sym);
    30  	pnod->class = PEXTERN;
    31  	nodconst(&nod, types[TINT32], funcdatakind);
    32  	gins(AFUNCDATA, &nod, pnod);
    33  	return sym;
    34  }
    35  
    36  // gvardef inserts a VARDEF for n into the instruction stream.
    37  // VARDEF is an annotation for the liveness analysis, marking a place
    38  // where a complete initialization (definition) of a variable begins.
    39  // Since the liveness analysis can see initialization of single-word
    40  // variables quite easy, gvardef is usually only called for multi-word
    41  // or 'fat' variables, those satisfying isfat(n->type).
    42  // However, gvardef is also called when a non-fat variable is initialized
    43  // via a block move; the only time this happens is when you have
    44  //	return f()
    45  // for a function with multiple return values exactly matching the return
    46  // types of the current function.
    47  //
    48  // A 'VARDEF x' annotation in the instruction stream tells the liveness
    49  // analysis to behave as though the variable x is being initialized at that
    50  // point in the instruction stream. The VARDEF must appear before the
    51  // actual (multi-instruction) initialization, and it must also appear after
    52  // any uses of the previous value, if any. For example, if compiling:
    53  //
    54  //	x = x[1:]
    55  //
    56  // it is important to generate code like:
    57  //
    58  //	base, len, cap = pieces of x[1:]
    59  //	VARDEF x
    60  //	x = {base, len, cap}
    61  //
    62  // If instead the generated code looked like:
    63  //
    64  //	VARDEF x
    65  //	base, len, cap = pieces of x[1:]
    66  //	x = {base, len, cap}
    67  //
    68  // then the liveness analysis would decide the previous value of x was
    69  // unnecessary even though it is about to be used by the x[1:] computation.
    70  // Similarly, if the generated code looked like:
    71  //
    72  //	base, len, cap = pieces of x[1:]
    73  //	x = {base, len, cap}
    74  //	VARDEF x
    75  //
    76  // then the liveness analysis will not preserve the new value of x, because
    77  // the VARDEF appears to have "overwritten" it.
    78  //
    79  // VARDEF is a bit of a kludge to work around the fact that the instruction
    80  // stream is working on single-word values but the liveness analysis
    81  // wants to work on individual variables, which might be multi-word
    82  // aggregates. It might make sense at some point to look into letting
    83  // the liveness analysis work on single-word values as well, although
    84  // there are complications around interface values, slices, and strings,
    85  // all of which cannot be treated as individual words.
    86  //
    87  // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
    88  // even if its address has been taken. That is, a VARKILL annotation asserts
    89  // that its argument is certainly dead, for use when the liveness analysis
    90  // would not otherwise be able to deduce that fact.
    91  
    92  static void
    93  gvardefx(Node *n, int as)
    94  {
    95  	if(n == N)
    96  		fatal("gvardef nil");
    97  	if(n->op != ONAME) {
    98  		yyerror("gvardef %#O; %N", n->op, n);
    99  		return;
   100  	}
   101  	switch(n->class) {
   102  	case PAUTO:
   103  	case PPARAM:
   104  	case PPARAMOUT:
   105  		gins(as, N, n);
   106  	}
   107  }
   108  
   109  void
   110  gvardef(Node *n)
   111  {
   112  	gvardefx(n, AVARDEF);
   113  }
   114  
   115  void
   116  gvarkill(Node *n)
   117  {
   118  	gvardefx(n, AVARKILL);
   119  }
   120  
   121  static void
   122  removevardef(Prog *firstp)
   123  {
   124  	Prog *p;
   125  
   126  	for(p = firstp; p != P; p = p->link) {
   127  		while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
   128  			p->link = p->link->link;
   129  		if(p->to.type == D_BRANCH)
   130  			while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
   131  				p->to.u.branch = p->to.u.branch->link;
   132  	}
   133  }
   134  
   135  static void
   136  gcsymdup(Sym *s)
   137  {
   138  	LSym *ls;
   139  	uint64 lo, hi;
   140  	
   141  	ls = linksym(s);
   142  	if(ls->nr > 0)
   143  		fatal("cannot rosymdup %s with relocations", ls->name);
   144  	MD5 d;
   145  	md5reset(&d);
   146  	md5write(&d, ls->p, ls->np);
   147  	lo = md5sum(&d, &hi);
   148  	ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
   149  	ls->dupok = 1;
   150  }
   151  
   152  void
   153  compile(Node *fn)
   154  {
   155  	Plist *pl;
   156  	Node nod1, *n;
   157  	Prog *ptxt, *p;
   158  	int32 lno;
   159  	Type *t;
   160  	Iter save;
   161  	vlong oldstksize;
   162  	NodeList *l;
   163  	Sym *gcargs;
   164  	Sym *gclocals;
   165  
   166  	if(newproc == N) {
   167  		newproc = sysfunc("newproc");
   168  		deferproc = sysfunc("deferproc");
   169  		deferreturn = sysfunc("deferreturn");
   170  		panicindex = sysfunc("panicindex");
   171  		panicslice = sysfunc("panicslice");
   172  		throwreturn = sysfunc("throwreturn");
   173  	}
   174  
   175  	lno = setlineno(fn);
   176  
   177  	curfn = fn;
   178  	dowidth(curfn->type);
   179  
   180  	if(fn->nbody == nil) {
   181  		if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
   182  			yyerror("missing function body", fn);
   183  			goto ret;
   184  		}
   185  		if(debug['A'])
   186  			goto ret;
   187  		emitptrargsmap();
   188  		goto ret;
   189  	}
   190  
   191  	saveerrors();
   192  
   193  	// set up domain for labels
   194  	clearlabels();
   195  
   196  	if(curfn->type->outnamed) {
   197  		// add clearing of the output parameters
   198  		t = structfirst(&save, getoutarg(curfn->type));
   199  		while(t != T) {
   200  			if(t->nname != N) {
   201  				n = nod(OAS, t->nname, N);
   202  				typecheck(&n, Etop);
   203  				curfn->nbody = concat(list1(n), curfn->nbody);
   204  			}
   205  			t = structnext(&save);
   206  		}
   207  	}
   208  	
   209  	order(curfn);
   210  	if(nerrors != 0)
   211  		goto ret;
   212  	
   213  	hasdefer = 0;
   214  	walk(curfn);
   215  	if(nerrors != 0)
   216  		goto ret;
   217  	if(flag_race)
   218  		racewalk(curfn);
   219  	if(nerrors != 0)
   220  		goto ret;
   221  
   222  	continpc = P;
   223  	breakpc = P;
   224  
   225  	pl = newplist();
   226  	pl->name = linksym(curfn->nname->sym);
   227  
   228  	setlineno(curfn);
   229  
   230  	nodconst(&nod1, types[TINT32], 0);
   231  	ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
   232  	if(fn->dupok)
   233  		ptxt->TEXTFLAG |= DUPOK;
   234  	if(fn->wrapper)
   235  		ptxt->TEXTFLAG |= WRAPPER;
   236  	if(fn->needctxt)
   237  		ptxt->TEXTFLAG |= NEEDCTXT;
   238  	if(fn->nosplit)
   239  		ptxt->TEXTFLAG |= NOSPLIT;
   240  
   241  	// Clumsy but important.
   242  	// See test/recover.go for test cases and src/reflect/value.go
   243  	// for the actual functions being considered.
   244  	if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
   245  		if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
   246  			ptxt->TEXTFLAG |= WRAPPER;
   247  	}	
   248  	
   249  	afunclit(&ptxt->from, curfn->nname);
   250  
   251  	ginit();
   252  
   253  	gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
   254  	gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
   255  
   256  	for(t=curfn->paramfld; t; t=t->down)
   257  		gtrack(tracksym(t->type));
   258  
   259  	for(l=fn->dcl; l; l=l->next) {
   260  		n = l->n;
   261  		if(n->op != ONAME) // might be OTYPE or OLITERAL
   262  			continue;
   263  		switch(n->class) {
   264  		case PAUTO:
   265  		case PPARAM:
   266  		case PPARAMOUT:
   267  			nodconst(&nod1, types[TUINTPTR], l->n->type->width);
   268  			p = gins(ATYPE, l->n, &nod1);
   269  			p->from.gotype = linksym(ngotype(l->n));
   270  			break;
   271  		}
   272  	}
   273  
   274  	genlist(curfn->enter);
   275  	genlist(curfn->nbody);
   276  	gclean();
   277  	checklabels();
   278  	if(nerrors != 0)
   279  		goto ret;
   280  	if(curfn->endlineno)
   281  		lineno = curfn->endlineno;
   282  
   283  	if(curfn->type->outtuple != 0)
   284  		ginscall(throwreturn, 0);
   285  
   286  	ginit();
   287  	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
   288  	cgen_ret(nil);
   289  	if(hasdefer) {
   290  		// deferreturn pretends to have one uintptr argument.
   291  		// Reserve space for it so stack scanner is happy.
   292  		if(maxarg < widthptr)
   293  			maxarg = widthptr;
   294  	}
   295  	gclean();
   296  	if(nerrors != 0)
   297  		goto ret;
   298  
   299  	pc->as = ARET;	// overwrite AEND
   300  	pc->lineno = lineno;
   301  
   302  	fixjmp(ptxt);
   303  	if(!debug['N'] || debug['R'] || debug['P']) {
   304  		regopt(ptxt);
   305  		nilopt(ptxt);
   306  	}
   307  	expandchecks(ptxt);
   308  
   309  	oldstksize = stksize;
   310  	allocauto(ptxt);
   311  
   312  	if(0)
   313  		print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
   314  	USED(oldstksize);
   315  
   316  	setlineno(curfn);
   317  	if((int64)stksize+maxarg > (1ULL<<31)) {
   318  		yyerror("stack frame too large (>2GB)");
   319  		goto ret;
   320  	}
   321  
   322  	// Emit garbage collection symbols.
   323  	liveness(curfn, ptxt, gcargs, gclocals);
   324  	gcsymdup(gcargs);
   325  	gcsymdup(gclocals);
   326  
   327  	defframe(ptxt);
   328  
   329  	if(0)
   330  		frame(0);
   331  
   332  	// Remove leftover instrumentation from the instruction stream.
   333  	removevardef(ptxt);
   334  ret:
   335  	lineno = lno;
   336  }
   337  
   338  static void
   339  emitptrargsmap(void)
   340  {
   341  	int nptr, nbitmap, j, off;
   342  	vlong xoffset;
   343  	Bvec *bv;
   344  	Sym *sym;
   345  	
   346  	sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
   347  
   348  	nptr = curfn->type->argwid / widthptr;
   349  	bv = bvalloc(nptr*2);
   350  	nbitmap = 1;
   351  	if(curfn->type->outtuple > 0)
   352  		nbitmap = 2;
   353  	off = duint32(sym, 0, nbitmap);
   354  	off = duint32(sym, off, bv->n);
   355  	if(curfn->type->thistuple > 0) {
   356  		xoffset = 0;
   357  		twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
   358  	}
   359  	if(curfn->type->intuple > 0) {
   360  		xoffset = 0;
   361  		twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
   362  	}
   363  	for(j = 0; j < bv->n; j += 32)
   364  		off = duint32(sym, off, bv->b[j/32]);
   365  	if(curfn->type->outtuple > 0) {
   366  		xoffset = 0;
   367  		twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
   368  		for(j = 0; j < bv->n; j += 32)
   369  			off = duint32(sym, off, bv->b[j/32]);
   370  	}
   371  	ggloblsym(sym, off, RODATA);
   372  	free(bv);
   373  }
   374  
   375  // Sort the list of stack variables. Autos after anything else,
   376  // within autos, unused after used, within used, things with
   377  // pointers first, zeroed things first, and then decreasing size.
   378  // Because autos are laid out in decreasing addresses
   379  // on the stack, pointers first, zeroed things first and decreasing size
   380  // really means, in memory, things with pointers needing zeroing at
   381  // the top of the stack and increasing in size.
   382  // Non-autos sort on offset.
   383  static int
   384  cmpstackvar(Node *a, Node *b)
   385  {
   386  	int ap, bp;
   387  
   388  	if (a->class != b->class)
   389  		return (a->class == PAUTO) ? +1 : -1;
   390  	if (a->class != PAUTO) {
   391  		if (a->xoffset < b->xoffset)
   392  			return -1;
   393  		if (a->xoffset > b->xoffset)
   394  			return +1;
   395  		return 0;
   396  	}
   397  	if ((a->used == 0) != (b->used == 0))
   398  		return b->used - a->used;
   399  
   400  	ap = haspointers(a->type);
   401  	bp = haspointers(b->type);
   402  	if(ap != bp)
   403  		return bp - ap;
   404  
   405  	ap = a->needzero;
   406  	bp = b->needzero;
   407  	if(ap != bp)
   408  		return bp - ap;
   409  
   410  	if(a->type->width < b->type->width)
   411  		return +1;
   412  	if(a->type->width > b->type->width)
   413  		return -1;
   414  
   415  	return strcmp(a->sym->name, b->sym->name);
   416  }
   417  
   418  // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
   419  static void
   420  allocauto(Prog* ptxt)
   421  {
   422  	NodeList *ll;
   423  	Node* n;
   424  	vlong w;
   425  
   426  	stksize = 0;
   427  	stkptrsize = 0;
   428  
   429  	if(curfn->dcl == nil)
   430  		return;
   431  
   432  	// Mark the PAUTO's unused.
   433  	for(ll=curfn->dcl; ll != nil; ll=ll->next)
   434  		if (ll->n->class == PAUTO)
   435  			ll->n->used = 0;
   436  
   437  	markautoused(ptxt);
   438  
   439  	listsort(&curfn->dcl, cmpstackvar);
   440  
   441  	// Unused autos are at the end, chop 'em off.
   442  	ll = curfn->dcl;
   443  	n = ll->n;
   444  	if (n->class == PAUTO && n->op == ONAME && !n->used) {
   445  		// No locals used at all
   446  		curfn->dcl = nil;
   447  		fixautoused(ptxt);
   448  		return;
   449  	}
   450  
   451  	for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
   452  		n = ll->next->n;
   453  		if (n->class == PAUTO && n->op == ONAME && !n->used) {
   454  			ll->next = nil;
   455  			curfn->dcl->end = ll;
   456  			break;
   457  		}
   458  	}
   459  
   460  	// Reassign stack offsets of the locals that are still there.
   461  	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
   462  		n = ll->n;
   463  		if (n->class != PAUTO || n->op != ONAME)
   464  			continue;
   465  
   466  		dowidth(n->type);
   467  		w = n->type->width;
   468  		if(w >= MAXWIDTH || w < 0)
   469  			fatal("bad width");
   470  		stksize += w;
   471  		stksize = rnd(stksize, n->type->align);
   472  		if(haspointers(n->type))
   473  			stkptrsize = stksize;
   474  		if(thechar == '5' || thechar == '9')
   475  			stksize = rnd(stksize, widthptr);
   476  		if(stksize >= (1ULL<<31)) {
   477  			setlineno(curfn);
   478  			yyerror("stack frame too large (>2GB)");
   479  		}
   480  		n->stkdelta = -stksize - n->xoffset;
   481  	}
   482  	stksize = rnd(stksize, widthreg);
   483  	stkptrsize = rnd(stkptrsize, widthreg);
   484  
   485  	fixautoused(ptxt);
   486  
   487  	// The debug information needs accurate offsets on the symbols.
   488  	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
   489  		if (ll->n->class != PAUTO || ll->n->op != ONAME)
   490  			continue;
   491  		ll->n->xoffset += ll->n->stkdelta;
   492  		ll->n->stkdelta = 0;
   493  	}
   494  }
   495  
   496  static void movelargefn(Node*);
   497  
   498  void
   499  movelarge(NodeList *l)
   500  {
   501  	for(; l; l=l->next)
   502  		if(l->n->op == ODCLFUNC)
   503  			movelargefn(l->n);
   504  }
   505  
   506  static void
   507  movelargefn(Node *fn)
   508  {
   509  	NodeList *l;
   510  	Node *n;
   511  
   512  	for(l=fn->dcl; l != nil; l=l->next) {
   513  		n = l->n;
   514  		if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
   515  			addrescapes(n);
   516  	}
   517  }
   518  
   519  void
   520  cgen_checknil(Node *n)
   521  {
   522  	Node reg;
   523  
   524  	if(disable_checknil)
   525  		return;
   526  	// Ideally we wouldn't see any integer types here, but we do.
   527  	if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
   528  		dump("checknil", n);
   529  		fatal("bad checknil");
   530  	}
   531  	if(((thechar == '5' || thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
   532  		regalloc(&reg, types[tptr], n);
   533  		cgen(n, &reg);
   534  		gins(ACHECKNIL, &reg, N);
   535  		regfree(&reg);
   536  		return;
   537  	}
   538  	gins(ACHECKNIL, n, N);
   539  }