ncgg has parsed the optional conditional expression (optexpr) of each
splitting coercion since commit 72b83cc in 1985; but for almost 33
years, ncg has ignored the expression in c2_expr.
Few tables had conditional coercions (I only found them in arm and
m68020), and no tables had conditional splitting coercions, so this
only becomes a problem now as I try to add a conditional splitting
coercion to powerpc.
		
	
			
		
			
				
	
	
		
			714 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			714 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #ifndef NORCSID
 | |
| static char rcsid[] = "$Id$";
 | |
| #endif
 | |
| 
 | |
| #include <assert.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h> /* strcmp */
 | |
| #include "param.h"
 | |
| #include "tables.h"
 | |
| #include "types.h"
 | |
| #include <cgg_cg.h>
 | |
| #include "data.h"
 | |
| #include "result.h"
 | |
| #include "extern.h"
 | |
| #ifdef REGVARS
 | |
| #include "regvar.h"
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  *
 | |
|  * Author: Hans van Staveren
 | |
|  */
 | |
| 
 | |
| static int from_stack(set_p);
 | |
| #ifdef TABLEDEBUG
 | |
| static void ruletrace(void);
 | |
| #endif
 | |
| 
 | |
| int match(token_p tp, set_p tep, int optexp) {
 | |
| 	int bitno;
 | |
| 	token_p ct;
 | |
| 	result_t result;
 | |
| 
 | |
| 	if (tp->t_token == -1) {        /* register frame */
 | |
| 		bitno = tp->t_att[0].ar;
 | |
| 		if (tep->set_val[bitno>>4]&(1<<(bitno&017)))
 | |
| 			if (tep->set_val[0]&1 || getrefcount(bitno, FALSE)<=1)
 | |
| 				goto oklabel;
 | |
| 		return(0);
 | |
| 	} else {                /* token frame */
 | |
| 		bitno = tp->t_token+NREGS;
 | |
| 		if ((tep->set_val[bitno>>4]&(1<<(bitno&017)))==0)
 | |
| 			return(0);
 | |
| 	}
 | |
|     oklabel:
 | |
| 	if (optexp==0)
 | |
| 		return(1);
 | |
| 	ct=curtoken;
 | |
| 	curtoken=tp;
 | |
| 	compute(&enodes[optexp], &result);
 | |
| 	curtoken=ct;
 | |
| 	return(result.e_v.e_con);
 | |
| }
 | |
| 
 | |
