ack/util/ass/ass30.c
2019-03-17 22:46:32 +08:00

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 */
}
}