github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/cc/pgen.c (about)

     1  // Inferno utils/6c/sgen.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  #include "gc.h"
    32  #include "../../runtime/funcdata.h"
    33  
    34  int
    35  hasdotdotdot(Type *t)
    36  {
    37  	for(t=t->down; t!=T; t=t->down)
    38  		if(t->etype == TDOT)
    39  			return 1;
    40  	return 0;
    41  }
    42  
    43  vlong
    44  argsize(int doret)
    45  {
    46  	Type *t;
    47  	int32 s;
    48  
    49  //print("t=%T\n", thisfn);
    50  	s = 0;
    51  	if(hasdotdotdot(thisfn))
    52  		s = align(s, thisfn->link, Aarg0, nil);
    53  	for(t=thisfn->down; t!=T; t=t->down) {
    54  		switch(t->etype) {
    55  		case TVOID:
    56  			break;
    57  		case TDOT:
    58  			if((textflag & NOSPLIT) == 0)
    59  				yyerror("function takes ... without textflag NOSPLIT");
    60  			return ArgsSizeUnknown;
    61  		default:
    62  			s = align(s, t, Aarg1, nil);
    63  			s = align(s, t, Aarg2, nil);
    64  			break;
    65  		}
    66  //print("	%d %T\n", s, t);
    67  	}
    68  	if(thechar == '6')
    69  		s = (s+7) & ~7;
    70  	else
    71  		s = (s+3) & ~3;
    72  	if(doret && thisfn->link->etype != TVOID) {
    73  		s = align(s, thisfn->link, Aarg1, nil);
    74  		s = align(s, thisfn->link, Aarg2, nil);
    75  		if(thechar == '6')
    76  			s = (s+7) & ~7;
    77  		else
    78  			s = (s+3) & ~3;
    79  	}
    80  	return s;
    81  }
    82  
    83  void
    84  codgen(Node *n, Node *nn)
    85  {
    86  	Prog *sp;
    87  	Node *n1, nod, nod1;
    88  
    89  	cursafe = 0;
    90  	curarg = 0;
    91  	maxargsafe = 0;
    92  
    93  	/*
    94  	 * isolate name
    95  	 */
    96  	for(n1 = nn;; n1 = n1->left) {
    97  		if(n1 == Z) {
    98  			diag(nn, "can't find function name");
    99  			return;
   100  		}
   101  		if(n1->op == ONAME)
   102  			break;
   103  	}
   104  	nearln = nn->lineno;
   105  
   106  	p = gtext(n1->sym, stkoff);
   107  	p->from.sym->cfunc = 1;
   108  	sp = p;
   109  
   110  	/*
   111  	 * isolate first argument
   112  	 */
   113  	if(REGARG >= 0) {
   114  		if(typesuv[thisfn->link->etype]) {
   115  			nod1 = *nodret->left;
   116  			nodreg(&nod, &nod1, REGARG);
   117  			gmove(&nod, &nod1);
   118  		} else
   119  		if(firstarg && typechlp[firstargtype->etype]) {
   120  			nod1 = *nodret->left;
   121  			nod1.sym = firstarg;
   122  			nod1.type = firstargtype;
   123  			nod1.xoffset = align(0, firstargtype, Aarg1, nil);
   124  			nod1.etype = firstargtype->etype;
   125  			nodreg(&nod, &nod1, REGARG);
   126  			gmove(&nod, &nod1);
   127  		}
   128  	}
   129  
   130  	canreach = 1;
   131  	warnreach = 1;
   132  	gen(n);
   133  	if(canreach && thisfn->link->etype != TVOID)
   134  		diag(Z, "no return at end of function: %s", n1->sym->name);
   135  	noretval(3);
   136  	gbranch(ORETURN);
   137  
   138  	if(!debug['N'] || debug['R'] || debug['P'])
   139  		regopt(sp);
   140  
   141  	if(thechar=='6' || thechar=='7')	/* [sic] */
   142  		maxargsafe = xround(maxargsafe, 8);
   143  	sp->to.offset += maxargsafe;
   144  }
   145  
   146  void
   147  supgen(Node *n)
   148  {
   149  	int owarn;
   150  	long spc;
   151  	Prog *sp;
   152  
   153  	if(n == Z)
   154  		return;
   155  	suppress++;
   156  	owarn = warnreach;
   157  	warnreach = 0;
   158  	spc = pc;
   159  	sp = lastp;
   160  	gen(n);
   161  	lastp = sp;
   162  	pc = spc;
   163  	sp->link = nil;
   164  	suppress--;
   165  	warnreach = owarn;
   166  }
   167  
   168  void
   169  gen(Node *n)
   170  {
   171  	Node *l, nod, nod1;
   172  	Prog *sp, *spc, *spb;
   173  	Case *cn;
   174  	long sbc, scc;
   175  	int snbreak, sncontin;
   176  	int f, o, oldreach;
   177  
   178  loop:
   179  	if(n == Z)
   180  		return;
   181  	nearln = n->lineno;
   182  	o = n->op;
   183  	if(debug['G'])
   184  		if(o != OLIST)
   185  			print("%L %O\n", nearln, o);
   186  
   187  	if(!canreach) {
   188  		switch(o) {
   189  		case OLABEL:
   190  		case OCASE:
   191  		case OLIST:
   192  		case OBREAK:
   193  		case OFOR:
   194  		case OWHILE:
   195  		case ODWHILE:
   196  			/* all handled specially - see switch body below */
   197  			break;
   198  		default:
   199  			if(warnreach) {
   200  				warn(n, "unreachable code %O", o);
   201  				warnreach = 0;
   202  			}
   203  		}
   204  	}
   205  
   206  	switch(o) {
   207  
   208  	default:
   209  		complex(n);
   210  		cgen(n, Z);
   211  		break;
   212  
   213  	case OLIST:
   214  		gen(n->left);
   215  
   216  	rloop:
   217  		n = n->right;
   218  		goto loop;
   219  
   220  	case ORETURN:
   221  		canreach = 0;
   222  		warnreach = !suppress;
   223  		complex(n);
   224  		if(n->type == T)
   225  			break;
   226  		l = n->left;
   227  		if(l == Z) {
   228  			noretval(3);
   229  			gbranch(ORETURN);
   230  			break;
   231  		}
   232  		if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
   233  			regret(&nod, n, thisfn, 2);
   234  			sugen(l, &nod, n->type->width);
   235  			noretval(3);
   236  			gbranch(ORETURN);
   237  			break;
   238  		}
   239  		if(typecmplx[n->type->etype]) {
   240  			sugen(l, nodret, n->type->width);
   241  			noretval(3);
   242  			gbranch(ORETURN);
   243  			break;
   244  		}
   245  		regret(&nod1, n, thisfn, 2);
   246  		nod = nod1;
   247  		if(nod.op != OREGISTER)
   248  			regalloc(&nod, n, Z);
   249  		cgen(l, &nod);
   250  		if(nod1.op != OREGISTER)
   251  			gmove(&nod, &nod1);
   252  		regfree(&nod);
   253  		if(typefd[n->type->etype])
   254  			noretval(1);
   255  		else
   256  			noretval(2);
   257  		gbranch(ORETURN);
   258  		break;
   259  
   260  	case OLABEL:
   261  		canreach = 1;
   262  		l = n->left;
   263  		if(l) {
   264  			l->pc = pc;
   265  			if(l->label)
   266  				patch(l->label, pc);
   267  		}
   268  		gbranch(OGOTO);	/* prevent self reference in reg */
   269  		patch(p, pc);
   270  		goto rloop;
   271  
   272  	case OGOTO:
   273  		canreach = 0;
   274  		warnreach = !suppress;
   275  		n = n->left;
   276  		if(n == Z)
   277  			return;
   278  		if(n->complex == 0) {
   279  			diag(Z, "label undefined: %s", n->sym->name);
   280  			return;
   281  		}
   282  		if(suppress)
   283  			return;
   284  		gbranch(OGOTO);
   285  		if(n->pc) {
   286  			patch(p, n->pc);
   287  			return;
   288  		}
   289  		if(n->label)
   290  			patch(n->label, pc-1);
   291  		n->label = p;
   292  		return;
   293  
   294  	case OCASE:
   295  		canreach = 1;
   296  		l = n->left;
   297  		if(cases == C)
   298  			diag(n, "case/default outside a switch");
   299  		if(l == Z) {
   300  			newcase();
   301  			cases->val = 0;
   302  			cases->def = 1;
   303  			cases->label = pc;
   304  			cases->isv = 0;
   305  			goto rloop;
   306  		}
   307  		complex(l);
   308  		if(l->type == T)
   309  			goto rloop;
   310  		if(l->op == OCONST)
   311  		if(typeword[l->type->etype] && l->type->etype != TIND) {
   312  			newcase();
   313  			cases->val = l->vconst;
   314  			cases->def = 0;
   315  			cases->label = pc;
   316  			cases->isv = typev[l->type->etype];
   317  			goto rloop;
   318  		}
   319  		diag(n, "case expression must be integer constant");
   320  		goto rloop;
   321  
   322  	case OSWITCH:
   323  		l = n->left;
   324  		complex(l);
   325  		if(l->type == T)
   326  			break;
   327  		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
   328  			diag(n, "switch expression must be integer");
   329  			break;
   330  		}
   331  
   332  		gbranch(OGOTO);		/* entry */
   333  		sp = p;
   334  
   335  		cn = cases;
   336  		cases = C;
   337  		newcase();
   338  
   339  		sbc = breakpc;
   340  		breakpc = pc;
   341  		snbreak = nbreak;
   342  		nbreak = 0;
   343  		gbranch(OGOTO);
   344  		spb = p;
   345  
   346  		gen(n->right);		/* body */
   347  		if(canreach){
   348  			gbranch(OGOTO);
   349  			patch(p, breakpc);
   350  			nbreak++;
   351  		}
   352  
   353  		patch(sp, pc);
   354  		doswit(l);
   355  		patch(spb, pc);
   356  
   357  		cases = cn;
   358  		breakpc = sbc;
   359  		canreach = nbreak!=0;
   360  		if(canreach == 0)
   361  			warnreach = !suppress;
   362  		nbreak = snbreak;
   363  		break;
   364  
   365  	case OWHILE:
   366  	case ODWHILE:
   367  		l = n->left;
   368  		gbranch(OGOTO);		/* entry */
   369  		sp = p;
   370  
   371  		scc = continpc;
   372  		continpc = pc;
   373  		gbranch(OGOTO);
   374  		spc = p;
   375  
   376  		sbc = breakpc;
   377  		breakpc = pc;
   378  		snbreak = nbreak;
   379  		nbreak = 0;
   380  		gbranch(OGOTO);
   381  		spb = p;
   382  
   383  		patch(spc, pc);
   384  		if(n->op == OWHILE)
   385  			patch(sp, pc);
   386  		bcomplex(l, Z);		/* test */
   387  		patch(p, breakpc);
   388  		if(l->op != OCONST || vconst(l) == 0)
   389  			nbreak++;
   390  
   391  		if(n->op == ODWHILE)
   392  			patch(sp, pc);
   393  		gen(n->right);		/* body */
   394  		gbranch(OGOTO);
   395  		patch(p, continpc);
   396  
   397  		patch(spb, pc);
   398  		continpc = scc;
   399  		breakpc = sbc;
   400  		canreach = nbreak!=0;
   401  		if(canreach == 0)
   402  			warnreach = !suppress;
   403  		nbreak = snbreak;
   404  		break;
   405  
   406  	case OFOR:
   407  		l = n->left;
   408  		if(!canreach && l->right->left && warnreach) {
   409  			warn(n, "unreachable code FOR");
   410  			warnreach = 0;
   411  		}
   412  		gen(l->right->left);	/* init */
   413  		gbranch(OGOTO);		/* entry */
   414  		sp = p;
   415  
   416  		/*
   417  		 * if there are no incoming labels in the
   418  		 * body and the top's not reachable, warn
   419  		 */
   420  		if(!canreach && warnreach && deadheads(n)) {
   421  			warn(n, "unreachable code %O", o);
   422  			warnreach = 0;
   423  		}
   424  
   425  		scc = continpc;
   426  		continpc = pc;
   427  		gbranch(OGOTO);
   428  		spc = p;
   429  
   430  		sbc = breakpc;
   431  		breakpc = pc;
   432  		snbreak = nbreak;
   433  		nbreak = 0;
   434  		sncontin = ncontin;
   435  		ncontin = 0;
   436  		gbranch(OGOTO);
   437  		spb = p;
   438  
   439  		patch(spc, pc);
   440  		gen(l->right->right);	/* inc */
   441  		patch(sp, pc);
   442  		if(l->left != Z) {	/* test */
   443  			bcomplex(l->left, Z);
   444  			patch(p, breakpc);
   445  			if(l->left->op != OCONST || vconst(l->left) == 0)
   446  				nbreak++;
   447  		}
   448  		canreach = 1;
   449  		gen(n->right);		/* body */
   450  		if(canreach){
   451  			gbranch(OGOTO);
   452  			patch(p, continpc);
   453  			ncontin++;
   454  		}
   455  		if(!ncontin && l->right->right && warnreach) {
   456  			warn(l->right->right, "unreachable FOR inc");
   457  			warnreach = 0;
   458  		}
   459  
   460  		patch(spb, pc);
   461  		continpc = scc;
   462  		breakpc = sbc;
   463  		canreach = nbreak!=0;
   464  		if(canreach == 0)
   465  			warnreach = !suppress;
   466  		nbreak = snbreak;
   467  		ncontin = sncontin;
   468  		break;
   469  
   470  	case OCONTINUE:
   471  		if(continpc < 0) {
   472  			diag(n, "continue not in a loop");
   473  			break;
   474  		}
   475  		gbranch(OGOTO);
   476  		patch(p, continpc);
   477  		ncontin++;
   478  		canreach = 0;
   479  		warnreach = !suppress;
   480  		break;
   481  
   482  	case OBREAK:
   483  		if(breakpc < 0) {
   484  			diag(n, "break not in a loop");
   485  			break;
   486  		}
   487  		/*
   488  		 * Don't complain about unreachable break statements.
   489  		 * There are breaks hidden in yacc's output and some people
   490  		 * write return; break; in their switch statements out of habit.
   491  		 * However, don't confuse the analysis by inserting an
   492  		 * unreachable reference to breakpc either.
   493  		 */
   494  		if(!canreach)
   495  			break;
   496  		gbranch(OGOTO);
   497  		patch(p, breakpc);
   498  		nbreak++;
   499  		canreach = 0;
   500  		warnreach = !suppress;
   501  		break;
   502  
   503  	case OIF:
   504  		l = n->left;
   505  		if(bcomplex(l, n->right)) {
   506  			if(typefd[l->type->etype])
   507  				f = !l->fconst;
   508  			else
   509  				f = !l->vconst;
   510  			if(debug['c'])
   511  				print("%L const if %s\n", nearln, f ? "false" : "true");
   512  			if(f) {
   513  				canreach = 1;
   514  				supgen(n->right->left);
   515  				oldreach = canreach;
   516  				canreach = 1;
   517  				gen(n->right->right);
   518  				/*
   519  				 * treat constant ifs as regular ifs for
   520  				 * reachability warnings.
   521  				 */
   522  				if(!canreach && oldreach && debug['w'] < 2)
   523  					warnreach = 0;
   524  			}
   525  			else {
   526  				canreach = 1;
   527  				gen(n->right->left);
   528  				oldreach = canreach;
   529  				canreach = 1;
   530  				supgen(n->right->right);
   531  				/*
   532  				 * treat constant ifs as regular ifs for
   533  				 * reachability warnings.
   534  				 */
   535  				if(!oldreach && canreach && debug['w'] < 2)
   536  					warnreach = 0;
   537  				canreach = oldreach;
   538  			}
   539  		}
   540  		else {
   541  			sp = p;
   542  			canreach = 1;
   543  			if(n->right->left != Z)
   544  				gen(n->right->left);
   545  			oldreach = canreach;
   546  			canreach = 1;
   547  			if(n->right->right != Z) {
   548  				gbranch(OGOTO);
   549  				patch(sp, pc);
   550  				sp = p;
   551  				gen(n->right->right);
   552  			}
   553  			patch(sp, pc);
   554  			canreach = canreach || oldreach;
   555  			if(canreach == 0)
   556  				warnreach = !suppress;
   557  		}
   558  		break;
   559  
   560  	case OSET:
   561  	case OUSED:
   562  	case OPREFETCH:
   563  		usedset(n->left, o);
   564  		break;
   565  	}
   566  }
   567  
   568  void
   569  usedset(Node *n, int o)
   570  {
   571  	if(n->op == OLIST) {
   572  		usedset(n->left, o);
   573  		usedset(n->right, o);
   574  		return;
   575  	}
   576  	complex(n);
   577  	if(o == OPREFETCH) {
   578  		gprefetch(n);
   579  		return;
   580  	}
   581  	switch(n->op) {
   582  	case OADDR:	/* volatile */
   583  		gins(ANOP, n, Z);
   584  		break;
   585  	case ONAME:
   586  		if(o == OSET)
   587  			gins(ANOP, Z, n);
   588  		else
   589  			gins(ANOP, n, Z);
   590  		break;
   591  	}
   592  }
   593  
   594  int
   595  bcomplex(Node *n, Node *c)
   596  {
   597  	Node *b, nod;
   598  
   599  	complex(n);
   600  	if(n->type != T)
   601  	if(tcompat(n, T, n->type, tnot))
   602  		n->type = T;
   603  	if(n->type == T) {
   604  		gbranch(OGOTO);
   605  		return 0;
   606  	}
   607  	if(c != Z && n->op == OCONST && deadheads(c))
   608  		return 1;
   609  	if(typev[n->type->etype] && machcap(Z)) {
   610  		b = &nod;
   611  		b->op = ONE;
   612  		b->left = n;
   613  		b->right = new(0, Z, Z);
   614  		*b->right = *nodconst(0);
   615  		b->right->type = n->type;
   616  		b->type = types[TLONG];
   617  		n = b;
   618  	}
   619  	bool64(n);
   620  	boolgen(n, 1, Z);
   621  	return 0;
   622  }