/* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * */ #include "ass00.h" #include "assex.h" #include "ip_spec.h" #ifndef NORCSID static char rcs_id[] = "$Id$" ; static char rcs_ip[] = RCS_IP ; #endif 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) { if (lnp->ad.ad_i >= holsize) { hol_err_line= line_num ; } lnp->ad.ad_i += holbase; } } 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=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=0 && val=0 && val<=65535L && ( i_flag!=PAR_G || val<=maxadr ) ; case OP16 : 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 OP16U: 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 ; int 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 */ } }