439 lines
8.3 KiB
C
439 lines
8.3 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#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 */
|
|
}
|
|
}
|