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