github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  
    33  vlong
    34  argsize(void)
    35  {
    36  	Type *t;
    37  	int32 s;
    38  
    39  //print("t=%T\n", thisfn);
    40  	s = align(0, thisfn->link, Aarg0, nil);
    41  	for(t=thisfn->down; t!=T; t=t->down) {
    42  		switch(t->etype) {
    43  		case TVOID:
    44  			break;
    45  		case TDOT:
    46  			yyerror("function takes ... without textflag NOSPLIT");
    47  			s += 64;
    48  			break;
    49  		default:
    50  			s = align(s, t, Aarg1, nil);
    51  			s = align(s, t, Aarg2, nil);
    52  			break;
    53  		}
    54  //print("	%d %T\n", s, t);
    55  	}
    56  	if(thechar == '6')
    57  		s = (s+7) & ~7;
    58  	else
    59  		s = (s+3) & ~3;
    60  	return s;
    61  }
    62  
    63  void
    64  codgen(Node *n, Node *nn)
    65  {
    66  	Prog *sp;
    67  	Node *n1, nod, nod1;
    68  
    69  	cursafe = 0;
    70  	curarg = 0;
    71  	maxargsafe = 0;
    72  
    73  	/*
    74  	 * isolate name
    75  	 */
    76  	for(n1 = nn;; n1 = n1->left) {
    77  		if(n1 == Z) {
    78  			diag(nn, "cant find function name");
    79  			return;
    80  		}
    81  		if(n1->op == ONAME)
    82  			break;
    83  	}
    84  	nearln = nn->lineno;
    85  
    86  	p = gtext(n1->sym, stkoff);
    87  	sp = p;
    88  
    89  	/*
    90  	 * isolate first argument
    91  	 */
    92  	if(REGARG >= 0) {
    93  		if(typesuv[thisfn->link->etype]) {
    94  			nod1 = *nodret->left;
    95  			nodreg(&nod, &nod1, REGARG);
    96  			gmove(&nod, &nod1);
    97  		} else
    98  		if(firstarg && typechlp[firstargtype->etype]) {
    99  			nod1 = *nodret->left;
   100  			nod1.sym = firstarg;
   101  			nod1.type = firstargtype;
   102  			nod1.xoffset = align(0, firstargtype, Aarg1, nil);
   103  			nod1.etype = firstargtype->etype;
   104  			nodreg(&nod, &nod1, REGARG);
   105  			gmove(&nod, &nod1);
   106  		}
   107  	}
   108  
   109  	retok = 0;
   110  
   111  	canreach = 1;
   112  	warnreach = 1;
   113  	gen(n);
   114  	if(canreach && thisfn->link->etype != TVOID)
   115  		diag(Z, "no return at end of function: %s", n1->sym->name);
   116  	noretval(3);
   117  	gbranch(ORETURN);
   118  
   119  	if(!debug['N'] || debug['R'] || debug['P'])
   120  		regopt(sp);
   121  
   122  	if(thechar=='6' || thechar=='7')	/* [sic] */
   123  		maxargsafe = xround(maxargsafe, 8);
   124  	sp->to.offset += maxargsafe;
   125  }
   126  
   127  void
   128  supgen(Node *n)
   129  {
   130  	int owarn;
   131  	long spc;
   132  	Prog *sp;
   133  
   134  	if(n == Z)
   135  		return;
   136  	suppress++;
   137  	owarn = warnreach;
   138  	warnreach = 0;
   139  	spc = pc;
   140  	sp = lastp;
   141  	gen(n);
   142  	lastp = sp;
   143  	pc = spc;
   144  	sp->link = nil;
   145  	suppress--;
   146  	warnreach = owarn;
   147  }
   148  
   149  void
   150  gen(Node *n)
   151  {
   152  	Node *l, nod;
   153  	Prog *sp, *spc, *spb;
   154  	Case *cn;
   155  	long sbc, scc;
   156  	int snbreak, sncontin;
   157  	int f, o, oldreach;
   158  
   159  loop:
   160  	if(n == Z)
   161  		return;
   162  	nearln = n->lineno;
   163  	o = n->op;
   164  	if(debug['G'])
   165  		if(o != OLIST)
   166  			print("%L %O\n", nearln, o);
   167  
   168  	if(!canreach) {
   169  		switch(o) {
   170  		case OLABEL:
   171  		case OCASE:
   172  		case OLIST:
   173  		case OBREAK:
   174  		case OFOR:
   175  		case OWHILE:
   176  		case ODWHILE:
   177  			/* all handled specially - see switch body below */
   178  			break;
   179  		default:
   180  			if(warnreach) {
   181  				warn(n, "unreachable code %O", o);
   182  				warnreach = 0;
   183  			}
   184  		}
   185  	}
   186  
   187  	switch(o) {
   188  
   189  	default:
   190  		complex(n);
   191  		cgen(n, Z);
   192  		break;
   193  
   194  	case OLIST:
   195  		gen(n->left);
   196  
   197  	rloop:
   198  		n = n->right;
   199  		goto loop;
   200  
   201  	case ORETURN:
   202  		canreach = 0;
   203  		warnreach = !suppress;
   204  		complex(n);
   205  		if(n->type == T)
   206  			break;
   207  		l = n->left;
   208  		if(l == Z) {
   209  			noretval(3);
   210  			gbranch(ORETURN);
   211  			break;
   212  		}
   213  		if(typecmplx[n->type->etype]) {
   214  			sugen(l, nodret, n->type->width);
   215  			noretval(3);
   216  			gbranch(ORETURN);
   217  			break;
   218  		}
   219  		regret(&nod, n);
   220  		cgen(l, &nod);
   221  		regfree(&nod);
   222  		if(typefd[n->type->etype])
   223  			noretval(1);
   224  		else
   225  			noretval(2);
   226  		gbranch(ORETURN);
   227  		break;
   228  
   229  	case OLABEL:
   230  		canreach = 1;
   231  		l = n->left;
   232  		if(l) {
   233  			l->pc = pc;
   234  			if(l->label)
   235  				patch(l->label, pc);
   236  		}
   237  		gbranch(OGOTO);	/* prevent self reference in reg */
   238  		patch(p, pc);
   239  		goto rloop;
   240  
   241  	case OGOTO:
   242  		canreach = 0;
   243  		warnreach = !suppress;
   244  		n = n->left;
   245  		if(n == Z)
   246  			return;
   247  		if(n->complex == 0) {
   248  			diag(Z, "label undefined: %s", n->sym->name);
   249  			return;
   250  		}
   251  		if(suppress)
   252  			return;
   253  		gbranch(OGOTO);
   254  		if(n->pc) {
   255  			patch(p, n->pc);
   256  			return;
   257  		}
   258  		if(n->label)
   259  			patch(n->label, pc-1);
   260  		n->label = p;
   261  		return;
   262  
   263  	case OCASE:
   264  		canreach = 1;
   265  		l = n->left;
   266  		if(cases == C)
   267  			diag(n, "case/default outside a switch");
   268  		if(l == Z) {
   269  			newcase();
   270  			cases->val = 0;
   271  			cases->def = 1;
   272  			cases->label = pc;
   273  			cases->isv = 0;
   274  			goto rloop;
   275  		}
   276  		complex(l);
   277  		if(l->type == T)
   278  			goto rloop;
   279  		if(l->op == OCONST)
   280  		if(typeword[l->type->etype] && l->type->etype != TIND) {
   281  			newcase();
   282  			cases->val = l->vconst;
   283  			cases->def = 0;
   284  			cases->label = pc;
   285  			cases->isv = typev[l->type->etype];
   286  			goto rloop;
   287  		}
   288  		diag(n, "case expression must be integer constant");
   289  		goto rloop;
   290  
   291  	case OSWITCH:
   292  		l = n->left;
   293  		complex(l);
   294  		if(l->type == T)
   295  			break;
   296  		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
   297  			diag(n, "switch expression must be integer");
   298  			break;
   299  		}
   300  
   301  		gbranch(OGOTO);		/* entry */
   302  		sp = p;
   303  
   304  		cn = cases;
   305  		cases = C;
   306  		newcase();
   307  
   308  		sbc = breakpc;
   309  		breakpc = pc;
   310  		snbreak = nbreak;
   311  		nbreak = 0;
   312  		gbranch(OGOTO);
   313  		spb = p;
   314  
   315  		gen(n->right);		/* body */
   316  		if(canreach){
   317  			gbranch(OGOTO);
   318  			patch(p, breakpc);
   319  			nbreak++;
   320  		}
   321  
   322  		patch(sp, pc);
   323  		doswit(l);
   324  		patch(spb, pc);
   325  
   326  		cases = cn;
   327  		breakpc = sbc;
   328  		canreach = nbreak!=0;
   329  		if(canreach == 0)
   330  			warnreach = !suppress;
   331  		nbreak = snbreak;
   332  		break;
   333  
   334  	case OWHILE:
   335  	case ODWHILE:
   336  		l = n->left;
   337  		gbranch(OGOTO);		/* entry */
   338  		sp = p;
   339  
   340  		scc = continpc;
   341  		continpc = pc;
   342  		gbranch(OGOTO);
   343  		spc = p;
   344  
   345  		sbc = breakpc;
   346  		breakpc = pc;
   347  		snbreak = nbreak;
   348  		nbreak = 0;
   349  		gbranch(OGOTO);
   350  		spb = p;
   351  
   352  		patch(spc, pc);
   353  		if(n->op == OWHILE)
   354  			patch(sp, pc);
   355  		bcomplex(l, Z);		/* test */
   356  		patch(p, breakpc);
   357  		if(l->op != OCONST || vconst(l) == 0)
   358  			nbreak++;
   359  
   360  		if(n->op == ODWHILE)
   361  			patch(sp, pc);
   362  		gen(n->right);		/* body */
   363  		gbranch(OGOTO);
   364  		patch(p, continpc);
   365  
   366  		patch(spb, pc);
   367  		continpc = scc;
   368  		breakpc = sbc;
   369  		canreach = nbreak!=0;
   370  		if(canreach == 0)
   371  			warnreach = !suppress;
   372  		nbreak = snbreak;
   373  		break;
   374  
   375  	case OFOR:
   376  		l = n->left;
   377  		if(!canreach && l->right->left && warnreach) {
   378  			warn(n, "unreachable code FOR");
   379  			warnreach = 0;
   380  		}
   381  		gen(l->right->left);	/* init */
   382  		gbranch(OGOTO);		/* entry */
   383  		sp = p;
   384  
   385  		/*
   386  		 * if there are no incoming labels in the
   387  		 * body and the top's not reachable, warn
   388  		 */
   389  		if(!canreach && warnreach && deadheads(n)) {
   390  			warn(n, "unreachable code %O", o);
   391  			warnreach = 0;
   392  		}
   393  
   394  		scc = continpc;
   395  		continpc = pc;
   396  		gbranch(OGOTO);
   397  		spc = p;
   398  
   399  		sbc = breakpc;
   400  		breakpc = pc;
   401  		snbreak = nbreak;
   402  		nbreak = 0;
   403  		sncontin = ncontin;
   404  		ncontin = 0;
   405  		gbranch(OGOTO);
   406  		spb = p;
   407  
   408  		patch(spc, pc);
   409  		gen(l->right->right);	/* inc */
   410  		patch(sp, pc);
   411  		if(l->left != Z) {	/* test */
   412  			bcomplex(l->left, Z);
   413  			patch(p, breakpc);
   414  			if(l->left->op != OCONST || vconst(l->left) == 0)
   415  				nbreak++;
   416  		}
   417  		canreach = 1;
   418  		gen(n->right);		/* body */
   419  		if(canreach){
   420  			gbranch(OGOTO);
   421  			patch(p, continpc);
   422  			ncontin++;
   423  		}
   424  		if(!ncontin && l->right->right && warnreach) {
   425  			warn(l->right->right, "unreachable FOR inc");
   426  			warnreach = 0;
   427  		}
   428  
   429  		patch(spb, pc);
   430  		continpc = scc;
   431  		breakpc = sbc;
   432  		canreach = nbreak!=0;
   433  		if(canreach == 0)
   434  			warnreach = !suppress;
   435  		nbreak = snbreak;
   436  		ncontin = sncontin;
   437  		break;
   438  
   439  	case OCONTINUE:
   440  		if(continpc < 0) {
   441  			diag(n, "continue not in a loop");
   442  			break;
   443  		}
   444  		gbranch(OGOTO);
   445  		patch(p, continpc);
   446  		ncontin++;
   447  		canreach = 0;
   448  		warnreach = !suppress;
   449  		break;
   450  
   451  	case OBREAK:
   452  		if(breakpc < 0) {
   453  			diag(n, "break not in a loop");
   454  			break;
   455  		}
   456  		/*
   457  		 * Don't complain about unreachable break statements.
   458  		 * There are breaks hidden in yacc's output and some people
   459  		 * write return; break; in their switch statements out of habit.
   460  		 * However, don't confuse the analysis by inserting an
   461  		 * unreachable reference to breakpc either.
   462  		 */
   463  		if(!canreach)
   464  			break;
   465  		gbranch(OGOTO);
   466  		patch(p, breakpc);
   467  		nbreak++;
   468  		canreach = 0;
   469  		warnreach = !suppress;
   470  		break;
   471  
   472  	case OIF:
   473  		l = n->left;
   474  		if(bcomplex(l, n->right)) {
   475  			if(typefd[l->type->etype])
   476  				f = !l->fconst;
   477  			else
   478  				f = !l->vconst;
   479  			if(debug['c'])
   480  				print("%L const if %s\n", nearln, f ? "false" : "true");
   481  			if(f) {
   482  				canreach = 1;
   483  				supgen(n->right->left);
   484  				oldreach = canreach;
   485  				canreach = 1;
   486  				gen(n->right->right);
   487  				/*
   488  				 * treat constant ifs as regular ifs for
   489  				 * reachability warnings.
   490  				 */
   491  				if(!canreach && oldreach && debug['w'] < 2)
   492  					warnreach = 0;
   493  			}
   494  			else {
   495  				canreach = 1;
   496  				gen(n->right->left);
   497  				oldreach = canreach;
   498  				canreach = 1;
   499  				supgen(n->right->right);
   500  				/*
   501  				 * treat constant ifs as regular ifs for
   502  				 * reachability warnings.
   503  				 */
   504  				if(!oldreach && canreach && debug['w'] < 2)
   505  					warnreach = 0;
   506  				canreach = oldreach;
   507  			}
   508  		}
   509  		else {
   510  			sp = p;
   511  			canreach = 1;
   512  			if(n->right->left != Z)
   513  				gen(n->right->left);
   514  			oldreach = canreach;
   515  			canreach = 1;
   516  			if(n->right->right != Z) {
   517  				gbranch(OGOTO);
   518  				patch(sp, pc);
   519  				sp = p;
   520  				gen(n->right->right);
   521  			}
   522  			patch(sp, pc);
   523  			canreach = canreach || oldreach;
   524  			if(canreach == 0)
   525  				warnreach = !suppress;
   526  		}
   527  		break;
   528  
   529  	case OSET:
   530  	case OUSED:
   531  	case OPREFETCH:
   532  		usedset(n->left, o);
   533  		break;
   534  	}
   535  }
   536  
   537  void
   538  usedset(Node *n, int o)
   539  {
   540  	if(n->op == OLIST) {
   541  		usedset(n->left, o);
   542  		usedset(n->right, o);
   543  		return;
   544  	}
   545  	complex(n);
   546  	if(o == OPREFETCH) {
   547  		gprefetch(n);
   548  		return;
   549  	}
   550  	switch(n->op) {
   551  	case OADDR:	/* volatile */
   552  		gins(ANOP, n, Z);
   553  		break;
   554  	case ONAME:
   555  		if(o == OSET)
   556  			gins(ANOP, Z, n);
   557  		else
   558  			gins(ANOP, n, Z);
   559  		break;
   560  	}
   561  }
   562  
   563  int
   564  bcomplex(Node *n, Node *c)
   565  {
   566  	Node *b, nod;
   567  
   568  	complex(n);
   569  	if(n->type != T)
   570  	if(tcompat(n, T, n->type, tnot))
   571  		n->type = T;
   572  	if(n->type == T) {
   573  		gbranch(OGOTO);
   574  		return 0;
   575  	}
   576  	if(c != Z && n->op == OCONST && deadheads(c))
   577  		return 1;
   578  	if(typev[n->type->etype] && machcap(Z)) {
   579  		b = &nod;
   580  		b->op = ONE;
   581  		b->left = n;
   582  		b->right = new(0, Z, Z);
   583  		*b->right = *nodconst(0);
   584  		b->right->type = n->type;
   585  		b->type = types[TLONG];
   586  		n = b;
   587  	}
   588  	bool64(n);
   589  	boolgen(n, 1, Z);
   590  	return 0;
   591  }