github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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	"gg.h"
    12  #include	"opt.h"
    13  #include	"../../pkg/runtime/funcdata.h"
    14  
    15  enum { BitsPerPointer = 2 };
    16  
    17  static void allocauto(Prog* p);
    18  static void dumpgcargs(Node*, Sym*);
    19  static Bvec* dumpgclocals(Node*, Sym*);
    20  
    21  void
    22  compile(Node *fn)
    23  {
    24  	Bvec *bv;
    25  	Plist *pl;
    26  	Node nod1, *n, *gcargsnod, *gclocalsnod;
    27  	Prog *ptxt, *p, *p1;
    28  	int32 lno;
    29  	Type *t;
    30  	Iter save;
    31  	vlong oldstksize;
    32  	NodeList *l;
    33  	Sym *gcargssym, *gclocalssym;
    34  	static int ngcargs, ngclocals;
    35  
    36  	if(newproc == N) {
    37  		newproc = sysfunc("newproc");
    38  		deferproc = sysfunc("deferproc");
    39  		deferreturn = sysfunc("deferreturn");
    40  		panicindex = sysfunc("panicindex");
    41  		panicslice = sysfunc("panicslice");
    42  		throwreturn = sysfunc("throwreturn");
    43  	}
    44  
    45  	lno = setlineno(fn);
    46  
    47  	if(fn->nbody == nil) {
    48  		if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0)
    49  			yyerror("missing function body", fn);
    50  		goto ret;
    51  	}
    52  
    53  	saveerrors();
    54  
    55  	// set up domain for labels
    56  	clearlabels();
    57  
    58  	curfn = fn;
    59  	dowidth(curfn->type);
    60  
    61  	if(curfn->type->outnamed) {
    62  		// add clearing of the output parameters
    63  		t = structfirst(&save, getoutarg(curfn->type));
    64  		while(t != T) {
    65  			if(t->nname != N) {
    66  				n = nod(OAS, t->nname, N);
    67  				typecheck(&n, Etop);
    68  				curfn->nbody = concat(list1(n), curfn->nbody);
    69  			}
    70  			t = structnext(&save);
    71  		}
    72  	}
    73  	
    74  	order(curfn);
    75  	if(nerrors != 0)
    76  		goto ret;
    77  	
    78  	hasdefer = 0;
    79  	walk(curfn);
    80  	if(nerrors != 0)
    81  		goto ret;
    82  	if(flag_race)
    83  		racewalk(curfn);
    84  	if(nerrors != 0)
    85  		goto ret;
    86  
    87  	continpc = P;
    88  	breakpc = P;
    89  
    90  	pl = newplist();
    91  	pl->name = curfn->nname;
    92  
    93  	setlineno(curfn);
    94  
    95  	nodconst(&nod1, types[TINT32], 0);
    96  	ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
    97  	if(fn->dupok)
    98  		ptxt->TEXTFLAG = DUPOK;
    99  	afunclit(&ptxt->from, curfn->nname);
   100  
   101  	ginit();
   102  
   103  	snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++);
   104  	gcargssym = lookup(namebuf);
   105  	gcargsnod = newname(gcargssym);
   106  	gcargsnod->class = PEXTERN;
   107  
   108  	nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs);
   109  	gins(AFUNCDATA, &nod1, gcargsnod);
   110  
   111  	snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++);
   112  	gclocalssym = lookup(namebuf);
   113  	gclocalsnod = newname(gclocalssym);
   114  	gclocalsnod->class = PEXTERN;
   115  
   116  	nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals);
   117  	gins(AFUNCDATA, &nod1, gclocalsnod);
   118  
   119  	for(t=curfn->paramfld; t; t=t->down)
   120  		gtrack(tracksym(t->type));
   121  
   122  	for(l=fn->dcl; l; l=l->next) {
   123  		n = l->n;
   124  		if(n->op != ONAME) // might be OTYPE or OLITERAL
   125  			continue;
   126  		switch(n->class) {
   127  		case PAUTO:
   128  		case PPARAM:
   129  		case PPARAMOUT:
   130  			nodconst(&nod1, types[TUINTPTR], l->n->type->width);
   131  			p = gins(ATYPE, l->n, &nod1);
   132  			p->from.gotype = ngotype(l->n);
   133  			break;
   134  		}
   135  	}
   136  
   137  	genlist(curfn->enter);
   138  
   139  	retpc = nil;
   140  	if(hasdefer || curfn->exit) {
   141  		p1 = gjmp(nil);
   142  		retpc = gjmp(nil);
   143  		patch(p1, pc);
   144  	}
   145  
   146  	genlist(curfn->nbody);
   147  	gclean();
   148  	checklabels();
   149  	if(nerrors != 0)
   150  		goto ret;
   151  	if(curfn->endlineno)
   152  		lineno = curfn->endlineno;
   153  
   154  	if(curfn->type->outtuple != 0)
   155  		ginscall(throwreturn, 0);
   156  
   157  	if(retpc)
   158  		patch(retpc, pc);
   159  	ginit();
   160  	if(hasdefer)
   161  		ginscall(deferreturn, 0);
   162  	if(curfn->exit)
   163  		genlist(curfn->exit);
   164  	gclean();
   165  	if(nerrors != 0)
   166  		goto ret;
   167  
   168  	pc->as = ARET;	// overwrite AEND
   169  	pc->lineno = lineno;
   170  
   171  	if(!debug['N'] || debug['R'] || debug['P']) {
   172  		regopt(ptxt);
   173  	}
   174  	expandchecks(ptxt);
   175  
   176  	oldstksize = stksize;
   177  	allocauto(ptxt);
   178  
   179  	if(0)
   180  		print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
   181  
   182  	setlineno(curfn);
   183  	if((int64)stksize+maxarg > (1ULL<<31)) {
   184  		yyerror("stack frame too large (>2GB)");
   185  		goto ret;
   186  	}
   187  
   188  	// Emit garbage collection symbols.
   189  	dumpgcargs(fn, gcargssym);
   190  	bv = dumpgclocals(curfn, gclocalssym);
   191  
   192  	defframe(ptxt, bv);
   193  	free(bv);
   194  
   195  	if(0)
   196  		frame(0);
   197  
   198  ret:
   199  	lineno = lno;
   200  }
   201  
   202  static void
   203  walktype1(Type *t, vlong *xoffset, Bvec *bv)
   204  {
   205  	vlong fieldoffset, i, o;
   206  	Type *t1;
   207  
   208  	if(t->align > 0 && (*xoffset % t->align) != 0)
   209  	 	fatal("walktype1: invalid initial alignment, %T", t);
   210  
   211  	switch(t->etype) {
   212  	case TINT8:
   213  	case TUINT8:
   214  	case TINT16:
   215  	case TUINT16:
   216  	case TINT32:
   217  	case TUINT32:
   218  	case TINT64:
   219  	case TUINT64:
   220  	case TINT:
   221  	case TUINT:
   222  	case TUINTPTR:
   223  	case TBOOL:
   224  	case TFLOAT32:
   225  	case TFLOAT64:
   226  	case TCOMPLEX64:
   227  	case TCOMPLEX128:
   228  		*xoffset += t->width;
   229  		break;
   230  
   231  	case TPTR32:
   232  	case TPTR64:
   233  	case TUNSAFEPTR:
   234  	case TFUNC:
   235  	case TCHAN:
   236  	case TMAP:
   237  		if(*xoffset % widthptr != 0)
   238  			fatal("walktype1: invalid alignment, %T", t);
   239  		bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
   240  		*xoffset += t->width;
   241  		break;
   242  
   243  	case TSTRING:
   244  		// struct { byte *str; intgo len; }
   245  		if(*xoffset % widthptr != 0)
   246  			fatal("walktype1: invalid alignment, %T", t);
   247  		bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
   248  		*xoffset += t->width;
   249  		break;
   250  
   251  	case TINTER:
   252  		// struct { Itab* tab;  union { void* ptr, uintptr val } data; }
   253  		// or, when isnilinter(t)==true:
   254  		// struct { Type* type; union { void* ptr, uintptr val } data; }
   255  		if(*xoffset % widthptr != 0)
   256  			fatal("walktype1: invalid alignment, %T", t);
   257  		bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1);
   258  		if(isnilinter(t))
   259  			bvset(bv, ((*xoffset / widthptr) * BitsPerPointer));
   260  		*xoffset += t->width;
   261  		break;
   262  
   263  	case TARRAY:
   264  		// The value of t->bound is -1 for slices types and >0 for
   265  		// for fixed array types.  All other values are invalid.
   266  		if(t->bound < -1)
   267  			fatal("walktype1: invalid bound, %T", t);
   268  		if(isslice(t)) {
   269  			// struct { byte* array; uintgo len; uintgo cap; }
   270  			if(*xoffset % widthptr != 0)
   271  				fatal("walktype1: invalid TARRAY alignment, %T", t);
   272  			bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
   273  			*xoffset += t->width;
   274  		} else if(!haspointers(t->type))
   275  				*xoffset += t->width;
   276  		else
   277  			for(i = 0; i < t->bound; ++i)
   278  				walktype1(t->type, xoffset, bv);
   279  		break;
   280  
   281  	case TSTRUCT:
   282  		o = 0;
   283  		for(t1 = t->type; t1 != T; t1 = t1->down) {
   284  			fieldoffset = t1->width;
   285  			*xoffset += fieldoffset - o;
   286  			walktype1(t1->type, xoffset, bv);
   287  			o = fieldoffset + t1->type->width;
   288  		}
   289  		*xoffset += t->width - o;
   290  		break;
   291  
   292  	default:
   293  		fatal("walktype1: unexpected type, %T", t);
   294  	}
   295  }
   296  
   297  static void
   298  walktype(Type *type, Bvec *bv)
   299  {
   300  	vlong xoffset;
   301  
   302  	// Start the walk at offset 0.  The correct offset will be
   303  	// filled in by the first type encountered during the walk.
   304  	xoffset = 0;
   305  	walktype1(type, &xoffset, bv);
   306  }
   307  
   308  // Compute a bit vector to describes the pointer containing locations
   309  // in the in and out argument list and dump the bitvector length and
   310  // data to the provided symbol.
   311  static void
   312  dumpgcargs(Node *fn, Sym *sym)
   313  {
   314  	Type *thistype, *inargtype, *outargtype;
   315  	Bvec *bv;
   316  	int32 i;
   317  	int off;
   318  
   319  	thistype = getthisx(fn->type);
   320  	inargtype = getinargx(fn->type);
   321  	outargtype = getoutargx(fn->type);
   322  	bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer);
   323  	if(thistype != nil)
   324  		walktype(thistype, bv);
   325  	if(inargtype != nil)
   326  		walktype(inargtype, bv);
   327  	if(outargtype != nil)
   328  		walktype(outargtype, bv);
   329  	off = duint32(sym, 0, bv->n);
   330  	for(i = 0; i < bv->n; i += 32)
   331  		off = duint32(sym, off, bv->b[i/32]);
   332  	free(bv);
   333  	ggloblsym(sym, off, 0, 1);
   334  }
   335  
   336  // Compute a bit vector to describes the pointer containing locations
   337  // in local variables and dumps the bitvector length and data out to
   338  // the provided symbol. Returns the vector for use and freeing by caller.
   339  static Bvec*
   340  dumpgclocals(Node* fn, Sym *sym)
   341  {
   342  	Bvec *bv;
   343  	NodeList *ll;
   344  	Node *node;
   345  	vlong xoffset;
   346  	int32 i;
   347  	int off;
   348  
   349  	bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer);
   350  	for(ll = fn->dcl; ll != nil; ll = ll->next) {
   351  		node = ll->n;
   352  		if(node->class == PAUTO && node->op == ONAME) {
   353  			if(haspointers(node->type)) {
   354  				xoffset = node->xoffset + stkptrsize;
   355  				walktype1(node->type, &xoffset, bv);
   356  			}
   357  		}
   358  	}
   359  	off = duint32(sym, 0, bv->n);
   360  	for(i = 0; i < bv->n; i += 32) {
   361  		off = duint32(sym, off, bv->b[i/32]);
   362  	}
   363  	ggloblsym(sym, off, 0, 1);
   364  	return bv;
   365  }
   366  
   367  // Sort the list of stack variables. Autos after anything else,
   368  // within autos, unused after used, within used, things with
   369  // pointers first, zeroed things first, and then decreasing size.
   370  // Because autos are laid out in decreasing addresses
   371  // on the stack, pointers first, zeroed things first and decreasing size
   372  // really means, in memory, things with pointers needing zeroing at
   373  // the top of the stack and increasing in size.
   374  // Non-autos sort on offset.
   375  static int
   376  cmpstackvar(Node *a, Node *b)
   377  {
   378  	int ap, bp;
   379  
   380  	if (a->class != b->class)
   381  		return (a->class == PAUTO) ? +1 : -1;
   382  	if (a->class != PAUTO) {
   383  		if (a->xoffset < b->xoffset)
   384  			return -1;
   385  		if (a->xoffset > b->xoffset)
   386  			return +1;
   387  		return 0;
   388  	}
   389  	if ((a->used == 0) != (b->used == 0))
   390  		return b->used - a->used;
   391  
   392  	ap = haspointers(a->type);
   393  	bp = haspointers(b->type);
   394  	if(ap != bp)
   395  		return bp - ap;
   396  
   397  	ap = a->needzero;
   398  	bp = b->needzero;
   399  	if(ap != bp)
   400  		return bp - ap;
   401  
   402  	if(a->type->width < b->type->width)
   403  		return +1;
   404  	if(a->type->width > b->type->width)
   405  		return -1;
   406  	return 0;
   407  }
   408  
   409  // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
   410  static void
   411  allocauto(Prog* ptxt)
   412  {
   413  	NodeList *ll;
   414  	Node* n;
   415  	vlong w;
   416  
   417  	stksize = 0;
   418  	stkptrsize = 0;
   419  	stkzerosize = 0;
   420  
   421  	if(curfn->dcl == nil)
   422  		return;
   423  
   424  	// Mark the PAUTO's unused.
   425  	for(ll=curfn->dcl; ll != nil; ll=ll->next)
   426  		if (ll->n->class == PAUTO)
   427  			ll->n->used = 0;
   428  
   429  	markautoused(ptxt);
   430  	
   431  	// TODO: Remove when liveness analysis sets needzero instead.
   432  	for(ll=curfn->dcl; ll != nil; ll=ll->next)
   433  		if (ll->n->class == PAUTO)
   434  			ll->n->needzero = 1; // ll->n->addrtaken;
   435  
   436  	listsort(&curfn->dcl, cmpstackvar);
   437  
   438  	// Unused autos are at the end, chop 'em off.
   439  	ll = curfn->dcl;
   440  	n = ll->n;
   441  	if (n->class == PAUTO && n->op == ONAME && !n->used) {
   442  		// No locals used at all
   443  		curfn->dcl = nil;
   444  		fixautoused(ptxt);
   445  		return;
   446  	}
   447  
   448  	for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
   449  		n = ll->next->n;
   450  		if (n->class == PAUTO && n->op == ONAME && !n->used) {
   451  			ll->next = nil;
   452  			curfn->dcl->end = ll;
   453  			break;
   454  		}
   455  	}
   456  
   457  	// Reassign stack offsets of the locals that are still there.
   458  	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
   459  		n = ll->n;
   460  		if (n->class != PAUTO || n->op != ONAME)
   461  			continue;
   462  
   463  		dowidth(n->type);
   464  		w = n->type->width;
   465  		if(w >= MAXWIDTH || w < 0)
   466  			fatal("bad width");
   467  		stksize += w;
   468  		stksize = rnd(stksize, n->type->align);
   469  		if(haspointers(n->type)) {
   470  			stkptrsize = stksize;
   471  			if(n->needzero)
   472  				stkzerosize = stksize;
   473  		}
   474  		if(thechar == '5')
   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, widthptr);
   483  	stkptrsize = rnd(stkptrsize, widthptr);
   484  	stkzerosize = rnd(stkzerosize, widthptr);
   485  
   486  	fixautoused(ptxt);
   487  
   488  	// The debug information needs accurate offsets on the symbols.
   489  	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
   490  		if (ll->n->class != PAUTO || ll->n->op != ONAME)
   491  			continue;
   492  		ll->n->xoffset += ll->n->stkdelta;
   493  		ll->n->stkdelta = 0;
   494  	}
   495  }
   496  
   497  static void movelargefn(Node*);
   498  
   499  void
   500  movelarge(NodeList *l)
   501  {
   502  	for(; l; l=l->next)
   503  		if(l->n->op == ODCLFUNC)
   504  			movelargefn(l->n);
   505  }
   506  
   507  static void
   508  movelargefn(Node *fn)
   509  {
   510  	NodeList *l;
   511  	Node *n;
   512  
   513  	for(l=fn->dcl; l != nil; l=l->next) {
   514  		n = l->n;
   515  		if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
   516  			addrescapes(n);
   517  	}
   518  }
   519  
   520  void
   521  cgen_checknil(Node *n)
   522  {
   523  	Node reg;
   524  
   525  	if(disable_checknil)
   526  		return;
   527  	while(n->op == ODOT || (n->op == OINDEX && isfixedarray(n->left->type->type))) // NOTE: not ODOTPTR
   528  		n = n->left;
   529  	if((thechar == '5' && n->op != OREGISTER) || !n->addable) {
   530  		regalloc(&reg, types[tptr], n);
   531  		cgen(n, &reg);
   532  		gins(ACHECKNIL, &reg, N);
   533  		regfree(&reg);
   534  		return;
   535  	}
   536  	gins(ACHECKNIL, n, N);
   537  }