P8000/WEGA/contrib/lcc/cmd/comp/common/allo.c

657 lines
12 KiB
C

# include "mfile2.h"
#ifndef NHALF
#define NHALF 0x800
#endif
#ifndef RKLET
#define RKLET 0x1000
#endif
#ifndef RXLET
#define RXLET 0x2000
#endif
NODE resc[NRGS];
int busy[NRGS];
# define TBUSY 0100
allo0()
{
/* free everything */
register i;
for( i=0; i<NRGS; ++i )
{
busy[i] = 0;
}
}
allo( p, q )
register NODE *p;
register struct optab *q;
{
register n, i, j;
register NODE *presc;
int k, rw;
n = q->needs;
rw = q->rewrite;
if( rdebug > 1 ) printf( "allo( %d, %d ), needs = 0x%x\n", p-node, q->stinline, q->needs );
i = 0;
while( n & ( QCOUNT | PCOUNT | NCOUNT ) )
{
if ( n & QCOUNT )
{
j = freequad ( p, n ,rw );
if(rw & RXLET)
rw &= ~RXLET;
busy[j] |= TBUSY;
busy[j+1] |= TBUSY;
busy[j+2] |= TBUSY;
busy[j+3] |= TBUSY;
n -= 0x100;
k = 4;
}
else if( n & PCOUNT )
{
j = freepair( p, n , rw);
if(rw & RXLET)
rw &= ~RXLET;
busy[j] |= TBUSY;
busy[j+1] |= TBUSY;
n -= 0x10;
k = 2;
}
else if ( n & NCOUNT )
{
j = freereg( p, n );
busy[j] |= TBUSY;
n -= 1;
k = 1;
}
presc = &resc[i];
presc->in.op = REG;
presc->tn.rval = j;
/* presc->tn.type = ( k == 4 ) ? TDOUBLE : ( k == 2 ) ? TLONG : TSHORT; */
presc->tn.type = p->in.type;
presc->tn.lval = 0;
presc->bn.label = k;
++i;
}
/* turn off "temporarily busy" bit */
for( j=0; j<NRGS; ++j )
{
busy[j] &= ~TBUSY;
}
if( rdebug > 1 )
{
for( j=0; j<i; ++j )
{
if( resc[j].tn.op == REG )
printf( ", RESC%d = REG(%d+%d) type = 0x%x", j+1 ,resc[j].tn.rval, resc[j].bn.label , resc[j].in.type);
else
printf( ", RESC%d = TEMP(%ld) ", j+1 ,resc[j].tn.lval );
}
putchar( '\n' );
}
}
OFFSZ tmpoff; /* offset of next temp to be allocated */
int rdebug = 0;
OFFSZ
freetemp( k )
register OFFSZ k;
{
/* allocate k integers worth of temp space
** we also make the convention that, if the number of words is more than 1,
** it must be aligned for storing doubles...
*/
# ifndef BACKTEMP
OFFSZ t;
if( k>1 )
{
SETOFF( tmpoff, ALDOUBLE );
}
t = tmpoff;
tmpoff += k*SZINT;
if( tmpoff > maxtemp ) maxtemp = tmpoff;
return(t);
# else
tmpoff += k*SZINT;
if( k>1 )
{
SETOFF( tmpoff, ALDOUBLE );
}
if( tmpoff > maxtemp ) maxtemp = tmpoff;
return( -tmpoff );
# endif
}
# ifdef STACK
/* for stack machines, totally disable the register allocation */
freereg( p, n )
NODE *p;
{
return( 0 );
}
freepair( p, n )
NODE *p;
{
cerror( "pairs on a stack machine?" );
}
rbusy( r, t )
TWORD t;
{
}
rfree( r, t )
TWORD t;
{
}
regrcl( p )
NODE *p;
{
}
# else
freepair( p, n, rw )
register NODE *p;
register n ;
int rw;
{
/* allocate a register pair */
/* p gives the type */
register j;
register t = optype( p->tn.op );
if( callop(p->in.op) )
{
j = callreg(p);
if( j&1 ) cerror( "callreg returns bad pair" );
if( usable( p, n, j ) && usable( p, n, j+1) ) return( j );
/* have allocated callreg first */
}
if ( rw & RXLET )
{
if ( usable ( p, n, 2) && usable (p, n, 3) ) return ( 2 );
cerror ( "RXLET bad pair allocation");
}
if( n )
{
if( (n&LPREF) && (j = shared( getlt( p, t ) ) ) >= 0 ) {
j = ( NHALF & rw ) ? j & 0xe : j;
if ( j & 1 ) cerror("illegal pair LPREF");
if( usable( p, n, j ) && usable( p, n, j+1) ) return( j );
}
if( (n&RPREF) && (j = shared( getrt( p, t ) ) ) >= 0 &&
usable( p, n, j ) && usable( p, n, j+1) ) return( j );
for( j=2; j<NRGS; j+=2 ) {
if( usable(p,n,j) && usable(p,n,j+1) )
return( j );
}
}
cerror( "pair register allocation fails, try simplify expression" );
/* NOTREACHED */
}
freequad( p, n ,rw)
register NODE *p;
register n;
int rw;
{
/* allocate a register pair */
/* p gives the type */
register j;
register t = optype ( p->tn.op );
if( callop(p->in.op) )
{
j = callreg(p);
if( j ) cerror( "callreg returns bad pair" );
if( usable( p, n, j ) && usable( p, n, j+1) &&
usable(p,n, j+2 ) && usable( p, n, j+3) ) return( j );
/* have allocated callreg first */
}
if ( rw & RXLET )
{
if( usable(p,n,0) && usable(p,n,1) &&
usable(p,n,2) && usable (p,n,3) ) return ( 0 );
cerror ("RXLET bad quad allocation");
}
if( n )
{
if( (n&LPREF) && (j = shared( getlt( p, t ) ) ) >= 0) {
j = ( rw & NHALF ) ? j & 0xc : j;
if ( j & 0x3 ) cerror ( "illegal quad LPREF");
if( usable( p, n, j ) && usable ( p, n, j+1 ) &&
usable(p,n,j+2) && usable(p,n,j+3) ) return( j );
}
if( (n&RPREF) && (j = shared( getrt( p, t ) ) ) >= 0 &&
usable( p, n, j ) && usable ( p, n, j+1 ) &&
usable(p,n,j+2) && usable(p,n,j+3) ) return( j );
for( j=0; j<NRGS; j+=4 )
if( usable(p,n,j) && usable(p,n,j+1) &&
usable(p,n,j+2) && usable(p,n,j+3))
return( j );
}
cerror( "quad register allocation fails, try simplify exprssion" );
/* NOTREACHED */
}
freereg( p, n )
register NODE *p;
register n;
{
/* allocate a register */
/* p gives the type */
register j;
register int t = optype( p->tn.op );
if( callop(p->in.op) )
{
j = callreg(p);
if( usable( p, n, j ) ) return( j );
/* have allocated callreg first */
}
if( n )
{
if( (n&LPREF) && (j = shared( getlt( p, t ) ) ) >= 0 &&
usable( p, n, j ) ) return( j );
if( (n&RPREF) && (j = shared( getrt( p, t ) ) ) >= 0 &&
usable( p, n, j ) ) return( j );
for( j=2; j<NRGS ; ++j ) if( usable(p,n,j) ) return( j );
}
cerror( "short register allocation fails, try simplify expression" );
/* NOTREACHED */
}
shared( p )
register NODE *p;
{
/* simple, at present */
/* try to find a register to share */
register r, o;
if( rdebug )
{
printf( "shared called on:\n" );
e2print( p );
}
if( (o=p->tn.op) == REG )
{
r = p->tn.rval;
if( r >= NRGS ) return( -1 );
if( rdebug )
{
printf( "preference for R%d\n", r );
}
return( r );
}
/* we look for shared regs under unary-like ops */
switch( optype( o ) )
{
case BITYPE:
/* look for simple cases */
/* look only on the left */
case UTYPE:
return( shared( p->in.left ) );
}
return( -1 );
}
usable( p, n, r )
register NODE *p;
register n,r;
{
/* decide if register r is usable in tree p to satisfy need n */
if( r>= NRGS || (busy[r] & TBUSY) ) return( 0 );
if( busy[r] > 1 )
{
/*
** uerror( "register %d too busy", r );
*/
return( 0 );
}
if( busy[r] == 0 ) return(1);
/* busy[r] is 1: is there chance for sharing */
return( shareit( p, r, n ) );
}
shareit( p, r, n )
register NODE *p;
register r,n;
{
/* can we make register r available by sharing from p
** given that the need is n
*/
register int t = optype(p->tn.op);
if( (n&LSHARE) && ushare( getlt( p, t ), r ) ) return(1);
if( (n&RSHARE) && ushare( getrt( p, t ), r ) ) return(1);
return(0);
}
ushare( p, r )
register NODE *p;
register r;
{
/* can we find register r to share in p */
if( p->in.op == REG )
{
/****
if( typlen ( p->tn.type ) == 4 && r==(p->tn.rval+1) ) return( 1 );
if( typlen ( p->tn.type ) == 8 &&
( r > (p->tn.rval) && r <= (p->tn.rval+3) )
) return( 1 );
return( r == p->tn.rval );
********/
if ( r >= p->tn.rval && r < p->tn.rval + p->bn.label )return(1);
}
switch( optype( p->tn.op ) )
{
case BITYPE:
if( ushare( p->in.right, r ) ) return( 1 );
case UTYPE:
if( ushare( p->in.left, r ) ) return( 1 );
}
return(0);
}
regrcl( p )
register NODE *p;
{
/* free registers in the tree (or fragment) p */
register r;
if( !p ) return;
r = p->tn.rval;
if( p->in.op == REG ) rfree( r, p->bn.label );
switch( optype( p->tn.op ) )
{
case BITYPE:
regrcl( p->in.right );
/* explict assignment to regs not accounted for */
if( asgop(p->tn.op) && p->in.left->tn.op == REG ) break;
case UTYPE:
regrcl( p->in.left );
}
}
rfree( r, n )
register int n;
register r;
{
register i;
/* mark register r free, if it is legal to do so */
/* t is the type */
r &= 0xf;
#ifndef NODBG
if( rdebug )
{
printf( "rfree( R%d , lenght=%d)\n", r, n);
}
#endif
if( istreg(r) )
{
for ( i = n ; i ; --i ){
if( !istreg(r+i-1) ) cerror ( "register to big" ) ;
if( --busy[r+i-1] < 0 ) cerror ( "register overfreed %d" ,r+i-1);
}
}
}
rbusy(r, n )
register r;
register n;
{
register i;
/* mark register r busy */
r &= 0xf;
#ifndef NODBG
if( rdebug )
{
printf( "rbusy( R%d, length=%d ) \n", r, n);
}
#endif
if( istreg(r) )
{
for ( i = n ; i ; --i ){
if( !istreg(r+i-1) ) cerror ( "register to big" ) ;
++busy[r+i-1] ;
}
}
}
# endif
rwprint( rw )
register rw;
{
/* print rewriting rule */
register i, flag;
static char * rwnames[] =
{
"RLEFT",
"RRIGHT",
"RESC1",
"RESC2",
"RESC3",
"RESC4",
"RESCC",
"RNOP",
"RNULL",
"RHIGHT",
"RLOW",
0,
};
if( rw == RNULL )
{
printf( "RNULL" );
return;
}
flag = 0;
for( i=0; rwnames[i]; ++i )
{
if( rw & (1<<i) )
{
if( flag ) printf( "|" );
++flag;
printf( rwnames[i] );
}
}
if( !flag ) printf( "?0x%lx", rw );
}
reclaim( p, rw, goal )
register NODE *p;
register rw, goal;
{
register NODE *q;
register o;
/* get back stuff */
if( rdebug )
{
printf( "reclaim( %d, ", p-node );
rwprint( rw );
printf( ", " );
prgoal( goal );
printf( " )\n" );
}
if( !p ) return;
if( rdebug > 1)
printf("reclaim inputtype = 0x%x\n",p->tn.type);
/* special cases... */
if( (o=p->tn.op) == COMOP )
{
/* LHS has already been freed; don't free again */
regrcl( p->in.right );
}
else regrcl( p );
if( (o==FREE && rw==RNULL) || rw==RNOP ) return;
if( callop(o) )
{
/* check that all scratch regs are free */
callchk(p); /* ordinarily, this is the same as allchk() */
}
if( rw == RNULL || (goal&FOREFF) )
{
/* totally clobber, leave nothing */
tfree(p);
return;
}
/* handle condition codes specially */
if( (goal & FORCC) && (rw&RESCC))
{
/* result is CC register */
tfree(p);
p->in.op = CCODES;
p->tn.lval = 0;
p->tn.rval = 0;
return;
}
q = 0;
if ( rw&RRIGHT ) {
q = getr( p );
q->tn.type = p->tn.type;
}
else {
int k;
if( rw & RLEFT) { q = getl (p); q->tn.type = p->tn.type; k=1 ;}
else if( rw&RESC1 ) q = &resc[0];
else if( rw&RESC2 ) q = &resc[1];
else if( rw&RESC3 ) q = &resc[2];
else if( rw&RESC4 ) q = &resc[3];
else cerror( "illegal reclaim, op %s", opst[p->tn.op]);
if ( q->tn.op == REG ) {
if( q->tn.rval < 8 ) k = q->bn.label / 2 ;
if ( k == 0 && (rw & (RHIGHT | RLOW)))
cerror( "illegal half register");
if ( k ) {
if (rw&RHIGHT ) {
q->bn.label = k;
}
if (rw&RLOW ) {
q->tn.rval += k;
if ( q->tn.rval < 8 )
q->bn.label = k;
if ( RKLET & rw && k == 2 )
q->bn.label = 1;
}
}
/* Halbieren der Reclaims */
if ( q->in.type & TCHAR )
q->in.type = (~TCHAR & q->in.type) | TSHORT ;
if ( q->in.type == TUCHAR )
q->in.type = (~TUCHAR & q->in.type) | TUSHORT;
if (( rw&RLOW) && (rw&RLEFT) )
q->in.type = TINT;
}
if ( rdebug > 1 ) {
printf ( "reclaim type = 0x%x\n",q->in.type);
}
}
if( o == STARG ) p = p->in.left; /* STARGs are still STARGS */
q = tcopy(q);
tfree(p);
*p = *q; /* make the result replace the original */
q->in.op = FREE;
}
NODE *
tcopy( p )
register NODE *p;
{
/* make a fresh copy of p */
register NODE *q;
register r;
q=talloc();
*q = *p;
r = p->tn.rval;
if( p->in.op == REG ) rbusy( r, p->bn.label );
switch( optype(q->in.op) )
{
case BITYPE:
q->in.right = tcopy(p->in.right);
case UTYPE:
q->in.left = tcopy(p->in.left);
}
return(q);
}
allchk()
{
/* check to ensure that all register are free */
register i;
for( i=0; i<NRGS; ++i )
{
if( busy[i] )
{
cerror( "register allocation error");
}
}
}
/* this may not be the best place for this routine... */
OFFSZ
argsize( p )
register NODE *p;
{
/* size of the arguments */
register OFFSZ t;
t = 0;
if( p->tn.op == CM )
{
t = argsize( p->in.left );
p = p->in.right;
}
if( p->tn.type & (TDOUBLE|TFLOAT) )
{
SETOFF( t, ALDOUBLE );
t += SZDOUBLE;
}
else if( p->tn.type & (TLONG|TULONG) )
{
SETOFF( t, ALLONG );
t += SZLONG;
}
else if( p->tn.type & TPOINT )
{
SETOFF( t, ALPOINT );
t += SZPOINT;
}
else if( p->tn.type & TSTRUCT )
{
SETOFF( t, p->stn.stalign ); /* alignment */
t += p->stn.stsize; /* size */
}
else
{
SETOFF( t, ALINT );
t += SZINT;
}
return( t );
}