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