/* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * */ #include #include "ass00.h" #include "assex.h" #include "assci.h" #include "asscm.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. */ /* Forward declarations. */ static int valid(register line_t *); static char *findfit(int, cons_t); static char *findnop(int); /* ** Determine the exact instruction length & format where possible, and the ** the upper and lower limits otherwise. Enter limits in labeltable */ void pass_3(void) { 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 int 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"); } } int oplength(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; } /* ** Determine the format that should be used for each instruction, ** depending on its offsets */ void determine_props(line_t *lnp, int *min_len, int *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); } static char *findfit(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; } static char* findnop(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 */ return NULL; } int opfit(int flag, int number, cons_t val, int i_flag) { /* 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 OP16U: return 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"); return -1; /* NOTREACHED */ } } /* ** return estimation of value of parameter */ cons_t parval(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); } static int valid(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"); return -1; /* NOTREACHED */ } }