xref: /csrg-svn/old/pcc/ccom.tahoe/local.c (revision 32871)
125827Ssam #ifndef lint
2*32871Sdonn static char sccsid[] = "@(#)local.c	1.10 (Berkeley) 12/10/87";
325827Ssam #endif
425827Ssam 
526081Ssam # include "pass1.h"
625827Ssam 
725827Ssam /*	this file contains code which is dependent on the target machine */
825827Ssam 
925827Ssam NODE *
clocal(p)1025827Ssam clocal(p) register NODE *p; {
1125827Ssam 
1225827Ssam 	/* this is called to do local transformations on
1325827Ssam 	   an expression tree preparitory to its being
1425827Ssam 	   written out in intermediate code.
1525827Ssam 	*/
1625827Ssam 
1725827Ssam 	/* the major essential job is rewriting the
1825827Ssam 	   automatic variables and arguments in terms of
1925827Ssam 	   REG and OREG nodes */
2025827Ssam 	/* conversion ops which are not necessary are also clobbered here */
2125827Ssam 	/* in addition, any special features (such as rewriting
2225827Ssam 	   exclusive or) are easily handled here as well */
2325827Ssam 
2425827Ssam 	register struct symtab *q;
2525827Ssam 	register NODE *r;
2625827Ssam 	register int o;
2725827Ssam 	register int m, ml;
2825827Ssam 
2925827Ssam 	switch( o = p->in.op ){
3025827Ssam 
3125827Ssam 	case NAME:
3225827Ssam 		if( p->tn.rval < 0 ) { /* already processed; ignore... */
3325827Ssam 			return(p);
3425827Ssam 			}
3525827Ssam 		q = &stab[p->tn.rval];
3625827Ssam 		switch( q->sclass ){
3725827Ssam 
3825827Ssam 		case AUTO:
3925827Ssam 		case PARAM:
4025827Ssam 			/* fake up a structure reference */
4125827Ssam 			r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 );
4225827Ssam 			r->tn.lval = 0;
4325827Ssam 			r->tn.rval = STKREG;
4425827Ssam 			p = stref( block( STREF, r, p, 0, 0, 0 ) );
4525827Ssam 			break;
4625827Ssam 
4725827Ssam 		case ULABEL:
4825827Ssam 		case LABEL:
4925827Ssam 		case STATIC:
5025827Ssam 			if( q->slevel == 0 ) break;
5125827Ssam 			p->tn.lval = 0;
5225827Ssam 			p->tn.rval = -q->offset;
5325827Ssam 			break;
5425827Ssam 
5525827Ssam 		case REGISTER:
5625827Ssam 			p->in.op = REG;
5725827Ssam 			p->tn.lval = 0;
5825827Ssam 			p->tn.rval = q->offset;
5925827Ssam #ifdef REG_CHAR
6025827Ssam 			m = p->in.type;
6125827Ssam 			if( m==CHAR || m==SHORT )
6225827Ssam 				p->in.type = INT;
6325827Ssam 			else if( m==UCHAR || m==USHORT )
6425827Ssam 				p->in.type = UNSIGNED;
6525827Ssam #endif
6625827Ssam 			break;
6725827Ssam 
6825827Ssam 			}
6925827Ssam 		break;
7025827Ssam 
7125827Ssam 	case LT:
7225827Ssam 	case LE:
7325827Ssam 	case GT:
7425827Ssam 	case GE:
7525827Ssam 		if( ISPTR( p->in.left->in.type ) || ISPTR( p->in.right->in.type ) ){
7625827Ssam 			p->in.op += (ULT-LT);
7725827Ssam 			}
7825827Ssam 		break;
7925827Ssam 
8025827Ssam 	case PCONV:
8125827Ssam 		/* do pointer conversions for char and longs */
8225827Ssam 		ml = p->in.left->in.type;
8325827Ssam 		if( ( ml==CHAR || ml==UCHAR || ml==SHORT || ml==USHORT ) && p->in.left->in.op != ICON ) break;
8425827Ssam 
8525827Ssam 		/* pointers all have the same representation; the type is inherited */
8625827Ssam 
8725827Ssam 		p->in.left->in.type = p->in.type;
8825827Ssam 		p->in.left->fn.cdim = p->fn.cdim;
8925827Ssam 		p->in.left->fn.csiz = p->fn.csiz;
9025827Ssam 		p->in.op = FREE;
9125827Ssam 		return( p->in.left );
9225827Ssam 
9325827Ssam 	case SCONV:
9425827Ssam 		m = p->in.type;
9525827Ssam 		ml = p->in.left->in.type;
9632870Sdonn 		if(m == ml)
9732870Sdonn 			goto clobber;
9832870Sdonn 		o = p->in.left->in.op;
9925827Ssam 		if(m == FLOAT || m == DOUBLE) {
10032870Sdonn 			if(o==SCONV &&
10129671Ssam 			 ml == DOUBLE &&
10225827Ssam 			 p->in.left->in.left->in.type==m) {
10325827Ssam 				p->in.op = p->in.left->in.op = FREE;
10425827Ssam 				return(p->in.left->in.left);
10532870Sdonn 				}
10632870Sdonn 			/* see makety() for constant conversions */
10732870Sdonn 			break;
10825827Ssam 			}
10925827Ssam 		if(ml == FLOAT || ml == DOUBLE){
11032870Sdonn 			if(o != FCON && o != DCON)
11132870Sdonn 				break;
11232870Sdonn 			ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */
11332870Sdonn 			r = block( ICON, (NODE *)NULL, (NODE *)NULL, ml, 0, 0 );
11432870Sdonn 			if( o == FCON )
11532870Sdonn 				r->tn.lval = ml == INT ?
11632870Sdonn 					(int) p->in.left->fpn.fval :
11732870Sdonn 					(unsigned) p->in.left->fpn.fval;
11832870Sdonn 			else
11932870Sdonn 				r->tn.lval = ml == INT ?
12032870Sdonn 					(int) p->in.left->dpn.dval :
12132870Sdonn 					(unsigned) p->in.left->dpn.dval;
12232870Sdonn 			r->tn.rval = NONAME;
12332870Sdonn 			p->in.left->in.op = FREE;
12432870Sdonn 			p->in.left = r;
12532870Sdonn 			o = ICON;
12632870Sdonn 			if( m == ml )
12732870Sdonn 				goto clobber;
12825827Ssam 			}
12925827Ssam 		/* now, look for conversions downwards */
13025827Ssam 
13132870Sdonn 		if( o == ICON ){ /* simulate the conversion here */
13225827Ssam 			CONSZ val;
13325827Ssam 			val = p->in.left->tn.lval;
13425827Ssam 			switch( m ){
13525827Ssam 			case CHAR:
13625827Ssam 				p->in.left->tn.lval = (char) val;
13725827Ssam 				break;
13825827Ssam 			case UCHAR:
13925827Ssam 				p->in.left->tn.lval = val & 0XFF;
14025827Ssam 				break;
14125827Ssam 			case USHORT:
14225827Ssam 				p->in.left->tn.lval = val & 0XFFFFL;
14325827Ssam 				break;
14425827Ssam 			case SHORT:
14525827Ssam 				p->in.left->tn.lval = (short)val;
14625827Ssam 				break;
14725827Ssam 			case UNSIGNED:
14825827Ssam 				p->in.left->tn.lval = val & 0xFFFFFFFFL;
14925827Ssam 				break;
15025827Ssam 			case INT:
15125827Ssam 				p->in.left->tn.lval = (int)val;
15225827Ssam 				break;
15325827Ssam 				}
15425827Ssam 			p->in.left->in.type = m;
15532870Sdonn 			}
15632870Sdonn 		else
15732870Sdonn 			break;
15832870Sdonn 
15932870Sdonn 	clobber:
16025827Ssam 		p->in.op = FREE;
16125827Ssam 		return( p->in.left );  /* conversion gets clobbered */
16225827Ssam 
16325827Ssam 	case PVCONV:
16425827Ssam 	case PMCONV:
16525827Ssam 		if( p->in.right->in.op != ICON ) cerror( "bad conversion", 0);
16625827Ssam 		p->in.op = FREE;
16725827Ssam 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
16825827Ssam 
16925827Ssam 	case FLD:
17025827Ssam 		/* make sure that the second pass does not make the
17125827Ssam 		   descendant of a FLD operator into a doubly indexed OREG */
17225827Ssam 
17325827Ssam 		if( p->in.left->in.op == UNARY MUL
17425827Ssam 				&& (r=p->in.left->in.left)->in.op == PCONV)
17525827Ssam 			if( r->in.left->in.op == PLUS || r->in.left->in.op == MINUS )
17625827Ssam 				if( ISPTR(r->in.type) ) {
17725827Ssam 					if( ISUNSIGNED(p->in.left->in.type) )
17825827Ssam 						p->in.left->in.type = UNSIGNED;
17925827Ssam 					else
18025827Ssam 						p->in.left->in.type = INT;
18125827Ssam 				}
18225827Ssam 		break;
18326081Ssam 	case FORTCALL: /* arg must be FLOAT */
18426081Ssam 		if((r = p->in.right)->in.type != FLOAT)
18526081Ssam 			p->in.right = clocal(makety(r, FLOAT, 0, FLOAT));
18626081Ssam 		return(p);
18726081Ssam 	}
18825827Ssam 
18932870Sdonn 	return(p);
19025827Ssam 	}
19125827Ssam 
19232869Sdonn /*ARGSUSED*/
andable(p)19325827Ssam andable( p ) NODE *p; {
19425827Ssam 	return(1);  /* all names can have & taken on them */
19525827Ssam 	}
19625827Ssam 
cendarg()19725827Ssam cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */
19825827Ssam 	autooff = AUTOINIT;
19925827Ssam 	}
20025827Ssam 
cisreg(t)20125827Ssam cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */
20225827Ssam 
20325827Ssam 	if( t==INT || t==UNSIGNED || t==LONG || t==ULONG	/* tbl */
20425827Ssam #ifdef REG_CHAR
20525827Ssam 		|| t==CHAR || t==UCHAR || t==SHORT || t==USHORT		/* tbl */
20625827Ssam #endif
20729671Ssam 		|| ISPTR(t) || t == FLOAT) return (1);		/* wnj */
20825827Ssam 	return(0);
20925827Ssam 	}
21025827Ssam 
21132869Sdonn /*ARGSUSED*/
21225827Ssam NODE *
offcon(off,t,d,s)21325827Ssam offcon( off, t, d, s ) OFFSZ off; TWORD t; {
21425827Ssam 
21525827Ssam 	/* return a node, for structure references, which is suitable for
21625827Ssam 	   being added to a pointer of type t, in order to be off bits offset
21725827Ssam 	   into a structure */
21825827Ssam 
21925827Ssam 	register NODE *p;
22025827Ssam 
22125827Ssam 	/* t, d, and s are the type, dimension offset, and sizeoffset */
22232869Sdonn 	/* in general they  are necessary for offcon, but not on Tahoe */
22325827Ssam 
22425827Ssam 	p = bcon(0);
22525827Ssam 	p->tn.lval = off/SZCHAR;
22625827Ssam 	return(p);
22725827Ssam 
22825827Ssam 	}
22925827Ssam 
23025827Ssam 
23125827Ssam static inwd	/* current bit offsed in word */;
23225827Ssam static CONSZ word	/* word being built from fields */;
23325827Ssam 
incode(p,sz)23425827Ssam incode( p, sz ) register NODE *p; {
23525827Ssam 
23625827Ssam 	/* generate initialization code for assigning a constant c
23725827Ssam 		to a field of width sz */
23825827Ssam 	/* we assume that the proper alignment has been obtained */
23925827Ssam 	/* inoff is updated to have the proper final value */
24025827Ssam 	/* we also assume sz  < SZINT */
24125827Ssam 
24232869Sdonn 	if(nerrors) return;
24325827Ssam 	inwd += sz;
24425827Ssam 	if(inwd > SZINT) cerror("incode: field > int");
24525827Ssam 	word |= (p->tn.lval&((1L<<sz)-1)) << (SZINT-inwd);
24625827Ssam 	inoff += sz;
24725827Ssam 	if(inoff%SZINT == 0) {
24832870Sdonn 		printf( "	.long	0x%lx\n", word);
24925827Ssam 		word = inwd = 0;
25025827Ssam 		}
25125827Ssam 	}
25225827Ssam 
fincode(d,sz)25325827Ssam fincode( d, sz ) double d; register int sz; {
25425827Ssam 	/*
25525827Ssam 	 * output code to initialize space of size sz to the value d
25625827Ssam 	 * the proper alignment has been obtained
25726081Ssam 	 * inoff is updated to have the proper final value.
25825827Ssam 	 */
25925827Ssam 
26025827Ssam 	register struct sh4 {
26125827Ssam 		unsigned short sh[4];
26225827Ssam 	} *x;
26325827Ssam 	float f;
26425827Ssam 
26532869Sdonn 	if (nerrors) return;
26625827Ssam 	if(sz == SZFLOAT) {	/* force rounding */
26725827Ssam 		f = d;
26825827Ssam 		d = f;
26925827Ssam 	}
27025827Ssam 
27125827Ssam 	x = (struct sh4 *)&d;
27225827Ssam 	printf("	.long	0x%04x%04x", x->sh[0], x->sh[1]);
27325827Ssam 	if(sz == SZDOUBLE) {
27425827Ssam 		printf(", 0x%04x%04x", x->sh[2], x->sh[3]);
27525827Ssam 		printf(" # .double %.17g\n", d);
27625827Ssam 	} else
27725827Ssam 		printf(" # .float %.8g\n", d);
27825827Ssam 	inoff += sz;
27925827Ssam 	}
28025827Ssam 
cinit(p,sz)28125827Ssam cinit( p, sz ) NODE *p; {
28226081Ssam 	NODE *l;
28326081Ssam 
28426081Ssam 	/*
28526081Ssam 	 * as a favor (?) to people who want to write
28626081Ssam 	 *     int i = 9600/134.5;
28726081Ssam 	 * we will, under the proper circumstances, do
28832870Sdonn 	 * a coercion here.
28926081Ssam 	 */
29026081Ssam 	switch (p->in.type) {
29126081Ssam 	case INT:
29226081Ssam 	case UNSIGNED:
29326081Ssam 		l = p->in.left;
29426081Ssam 		if (l->in.op != SCONV ||
29526081Ssam 		    (l->in.left->tn.op != DCON && l->in.left->tn.op != FCON))
29626081Ssam 			break;
29726081Ssam 		l->in.op = FREE;
29826081Ssam 		l = l->in.left;
29926081Ssam 		l->tn.lval = l->tn.op == DCON ? (long)(l->dpn.dval) :
30026081Ssam 			(long)(l->fpn.fval);
30126081Ssam 		l->tn.rval = NONAME;
30226081Ssam 		l->tn.op = ICON;
30326081Ssam 		l->tn.type = INT;
30426081Ssam 		p->in.left = l;
30526081Ssam 		break;
30626081Ssam 	}
30732870Sdonn 	/* arrange for the initialization of p into a space of size sz */
30825827Ssam 	/* the proper alignment has been opbtained */
30925827Ssam 	/* inoff is updated to have the proper final value */
31025827Ssam 	ecode( p );
31125827Ssam 	inoff += sz;
31225827Ssam 	}
31325827Ssam 
vfdzero(n)31425827Ssam vfdzero( n ){ /* define n bits of zeros in a vfd */
31525827Ssam 
31625827Ssam 	if( n <= 0 ) return;
31725827Ssam 
31832870Sdonn 	if (nerrors) return;
31925827Ssam 	inwd += n;
32025827Ssam 	inoff += n;
32125827Ssam 	if( inoff%ALINT ==0 ) {
32232870Sdonn 		printf( "	.long	0x%lx\n", word );
32325827Ssam 		word = inwd = 0;
32425827Ssam 		}
32525827Ssam 	}
32625827Ssam 
32725827Ssam char *
exname(p)32825827Ssam exname( p ) char *p; {
32925827Ssam 	/* make a name look like an external name in the local machine */
33025827Ssam 
33125827Ssam #ifndef FLEXNAMES
33225827Ssam 	static char text[NCHNAM+1];
33325827Ssam #else
33425827Ssam 	static char text[BUFSIZ+1];
33525827Ssam #endif
33625827Ssam 
33725827Ssam 	register int i;
33825827Ssam 
33925827Ssam 	text[0] = '_';
34025827Ssam #ifndef FLEXNAMES
34126081Ssam 	for( i=1; *p&&i<NCHNAM; ++i )
34225827Ssam #else
34326081Ssam 	for( i=1; *p; ++i )
34425827Ssam #endif
34525827Ssam 		text[i] = *p++;
34625827Ssam 
34725827Ssam 	text[i] = '\0';
34825827Ssam #ifndef FLEXNAMES
34925827Ssam 	text[NCHNAM] = '\0';  /* truncate */
35025827Ssam #endif
35125827Ssam 
35225827Ssam 	return( text );
35325827Ssam 	}
35425827Ssam 
ctype(type)35532870Sdonn ctype( type ) TWORD type;
35632870Sdonn 	{ /* map types which are not defined on the local machine */
35725827Ssam 	switch( BTYPE(type) ){
35825827Ssam 
35925827Ssam 	case LONG:
36025827Ssam 		MODTYPE(type,INT);
36125827Ssam 		break;
36225827Ssam 
36325827Ssam 	case ULONG:
36425827Ssam 		MODTYPE(type,UNSIGNED);
36525827Ssam 		}
36625827Ssam 	return( type );
36725827Ssam 	}
36825827Ssam 
noinit()36925827Ssam noinit() { /* curid is a variable which is defined but
37025827Ssam 	is not initialized (and not a function );
37125827Ssam 	This routine returns the stroage class for an uninitialized declaration */
37225827Ssam 
37325827Ssam 	return(EXTERN);
37425827Ssam 
37525827Ssam 	}
37625827Ssam 
commdec(id)37725827Ssam commdec( id ){ /* make a common declaration for id, if reasonable */
37825827Ssam 	register struct symtab *q;
37925827Ssam 	OFFSZ off, tsize();
38025827Ssam 
38132869Sdonn 	if (nerrors) return;
38225827Ssam 	q = &stab[id];
38325827Ssam 	printf( "	.comm	%s,", exname( q->sname ) );
38425827Ssam 	off = tsize( q->stype, q->dimoff, q->sizoff );
38526162Ssam 	printf( "%d\n" /*CONFMT*/, off/SZCHAR );
38625827Ssam 	}
38725827Ssam 
prtdcon(p)38826081Ssam prtdcon(p)
38926081Ssam 	register NODE *p;
39026081Ssam {
39126081Ssam 	register int o = p->in.op;
39226081Ssam 	int i;
39325827Ssam 
39426081Ssam 	if (o != DCON && o != FCON)
39526081Ssam 		return;
39626081Ssam 	/*
39726081Ssam 	 * Clobber constants of value zero so
39826081Ssam 	 * we can generate more efficient code.
39926081Ssam 	 */
40026081Ssam 	if ((o == DCON && p->dpn.dval == 0) ||
40126081Ssam 	    (o == FCON && p->fpn.fval == 0)) {
40226081Ssam 		p->in.op = ICON;
40326081Ssam 		p->tn.rval = NONAME;
40426081Ssam 		return;
40526081Ssam 	}
40626081Ssam 	locctr(DATA);
40726081Ssam 	defalign(o == DCON ? ALDOUBLE : ALFLOAT);
40826081Ssam 	deflab(i = getlab());
40926081Ssam 	if (o == FCON)
41026081Ssam 		fincode(p->fpn.fval, SZFLOAT);
41126081Ssam 	else
41226081Ssam 		fincode(p->dpn.dval, SZDOUBLE);
41326081Ssam 	p->tn.lval = 0;
41426081Ssam 	p->tn.rval = -i;
41526081Ssam 	p->in.type = (o == DCON ? DOUBLE : FLOAT);
41626081Ssam 	p->in.op = NAME;
41726081Ssam }
41826081Ssam 
ecode(p)41925827Ssam ecode( p ) NODE *p; {
42025827Ssam 
42125827Ssam 	/* walk the tree and write out the nodes.. */
42225827Ssam 
42325827Ssam 	if( nerrors ) return;
42425827Ssam 	p2tree( p );
42525827Ssam 	p2compile( p );
42625827Ssam 	}
42725827Ssam 
42825827Ssam #ifndef ONEPASS
tlen(p)42925827Ssam tlen(p) NODE *p;
43025827Ssam {
43125827Ssam 	switch(p->in.type) {
43225827Ssam 		case CHAR:
43325827Ssam 		case UCHAR:
43425827Ssam 			return(1);
43525827Ssam 
43625827Ssam 		case SHORT:
43725827Ssam 		case USHORT:
43832870Sdonn 			return(SZSHORT/SZCHAR);
43925827Ssam 
44025827Ssam 		case DOUBLE:
44132870Sdonn 			return(SZDOUBLE/SZCHAR);
44225827Ssam 
44325827Ssam 		default:
44432870Sdonn 			return(SZINT/SZCHAR);
44525827Ssam 		}
44625827Ssam 	}
44725827Ssam #endif
448