372 lines
8.3 KiB
C
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 */
|
|
}
|
|
}
|