| void instance(int instno, token_p token) {
 | |
| 	inst_p inp;
 | |
| 	int i;
 | |
| 	token_p tp;
 | |
| #if MAXMEMBERS != 0
 | |
| 	struct reginfo *rp;
 | |
| #endif
 | |
| 	int regno;
 | |
| 	result_t result;
 | |
| 
 | |
| 	if (instno==0) {
 | |
| 		token->t_token = 0;
 | |
| 		for (i=TOKENSIZE-1;i>=0;i--)
 | |
| 			token->t_att[i].aw=0;
 | |
| 		return;
 | |
| 	}
 | |
| 	inp= &tokeninstances[instno];
 | |
| 	switch (inp->in_which) {
 | |
| 	default:
 | |
| 		assert(FALSE);
 | |
| 	case IN_COPY:
 | |
| 		if (inp->in_info[0] == 0)
 | |
| 			if (curtoken) tp = curtoken;
 | |
| 			else tp = &fakestack[stackheight-1];
 | |
| 		else	tp= &fakestack[stackheight-inp->in_info[0]];
 | |
| 		if (inp->in_info[1]==0) {
 | |
| 			*token = *tp;
 | |
| 		} else {
 | |
| 			token->t_token= -1;
 | |
| #if MAXMEMBERS!=0
 | |
| 			assert(tp->t_token == -1);
 | |
| 			rp = &machregs[tp->t_att[0].ar];
 | |
| 			token->t_att[0].ar=rp->r_members[inp->in_info[1]-1];
 | |
| #else
 | |
| 			assert(FALSE);
 | |
| #endif
 | |
| 		}
 | |
| 		return;
 | |
| 	case IN_MEMB:
 | |
| 		if (inp->in_info[0] == 0)
 | |
| 			if (curtoken) tp = curtoken;
 | |
| 			else tp = &fakestack[stackheight-1];
 | |
| 		else	tp= &fakestack[stackheight-inp->in_info[0]];
 | |
| 		assert(inp->in_info[1]!=0);
 | |
| 		assert(tp->t_token>0);
 | |
| 		token->t_token= -1;
 | |
| 		assert(tokens[tp->t_token].t_type[inp->in_info[1]-1] == EV_REG);
 | |
| 		token->t_att[0].ar=tp->t_att[inp->in_info[1]-1].ar;
 | |
| 		return;
 | |
| 	case IN_RIDENT:
 | |
| 		token->t_token= -1;
 | |
| 		token->t_att[0].ar= inp->in_info[0];
 | |
| 		return;
 | |
| 	case IN_ALLOC:
 | |
| 		token->t_token= -1;
 | |
| 		regno=allreg[inp->in_info[0]];
 | |
| #if MAXMEMBERS!=0
 | |
| 		if (inp->in_info[1])
 | |
| 			regno=machregs[regno].r_members[inp->in_info[1]-1];
 | |
| #endif
 | |
| 		token->t_att[0].ar = regno;
 | |
| 		return;
 | |
| #ifdef REGVARS
 | |
| 	case IN_S_DESCR:
 | |
| 	case IN_D_DESCR:
 | |
| 		compute(&enodes[inp->in_info[1]], &result);
 | |
| 		assert(result.e_typ==EV_INT);
 | |
| 		regno = PICK_REGVAR(result.e_v.e_con,
 | |
| 				    tokens[inp->in_info[0]].t_size);
 | |
| 		if (regno > 0) {
 | |
| 			token->t_token = -1;
 | |
| 			token->t_att[0].ar = regno;
 | |
| 			for (i=TOKENSIZE-1;i>0;i--)
 | |
| 				token->t_att[i].aw = 0;
 | |
| 			return;
 | |
| 		}
 | |
| 		/* fall through */
 | |
| #endif
 | |
| 	case IN_DESCR:
 | |
| 		token->t_token=inp->in_info[0];
 | |
| 		for (i=0;i<TOKENSIZE;i++)
 | |
| 			if (inp->in_info[i+1]==0) {
 | |
| 				assert(tokens[token->t_token].t_type[i]==0);
 | |
| 				token->t_att[i].aw=0;
 | |
| 			} else {
 | |
| 				compute(&enodes[inp->in_info[i+1]], &result);
 | |
| 				assert(tokens[token->t_token].t_type[i]==result.e_typ);
 | |
| 				if (result.e_typ==EV_INT)
 | |
| 					token->t_att[i].aw=result.e_v.e_con;
 | |
| 				else if (result.e_typ==EV_ADDR)
 | |
| 					token->t_att[i].aa= result.e_v.e_addr;
 | |
| 				else
 | |
| 					token->t_att[i].ar=result.e_v.e_reg;
 | |
| 			}
 | |
| 		return;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void cinstance(int instno, token_p token, token_p tp, int regno) {
 | |
| 	inst_p inp;
 | |
| 	int i;
 | |
| #if MAXMEMBERS != 0
 | |
| 	struct reginfo *rp;
 | |
| #endif
 | |
| 	result_t result;
 | |
| 	int sh; /* saved stackheight */
 | |
| 
 | |
| 	assert(instno!=0);
 | |
| 	inp= &tokeninstances[instno];
 | |
| 	switch (inp->in_which) {
 | |
| 	default:
 | |
| 		assert(FALSE);
 | |
| 	case IN_COPY:
 | |
| 		assert(inp->in_info[0] <= 1);
 | |
| 		if (inp->in_info[1]==0) {
 | |
| 			*token = *tp;
 | |
| 		} else {
 | |
| 			token->t_token= -1;
 | |
| #if MAXMEMBERS!=0
 | |
| 			assert(tp->t_token == -1);
 | |
| 			rp = &machregs[tp->t_att[0].ar];
 | |
| 			token->t_att[0].ar=rp->r_members[inp->in_info[1]-1];
 | |
| #else
 | |
| 			assert(FALSE);
 | |
| #endif
 | |
| 		}
 | |
| 		return;
 | |
| 	case IN_MEMB:
 | |
| 		assert(inp->in_info[0] <= 1);
 | |
| 		token->t_token= -1;
 | |
| 		assert(tp->t_token>0);
 | |
| 		assert(tokens[tp->t_token].t_type[inp->in_info[1]-1] == EV_REG);
 | |
| 		token->t_att[0].ar=tp->t_att[inp->in_info[1]-1].ar;
 | |
| 		return;
 | |
| 	case IN_RIDENT:
 | |
| 		token->t_token= -1;
 | |
| 		token->t_att[0].ar= inp->in_info[0];
 | |
| 		return;
 | |
| 	case IN_ALLOC:
 | |
| 		token->t_token= -1;
 | |
| 		assert(inp->in_info[0]==0);
 | |
| #if MAXMEMBERS!=0
 | |
| 		if (inp->in_info[1])
 | |
| 			regno=machregs[regno].r_members[inp->in_info[1]-1];
 | |
| #endif
 | |
| 		token->t_att[0].ar = regno;
 | |
| 		return;
 | |
| #ifdef REGVARS
 | |
| 	case IN_S_DESCR:
 | |
| 	case IN_D_DESCR:
 | |
| 		{	token_p ct = curtoken;
 | |
| 
 | |
| 			curtoken = tp;
 | |
| 			compute(&enodes[inp->in_info[1]], &result);
 | |
| 			curtoken = ct;
 | |
| 			assert(result.e_typ==EV_INT);
 | |
| 			regno = PICK_REGVAR(result.e_v.e_con,
 | |
| 					    tokens[inp->in_info[0]].t_size);
 | |
| 			if (regno > 0) {
 | |
| 				token->t_token = -1;
 | |
| 				token->t_att[0].ar = regno;
 | |
| 				for (i=TOKENSIZE-1;i>0;i--)
 | |
| 					token->t_att[i].aw = 0;
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		/* fall through */
 | |
| #endif
 | |
| 	case IN_DESCR:
 | |
| 		sh = stackheight;
 | |
| 		stackheight = tp - fakestack + 1;
 | |
| 		token->t_token=inp->in_info[0];
 | |
| 		for (i=0;i<TOKENSIZE;i++)
 | |
| 			if (inp->in_info[i+1]==0) {
 | |
| 				assert(tokens[token->t_token].t_type[i]==0);
 | |
| 				token->t_att[i].aw=0;
 | |
| 			} else {
 | |
| 				token_p ct = curtoken;
 | |
| 
 | |
| 				curtoken = tp;
 | |
| 				compute(&enodes[inp->in_info[i+1]], &result);
 | |
| 				curtoken = ct;
 | |
| 				assert(tokens[token->t_token].t_type[i]==result.e_typ);
 | |
| 				if (result.e_typ==EV_INT)
 | |
| 					token->t_att[i].aw=result.e_v.e_con;
 | |
| 				else if (result.e_typ==EV_ADDR)
 | |
| 					token->t_att[i].aa= result.e_v.e_addr;
 | |
| 				else
 | |
| 					token->t_att[i].ar=result.e_v.e_reg;
 | |
| 			}
 | |
| 		stackheight = sh;
 | |
| 		return;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int eqtoken(token_p tp1, token_p tp2) {
 | |
| 	int i;
 | |
| 	tkdef_p tdp;
 | |
| 
 | |
| 	if (tp1->t_token!=tp2->t_token)
 | |
| 		return(0);
 | |
| 	if (tp1->t_token==0)
 | |
| 		return(1);
 | |
| 	if (tp1->t_token==-1) {
 | |
| 		if (tp1->t_att[0].ar!=tp2->t_att[0].ar)
 | |
| 			return(0);
 | |
| 		return(1);
 | |
| 	}
 | |
| 	tdp = &tokens[tp1->t_token];
 | |
| 	for (i=0;i<TOKENSIZE;i++)
 | |
| 		switch(tdp->t_type[i]) {
 | |
| 		default:
 | |
| 			return(1);
 | |
| 		case EV_INT:
 | |
| 			if (tp1->t_att[i].aw != tp2->t_att[i].aw)
 | |
| 				return(0);
 | |
| 			break;
 | |
| 		case EV_REG:
 | |
| 			if (tp1->t_att[i].ar != tp2->t_att[i].ar)
 | |
| 				return(0);
 | |
| 			break;
 | |
| 		case EV_ADDR:
 | |
| 			if (strcmp(tp1->t_att[i].aa.ea_str, tp2->t_att[i].aa.ea_str))
 | |
| 				return(0);
 | |
| 			if (tp1->t_att[i].aa.ea_off!=tp2->t_att[i].aa.ea_off)
 | |
| 				return(0);
 | |
| 			break;
 | |
| 		}
 | |
| 	return(1);
 | |
| }
 | |
| 
 | |
| int distance(int cindex) {
 | |
| 	char *bp;
 | |
| 	int i;
 | |
| 	token_p tp;
 | |
| 	int tokexp,tpl;
 | |
| 	int expsize,toksize,exact;
 | |
| 	int xsekt=0;
 | |
| 	int fromstackneeded=0;
 | |
| 
 | |
| 	bp = &coderules[cindex];
 | |
| #ifndef NDEBUG
 | |
| 	if (*bp==DO_DLINE) {
 | |
| 		++bp;
 | |
| 		getint(i,bp);
 | |
| 	}
 | |
| #endif
 | |
| 	switch ( (*bp)&037 ) {
 | |
| 	default:
 | |
| 		return(stackheight==0 ? 0 : 100);
 | |
| 	case DO_MATCH:
 | |
| 		break;
 | |
| 	case DO_XXMATCH:
 | |
| 		xsekt++;
 | |
| 	case DO_XMATCH:
 | |
| 		xsekt++;
 | |
| 		break;
 | |
| 	}
 | |
| 	tpl= ((*bp++)>>5)&07;
 | |
| 	if (stackheight < tpl) {
 | |
| 		if (xsekt)
 | |
| 			return(MAXINT);
 | |
| 		fromstackneeded = tpl - stackheight;
 | |
| 		tpl = stackheight;
 | |
| 	} else
 | |
| 		if (stackheight != tpl && xsekt==2)
 | |
| 			return(MAXINT);
 | |
| 	exact=0;
 | |
| 	tp= &fakestack[stackheight-1];
 | |
| 	for (i=0;i<tpl;i++,tp--) {
 | |
| 		getint(tokexp,bp);
 | |
| 		if (!match(tp, &machsets[tokexp], 0)) {
 | |
| 			if (xsekt)
 | |
| 				return(MAXINT);
 | |
| 			expsize = ssize(tokexp);
 | |
| 			toksize = tsize(tp);
 | |
| 			if (expsize>toksize)
 | |
| 				return(100);
 | |
| 			if (expsize<toksize)
 | |
| 				return(99-i);
 | |
| 
 | |
| 			/* Now we have a match in size, but it is not exact.
 | |
| 			   Therefore, make sure that we can at least
 | |
| 			   create it from the stack!
 | |
| 			*/
 | |
| 			if (! from_stack(&machsets[tokexp])) {
 | |
| 				return MAXINT;
 | |
| 			}
 | |
| 		} else
 | |
| 			exact++;
 | |
| 	}
 | |
| 	for (;i<tpl+fromstackneeded;i++) {
 | |
| 		/*	Make sure that any pattern we pick can be
 | |
| 			made from the stack
 | |
| 		*/
 | |
| 		getint(tokexp,bp);
 | |
| 		if (! from_stack(&machsets[tokexp])) {
 | |
| 			return(MAXINT);
 | |
| 		}
 | |
| 	}
 | |
| 	if (exact==tpl && ! fromstackneeded) {
 | |
| 		if (xsekt)
 | |
| 			return(0);
 | |
| 		return(10-exact);
 | |
| 	}
 | |
| 	return(20-2*exact+fromstackneeded);
 | |
| }
 | |
| 
 | |
| extern set_t unstackset; /* tables.c */
 | |
| 
 | |
| static int from_stack(set_p s1) {
 | |
| 	set_p s2 = &unstackset;
 | |
| 	int i;
 | |
| 	for (i = 0; i < SETSIZE; i++) {
 | |
| 		if ((s1->set_val[i] & s2->set_val[i]) != 0) return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| unsigned costcalc(cost_t cost) {
 | |
| 	extern unsigned cc1,cc2,cc3,cc4; /* tables.c */
 | |
| 
 | |
| 	return(cost.ct_space*cc1/cc2 + cost.ct_time*cc3/cc4);
 | |
| }
 | |
| 
 | |
| int ssize(int tokexpno) {
 | |
| 
 | |
| 	return(machsets[tokexpno].set_size);
 | |
| }
 | |
| 
 | |
| int tsize(token_p tp) {
 | |
| 
 | |
| 	if (tp->t_token==-1)
 | |
| 		return(machregs[tp->t_att[0].ar].r_size);
 | |
| 	return(tokens[tp->t_token].t_size);
 | |
| }
 | |
| 
 | |
| #ifdef MAXSPLIT
 | |
| static int instsize(int tinstno, token_p tp) {
 | |
| 	inst_p inp;
 | |
| 	struct reginfo *rp;
 | |
| 
 | |
| 	inp = &tokeninstances[tinstno];
 | |
| 	switch (inp->in_which) {
 | |
| 	default:
 | |
| 		assert(FALSE);
 | |
| 	case IN_COPY:
 | |
| 		assert(inp->in_info[0]<=1);
 | |
| #if MAXMEMBERS!=0
 | |
| 		if (inp->in_info[1]==0)
 | |
| #endif
 | |
| 			return(tsize(tp));
 | |
| #if MAXMEMBERS!=0
 | |
| 		else {
 | |
| 			assert(tp->t_token == -1);
 | |
| 			rp = &machregs[tp->t_att[0].ar];
 | |
| 			return(machregs[rp->r_members[inp->in_info[1]-1]].r_size);
 | |
| 		}
 | |
| #endif
 | |
| 	case IN_RIDENT:
 | |
| 		return(machregs[inp->in_info[0]].r_size);
 | |
| 	case IN_ALLOC:
 | |
| 		assert(FALSE);  /* cannot occur in splitting coercion */
 | |
| 	case IN_DESCR:
 | |
| 	case IN_S_DESCR:
 | |
| 	case IN_D_DESCR:
 | |
| 		return(tokens[inp->in_info[0]].t_size);
 | |
| 	}
 | |
| }
 | |
| #endif /* MAXSPLIT */
 | |
| 
 | |
| void tref(token_p tp, int amount) {
 | |
| 	int i;
 | |
| 	byte *tdpb;
 | |
| 
 | |
| 	if (tp->t_token==-1)
 | |
| 		chrefcount(tp->t_att[0].ar,amount,FALSE);
 | |
| 	else {
 | |
| 		tdpb= &tokens[tp->t_token].t_type[0];
 | |
| 		for(i=0;i<TOKENSIZE;i++)
 | |
| 			if (*tdpb++==EV_REG)
 | |
| 				chrefcount(tp->t_att[i].ar,amount,FALSE);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #define MAXSAVE 10
 | |
| /* A few routines to save the top of the current stack,
 | |
|    restore it and check whether a certain register is present in the
 | |
|    saved stack
 | |
| */
 | |
| static token_t	aside[MAXSAVE] ;
 | |
| static int	aside_length = -1 ;
 | |
| 
 | |
| static void save_stack(token_p tp) {
 | |
| 	int i ;
 | |
| 	token_p tmp = &fakestack[stackheight - 1];
 | |
| 
 | |
| 	/*aside_length = &fakestack[stackheight-1] -tp;
 | |
| 	  This did not compile on Xenix V3.2: CODE GENERATION ERROR!
 | |
| 	*/
 | |
| 	aside_length = tmp - tp;
 | |
| 	assert(aside_length<=MAXSAVE);
 | |
| #ifndef NDEBUG
 | |
| 	if (aside_length!=0 && Debug>1)
 | |
| 		fprintf(stderr,"Saving %d items from fakestack\n",aside_length);
 | |
| #endif
 | |
| 	for (i=1;i<=aside_length;i++)
 | |
| 		aside[i-1] = tp[i];
 | |
| 	stackheight -= aside_length;
 | |
| }
 | |
| 
 | |
| int in_stack(int reg) {
 | |
| 	token_p tp ;
 | |
| 	int i ;
 | |
| 	tkdef_p tdp ;
 | |
| 
 | |
| 	for ( i=0, tp=aside ; i<aside_length ; i++, tp++ )
 | |
| 		if (tp->t_token==-1) {
 | |
| 			if(tp->t_att[0].ar==reg)
 | |
| 				goto gotone ;
 | |
| 		} else {
 | |
| 			tdp = &tokens[tp->t_token];
 | |
| 			for(i=0;i<TOKENSIZE;i++)
 | |
| 				if (tdp->t_type[i]==EV_REG &&
 | |
| 				    tp->t_att[i].ar==reg)
 | |
| 					goto gotone ;
 | |
| 		}
 | |
| 	return 0 ;
 | |
| gotone:
 | |
| #ifndef NDEBUG
 | |
| 	if ( Debug>2 )
 | |
| 		fprintf(stderr,"Register %d present on non-visible stack\n",
 | |
| 			reg ) ;
 | |
| #endif
 | |
| 	return 1 ;
 | |
| }
 | |
| 
 | |
| static void rest_stack(void) {
 | |
| 	int i ;
 | |
| 
 | |
| 	assert(aside_length!= -1); 
 | |
| #ifndef NDEBUG
 | |
| 	if (aside_length!=0 && Debug>1)
 | |
| 		fprintf(stderr,"Restoring %d items to fakestack(%d)\n",
 | |
| 			aside_length,stackheight);
 | |
| #endif
 | |
| 	for (i=0;i<aside_length;i++)
 | |
| 		fakestack[stackheight++] = aside[i];
 | |
| 	aside_length= -1 ;
 | |
| }
 | |
| 
 | |
| #ifdef MAXSPLIT
 | |
| int split(token_p tp, int *ip, int ply, int toplevel) {
 | |
| 	c2_p cp;
 | |
| 	token_t savestack[MAXSAVE];
 | |
| 	int ok;
 | |
| 	int i;
 | |
| 	int diff;
 | |
| 	token_p stp;
 | |
| 	int tpl;
 | |
| 
 | |
| 	for (cp=c2coercs;cp->c2_texpno>=0; cp++) {
 | |
| 		if (!match(tp,&machsets[cp->c2_texpno],cp->c2_expr))
 | |
| 			continue;
 | |
| 		ok=1;
 | |
| 		for (i=0; ok && i<cp->c2_nsplit;i++) {
 | |
| 			if (ip[i]==0)
 | |
| 				goto found;
 | |
| 			if (instsize(cp->c2_repl[i],tp) != ssize(ip[i]))
 | |
| 				ok=0;
 | |
| 		}
 | |
| 		goto found;
 | |
| 	}
 | |
| 	return(0);
 | |
| found:
 | |
| 	assert(stackheight+cp->c2_nsplit-1<MAXFSTACK);
 | |
| 	save_stack(tp);
 | |
| 	tpl = tokpatlen;
 | |
| 	tokpatlen = 1;
 | |
| 	codegen(&coderules[cp->c2_codep],ply,toplevel,MAXINT,0);
 | |
| 	tokpatlen = tpl;
 | |
| 	rest_stack();
 | |
| 	return(cp->c2_nsplit);
 | |
| }
 | |
| #endif /* MAXSPLIT */
 | |
| 
 | |
| unsigned docoerc(token_p tp, c3_p cp, int ply, int toplevel, int forced) {
 | |
| 	unsigned cost;
 | |
| 	int tpl;        /* saved tokpatlen */
 | |
| 
 | |
| 	save_stack(tp) ;
 | |
| 	tpl = tokpatlen;
 | |
| 	tokpatlen = 1;
 | |
| 	cost = codegen(&coderules[cp->c3_codep],ply,toplevel,MAXINT,forced);
 | |
| 	tokpatlen = tpl;
 | |
| 	rest_stack() ;
 | |
| 	nallreg = 0;
 | |
| 	return(cost);
 | |
| }
 | |
| 
 | |
| unsigned stackupto(token_p limit, int ply, int toplevel) {
 | |
| 	token_t savestack[MAXFSTACK];
 | |
| 	token_p stp;
 | |
| 	int i,diff;
 | |
| 	int tpl;        /* saved tokpatlen */
 | |
| 	int nareg;	/* saved nareg */
 | |
| 	int areg[MAXALLREG];
 | |
| 	c1_p cp;
 | |
| 	token_p tp;
 | |
| 	unsigned totalcost=0;
 | |
| 	struct reginfo *rp,**rpp;
 | |
| 
 | |
| 	for (tp=fakestack;tp<=limit;limit--) {
 | |
| 		for (cp=c1coercs;cp->c1_texpno>=0; cp++) {
 | |
| 			if (match(tp,&machsets[cp->c1_texpno],cp->c1_expr)) {
 | |
| 				if (cp->c1_prop>=0) {
 | |
| 					for (rpp=reglist[cp->c1_prop];
 | |
| 					       (rp = *rpp)!=0 &&
 | |
| 					       getrefcount((int)(rp-machregs), TRUE)!=0;
 | |
| 						  rpp++)
 | |
| 						;
 | |
| 					if (rp==0)
 | |
| 						continue;
 | |
| 						/* look for other possibility */
 | |
| 				}
 | |
| 				stp = &fakestack[stackheight-1];
 | |
| 				diff = stp -tp;
 | |
| 				assert(diff<=MAXFSTACK);
 | |
| 				for (i=1;i<=diff;i++)
 | |
| 					savestack[i-1] = tp[i];
 | |
| 				stackheight -= diff;
 | |
| 				tpl = tokpatlen;
 | |
| 				tokpatlen = 1;
 | |
| 				nareg = nallreg;
 | |
| 				for (i=0;i<nareg;i++)
 | |
| 					areg[i] = allreg[i];
 | |
| 				if (cp->c1_prop>=0) {
 | |
| 					nallreg=1; allreg[0] = rp-machregs;
 | |
| 					chrefcount(allreg[0],1,FALSE);
 | |
| 				} else 
 | |
| 					nallreg=0;
 | |
| 				totalcost+= codegen(&coderules[cp->c1_codep],ply,toplevel,MAXINT,0);
 | |
| 				tokpatlen = tpl;
 | |
| 				for (i=0;i<diff;i++) {
 | |
| 					fakestack[stackheight] = savestack[i];
 | |
| 					stackheight++;
 | |
| 					/* not cobmined in one statement;
 | |
| 					   this poor Xenix C compiler sometimes
 | |
| 					   gets failed assertions when you do
 | |
| 					   that!
 | |
| 					*/
 | |
| 				}
 | |
| 				nallreg=nareg;
 | |
| 				for (i=0;i<nareg;i++)
 | |
| 					allreg[i] = areg[i];
 | |
| 				goto contin;
 | |
| 			}
 | |
| 		}
 | |
| 		assert(FALSE);
 | |
| 	contin: ;
 | |
| 	}
 | |
| 	return(totalcost);
 | |
| }
 | |
| 
 | |
| c3_p findcoerc(token_p tp, set_p tep) {
 | |
| 	c3_p cp;
 | |
| 	token_t rtoken;
 | |
| 	int i;
 | |
| 	struct reginfo **rpp;
 | |
| 
 | |
| 	for (cp=c3coercs;cp->c3_texpno>=0; cp++) {
 | |
| 		if (tp!=(token_p) 0) {
 | |
| 			if (cp->c3_texpno==0)
 | |
| 				continue;
 | |
| 			if (!match(tp,&machsets[cp->c3_texpno],cp->c3_expr))
 | |
| 				continue;
 | |
| 		} else {
 | |
| 			if (cp->c3_texpno!=0)
 | |
| 				continue;
 | |
| 		}
 | |
| 		if (cp->c3_prop<0) {   /* no reg needed */
 | |
| 			cinstance(cp->c3_repl,&rtoken,tp,0);
 | |
| 			if (match(&rtoken,tep,0))
 | |
| 				return(cp);
 | |
| 		} else {
 | |
| 			curreglist = (rl_p) myalloc(sizeof (rl_t));
 | |
| 			curreglist->rl_n = 0;
 | |
| 			for (rpp=reglist[cp->c3_prop];*rpp;rpp++) {
 | |
| 				i = *rpp - machregs;
 | |
| 				cinstance(cp->c3_repl,&rtoken,tp,i);
 | |
| 				if (match(&rtoken,tep,0))
 | |
| 					curreglist->rl_list[curreglist->rl_n++] = i;
 | |
| 			}
 | |
| 			if (curreglist->rl_n != 0)
 | |
| 				return(cp);
 | |
| 			myfree((string)curreglist);
 | |
| 		}
 | |
| 	}
 | |
| 	return(0);      /* nothing found */
 | |
| }
 | |
| 
 | |
| void itokcost(void) {
 | |
| 	tkdef_p tdp;
 | |
| 
 | |
| 	for(tdp=tokens+1;tdp->t_size!=0;tdp++)
 | |
| 		tdp->t_cost.ct_space = costcalc(tdp->t_cost);
 | |
| }
 | |
| 
 | |
| void error(const char *s, ...) {
 | |
| 	va_list ap;
 | |
| 
 | |
| 	va_start(ap,s);
 | |
| 	fprintf(stderr,"Error: ");
 | |
| 	vfprintf(stderr,s,ap);
 | |
| 	fprintf(stderr,"\n");
 | |
| #ifdef TABLEDEBUG
 | |
| 	ruletrace();
 | |
| #endif
 | |
| 	out_finish();
 | |
| 	exit(-1);
 | |
| }
 | |
| 
 | |
| void fatal(const char *s, ...) {
 | |
| 	va_list ap;
 | |
| 
 | |
| 	va_start(ap,s);
 | |
| 	fprintf(stderr,"Fatal: ");
 | |
| 	vfprintf(stderr,s,ap);
 | |
| 	fprintf(stderr,"\n");
 | |
| #ifdef TABLEDEBUG
 | |
| 	ruletrace();
 | |
| #endif
 | |
| 	out_finish();
 | |
| 	abort();
 | |
| 	exit(-1);
 | |
| }
 | |
| 
 | |
| #ifdef TABLEDEBUG
 | |
| 
 | |
| static void ruletrace(void) {
 | |
| 	int i;
 | |
| 	extern int tablelines[MAXTDBUG];
 | |
| 	extern int ntableline;
 | |
| 	extern char *tablename;
 | |
| 
 | |
| 	fprintf(stderr,"Last code rules used\n");
 | |
| 	i=ntableline-1;
 | |
| 	while(i!=ntableline) {
 | |
| 		if (i<0)
 | |
| 			i += MAXTDBUG;
 | |
| 		if (tablelines[i]!=0)
 | |
| 			fprintf(stderr,"\%d: \"%s\", line %d\n",i,tablename,tablelines[i]);
 | |
| 		i--;
 | |
| 	}
 | |
| }
 | |
| #endif /* TABLEDEBUG */
 |