ack/util/ass/ass30.c
1984-07-02 15:35:56 +00:00

372 lines
8.3 KiB
C

/*
* (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
*
* This product is part of the Amsterdam Compiler Kit.
*
* Permission to use, sell, duplicate or disclose this software must be
* obtained in writing. Requests for such permissions may be sent to
*
* Dr. Andrew S. Tanenbaum
* Wiskundig Seminarium
* Vrije Universiteit
* Postbox 7161
* 1007 MC Amsterdam
* The Netherlands
*
*/
#include "ass00.h"
#include "assex.h"
#include "ip_spec.h"
short opt_line ; /* max_line_no - # lines removed from end
after perfoming exc's.
Used to estimate the distance in # of
instructions.
*/
/*
** Determine the exact instruction length & format where possible, and the
** the upper and lower limits otherwise. Enter limits in labeltable
*/
pass_3()
{
register line_t *lnp, *rev_lnp;
line_t *tmp_lnp;
locl_t *lbp;
int min_l, max_l, min_bytes;
short last_line ;
short hol_err_line ;
register insno ;
pass = 3;
opt_line= line_num ; hol_err_line=0 ;
min_bytes = max_bytes = 0; rev_lnp= lnp_cast 0 ;
for (lnp = pstate.s_fline ; lnp ; opt_line--, line_num-- ) {
pstate.s_fline= lnp;
insno = ctrunc(lnp->instr_num);
switch( insno ) {
case sp_fpseu :
last_line = line_num ;
line_num = lnp->ad.ad_ln.ln_first ;
opt_line -= lnp->ad.ad_ln.ln_extra ;
lnp->ad.ad_ln.ln_first= last_line ;
break ;
case sp_ilb1 :
lbp = lnp->ad.ad_lp;
lbp->l_defined = SEEN;
lbp->l_min = min_bytes;
lbp->l_max = max_bytes;
break ;
default:
if ( lnp->type1==CONST && (em_flag[insno]&EM_PAR)==PAR_G ) {
if (holbase != 0) {
lnp->ad.ad_i += holbase;
if (lnp->ad.ad_i >= holsize) {
hol_err_line= line_num ;
}
}
} else
if ( lnp->type1>=VALLOW && (em_flag[insno]&EM_PAR)==PAR_G ) {
if (holbase != 0) {
pstate.s_fline= lnp->l_next ;
newline(CONST) ;
pstate.s_fline->instr_num= insno ;
pstate.s_fline->ad.ad_i=
VAL1(lnp->type1)+holbase ;
freearea((area_t)lnp,
(unsigned)linesize[VALLOW]) ;
lnp= pstate.s_fline ;
if ( VAL1(lnp->type1) >= holsize) {
hol_err_line= line_num ;
}
}
}
if ( !valid(lnp) ) fatal("Invalid operand") ;
determine_props(lnp, &min_l, &max_l);
min_bytes += min_l; max_bytes += max_l;
break ;
}
tmp_lnp= lnp->l_next ;
lnp->l_next= rev_lnp ; rev_lnp= lnp ;
lnp= tmp_lnp ;
}
pstate.s_fline= rev_lnp ;
if ( hol_err_line ) {
line_num= hol_err_line ;
werror("address exceeds holsize") ;
}
}
/*
** Determine the format that should be used for each instruction,
** depending on its offsets
*/
determine_props(lnp, min_len, max_len)
line_t *lnp;
int *min_len, *max_len;
{
cons_t val ;
register int insno ;
register char *f_off, *l_off ;
char defined ;
insno=ctrunc(lnp->instr_num) ;
val=parval(lnp,&defined) ;
if ( !defined ) {
switch(em_flag[insno]&EM_PAR) {
case PAR_NO:
case PAR_W:
f_off = findnop(insno) ;
break ;
case PAR_G:
/* We want the maximum address that is a multiple
of the wordsize.
Assumption: there is no shortie for
intr max_word_multiple
where intr is a instruction allowing parameters
that are not a word multiple (PAR_G).
*/
f_off = findfit(insno, maxadr&(~(wordsize-1))) ;
break ;
case PAR_B:
f_off = findfit(insno, (cons_t)0) ;
l_off = findfit(insno, val ) ;
if ( f_off != l_off ) {
*min_len=oplength(*f_off) ;
*max_len=oplength(*l_off) ;
lnp->opoff = NO_OFF ;
return ;
}
break ;
}
} else {
f_off = findfit(insno,val) ;
}
lnp->opoff = f_off ;
*min_len = *max_len = oplength(*f_off) ;
}
char *findfit(instr,val) int instr ; cons_t val ; {
register char *currc,*endc ;
int found, flags, number ;
char *opc ;
endc = opindex[instr+1] ;
for ( currc=opindex[instr], found=0 ;
!found && currc<endc ; currc++ ) {
opc = currc ;
flags=ctrunc(*currc++) ;
switch ( flags&OPTYPE ) {
case OPNO :
continue ;
case OPMINI :
case OPSHORT :
number=ctrunc(*++currc) ;
}
found = opfit(flags, number, val, em_flag[instr]&EM_PAR ) ;
}
if ( !found ) fatal("Cannot find interpreter opcode") ;
return opc ;
}
char *findnop(instr) int instr ; {
register char *currc,*endc ;
endc = opindex[instr+1] ;
for ( currc=opindex[instr] ; currc<endc ; currc++ ) {
switch ( ctrunc(*currc)&OPTYPE ) {
case OPNO :
return currc ;
case OPSHORT :
case OPMINI :
currc++ ;
}
currc++ ;
}
fatal("Cannot find interpreter opcode") ;
/* NOTREACHED */
}
int opfit(flag,number,val,i_flag)
int i_flag,flag,number ; cons_t val ; {
/* Number is invalid if flag does not contain MINI or SHORT */
switch ( flag&OPRANGE ) {
case OP_POS :
if ( val<0 ) return 0 ;
break ;
case OP_NEG :
if ( val>=0 ) return 0 ;
break ;
}
if ( flag&OPWORD ) {
if ( val%wordsize ) return 0 ;
val /= wordsize ;
}
if ( flag&OPNZ ) {
if ( val==0 ) return 0 ;
val-- ;
}
switch ( flag&OPTYPE ) {
case OPMINI :
if ( val<0 ) val = -1-val ;
return val>=0 && val<number ;
case OPSHORT :
if ( val<0 ) val = -1-val ;
return val>=0 && val<number*256 ;
case OP16 :
if ( i_flag==PAR_G ) return val>=0 && val<=maxadr ;
return val>= -32768 && val<=32767 ;
case OP32 :
return TRUE ;
default :
fatal("illegal OPTYPE value") ;
/* NOTREACHED */
}
}
int oplength(flag) int flag ; {
int cnt ;
cnt=1 ;
if ( flag&OPESC ) cnt++ ;
switch( flag&OPTYPE ) {
case OPNO :
case OPMINI : break ;
case OP8 :
case OPSHORT : cnt++ ; break ;
case OP16 : cnt+=2 ; break ;
case OP32 : cnt+=5 ; break ;
case OP64 : cnt+=9 ; break ;
}
return cnt ;
}
/*
** return estimation of value of parameter
*/
cons_t parval(lnp,defined)
line_t *lnp;
char *defined;
{
register int type;
register locl_t *lbp;
register glob_t *gbp;
cons_t offs ;
*defined = TRUE ;
type = lnp->type1;
switch(type) {
default: if ( type>=VALLOW && type<=VALHIGH )
return VAL1(type) ;
error("bad type during parval");
break;
case CONST:
return(lnp->ad.ad_i);
case GLOSYM:
case GLOOFF:
if ( type!=GLOOFF) {
gbp = lnp->ad.ad_gp;
offs= 0 ;
} else {
gbp =lnp->ad.ad_df.df_gp ;
offs=lnp->ad.ad_df.df_i ;
}
if(gbp->g_status&DEF)
return(gbp->g_val.g_addr+offs);
else {
*defined = FALSE ;
return offs ;
}
case LOCSYM:
lbp = lnp->ad.ad_lp;
switch(pass) {
default:error("bad pass in parval");
case 3:
*defined = FALSE;
switch(lbp->l_defined) {
default : fatal("Illegal local label") ;
case NO :
error("Undefined local label") ;
lbp->l_defined= NOTPRESENT ;
case NOTPRESENT:
return max_bytes;
case SEEN :
return max_bytes - lbp->l_min ;
case YES :
/* l_min contains line_num
adjusted for exc's.
*/
return (lbp->l_min - opt_line -1 ) * maxinsl ;
}
case 4: if(lbp->l_defined == YES)
return(lbp->l_min-prog_size-maxinsl);
return max_bytes - lbp->l_max- prog_size;
case 5: if (lbp->l_defined == YES )
return lbp->l_min ;
*defined = FALSE ;
break ;
}
break;
case MISSING:
*defined = FALSE ;
break;
case PROCNAME:
return(lnp->ad.ad_pp->p_num);
}
return(0);
}
int valid(lnp) register line_t *lnp ; {
cons_t val ;
char type ;
type = lnp->type1 ;
if ( type>=VALLOW && type<=VALHIGH ) {
val= VAL1(type) ;
type= CONST ;
} else if ( type==CONST ) val = lnp->ad.ad_i ;
switch ( em_flag[ctrunc(lnp->instr_num)]&EM_PAR ) {
case PAR_NO:
return type==MISSING ;
case PAR_C:
if ( type!=CONST ) return FALSE;
if ( val>maxint && val<=maxunsig ) {
lnp->ad.ad_i = val -maxunsig -1 ;
}
return TRUE ;
case PAR_D:
if ( type!=CONST ) return FALSE;
if ( val>maxdint && val<=maxdunsig ) {
lnp->ad.ad_i = val -maxdunsig -1 ;
}
return TRUE ;
case PAR_L:
case PAR_F:
return type==CONST ;
case PAR_N:
return type==CONST && val>=0 ;
case PAR_G:
return type==CONST || type==GLOSYM || type==GLOOFF ;
case PAR_W:
if ( type==MISSING ) return TRUE ;
case PAR_S:
return type==CONST && val>0 && val%wordsize==0 ;
case PAR_Z:
return type==CONST && val>=0 && val%wordsize==0 ;
case PAR_O:
return type==CONST && val>=0 &&
( val >= wordsize ? val%wordsize : wordsize%val ) == 0 ;
case PAR_P:
return type==PROCNAME ;
case PAR_B:
return type==LOCSYM ;
case PAR_R:
return type==CONST && val>=0 && val<=3 ;
default:
fatal("Unknown parameter type") ;
/* NOTREACHED */
}
}