375 lines
11 KiB
C
375 lines
11 KiB
C
/* $Id$ */
|
|
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* Functions to partition the huge set of EM-instructions. */
|
|
|
|
#include <em_mnem.h>
|
|
#include <em_pseu.h>
|
|
#include <em_reg.h>
|
|
#include <em_spec.h>
|
|
#include "../share/types.h"
|
|
#include "../share/aux.h"
|
|
#include "../share/debug.h"
|
|
#include "../share/global.h"
|
|
#include "cs.h"
|
|
#include "cs_stack.h"
|
|
|
|
#include "cs_partit.h"
|
|
|
|
#define XXX (-1)
|
|
#define ARGW 0
|
|
#define WS 1
|
|
#define PS 2
|
|
#define FEF 3
|
|
#define FIF 4
|
|
#define CVT 5
|
|
|
|
#define ANY 0
|
|
#define PTR 1
|
|
#define FLT 2
|
|
|
|
static struct {
|
|
byte i_group; /* Group of instruction. */
|
|
byte i_op1; /* Indication of size of operand of unary operator. */
|
|
/* Idem for 1st operand of binary operator. */
|
|
byte i_op2; /* Idem for 2nd operand of binary operator. */
|
|
byte i_av; /* Idem for result of operators. */
|
|
byte i_regtype; /* ANY, PTR, FLT. */
|
|
} info[] = {
|
|
{ XXX, XXX, XXX, XXX, XXX },
|
|
/* aar */ { TERNAIR_OP, XXX, XXX, PS, PTR },
|
|
/* adf */ { BINAIR_OP, ARGW, ARGW, ARGW, FLT },
|
|
/* adi */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* adp */ { EXPENSIVE_LOAD, XXX, XXX, XXX, PTR },
|
|
/* ads */ { BINAIR_OP, PS, ARGW, PS, PTR },
|
|
/* adu */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* and */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* asp */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* ass */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* beq */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* bge */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* bgt */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* ble */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* blm */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* bls */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* blt */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* bne */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* bra */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* cai */ { SIDE_EFFECTS, XXX, XXX, XXX, XXX },
|
|
/* cal */ { SIDE_EFFECTS, XXX, XXX, XXX, XXX },
|
|
/* cff */ { TERNAIR_OP, XXX, XXX, CVT, FLT },
|
|
/* cfi */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* cfu */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* cif */ { TERNAIR_OP, XXX, XXX, CVT, FLT },
|
|
/* cii */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* ciu */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* cmf */ { BINAIR_OP, ARGW, ARGW, WS, ANY },
|
|
/* cmi */ { BINAIR_OP, ARGW, ARGW, WS, ANY },
|
|
/* cmp */ { BINAIR_OP, PS, PS, WS, ANY },
|
|
/* cms */ { BINAIR_OP, ARGW, ARGW, WS, ANY },
|
|
/* cmu */ { BINAIR_OP, ARGW, ARGW, WS, ANY },
|
|
/* com */ { UNAIR_OP, ARGW, XXX, ARGW, ANY },
|
|
/* csa */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* csb */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* cuf */ { TERNAIR_OP, XXX, XXX, CVT, FLT },
|
|
/* cui */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* cuu */ { TERNAIR_OP, XXX, XXX, CVT, ANY },
|
|
/* dch */ { UNAIR_OP, PS, XXX, PS, PTR },
|
|
/* dec */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* dee */ { KILL_ENTITY, XXX, XXX, XXX, XXX },
|
|
/* del */ { KILL_ENTITY, XXX, XXX, XXX, XXX },
|
|
/* dup */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* dus */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* dvf */ { BINAIR_OP, ARGW, ARGW, ARGW, FLT },
|
|
/* dvi */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* dvu */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* exg */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* fef */ { UNAIR_OP, ARGW, XXX, FEF, XXX },
|
|
/* fif */ { BINAIR_OP, ARGW, ARGW, FIF, XXX },
|
|
/* fil */ { IGNORE, XXX, XXX, XXX, XXX },
|
|
/* gto */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* inc */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* ine */ { KILL_ENTITY, XXX, XXX, XXX, XXX },
|
|
/* inl */ { KILL_ENTITY, XXX, XXX, XXX, XXX },
|
|
/* inn */ { BINAIR_OP, ARGW, WS, WS, ANY },
|
|
/* ior */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* lae */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lal */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lar */ { LOAD_ARRAY, XXX, XXX, XXX, ANY },
|
|
/* ldc */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lde */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* ldf */ { EXPENSIVE_LOAD, XXX, XXX, XXX, ANY },
|
|
/* ldl */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lfr */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* lil */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lim */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lin */ { IGNORE, XXX, XXX, XXX, XXX },
|
|
/* lni */ { IGNORE, XXX, XXX, XXX, XXX },
|
|
/* loc */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* loe */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lof */ { EXPENSIVE_LOAD, XXX, XXX, XXX, ANY },
|
|
/* loi */ { EXPENSIVE_LOAD, XXX, XXX, XXX, ANY },
|
|
/* lol */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lor */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* los */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* lpb */ { UNAIR_OP, PS, XXX, PS, PTR },
|
|
/* lpi */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* lxa */ { EXPENSIVE_LOAD, XXX, XXX, XXX, PTR },
|
|
/* lxl */ { EXPENSIVE_LOAD, XXX, XXX, XXX, PTR },
|
|
/* mlf */ { BINAIR_OP, ARGW, ARGW, ARGW, FLT },
|
|
/* mli */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* mlu */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* mon */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* ngf */ { UNAIR_OP, ARGW, XXX, ARGW, FLT },
|
|
/* ngi */ { UNAIR_OP, ARGW, XXX, ARGW, ANY },
|
|
/* nop */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* rck */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* ret */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* rmi */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* rmu */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* rol */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* ror */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* rtt */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* sar */ { STORE_ARRAY, XXX, XXX, XXX, XXX },
|
|
/* sbf */ { BINAIR_OP, ARGW, ARGW, ARGW, FLT },
|
|
/* sbi */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* sbs */ { BINAIR_OP, PS, PS, ARGW, ANY },
|
|
/* sbu */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* sde */ { STORE_DIRECT, XXX, XXX, XXX, XXX },
|
|
/* sdf */ { STORE_INDIR, XXX, XXX, XXX, XXX },
|
|
/* sdl */ { STORE_DIRECT, XXX, XXX, XXX, XXX },
|
|
/* set */ { UNAIR_OP, WS, XXX, ARGW, ANY },
|
|
/* sig */ { FIDDLE_STACK, XXX, XXX, XXX, XXX },
|
|
/* sil */ { STORE_INDIR, XXX, XXX, XXX, XXX },
|
|
/* sim */ { STORE_DIRECT, XXX, XXX, XXX, XXX },
|
|
/* sli */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* slu */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* sri */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* sru */ { BINAIR_OP, ARGW, WS, ARGW, ANY },
|
|
/* ste */ { STORE_DIRECT, XXX, XXX, XXX, XXX },
|
|
/* stf */ { STORE_INDIR, XXX, XXX, XXX, XXX },
|
|
/* sti */ { STORE_INDIR, XXX, XXX, XXX, XXX },
|
|
/* stl */ { STORE_DIRECT, XXX, XXX, XXX, XXX },
|
|
/* str */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* sts */ { HOPELESS, XXX, XXX, XXX, XXX },
|
|
/* teq */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* tge */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* tgt */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* tle */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* tlt */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* tne */ { UNAIR_OP, WS, XXX, WS, ANY },
|
|
/* trp */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* xor */ { BINAIR_OP, ARGW, ARGW, ARGW, ANY },
|
|
/* zeq */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zer */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* zge */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zgt */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zle */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zlt */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zne */ { BBLOCK_END, XXX, XXX, XXX, XXX },
|
|
/* zre */ { KILL_ENTITY, XXX, XXX, XXX, XXX },
|
|
/* zrf */ { SIMPLE_LOAD, XXX, XXX, XXX, XXX },
|
|
/* zrl */ { KILL_ENTITY, XXX, XXX, XXX, XXX }
|
|
};
|
|
|
|
#define GROUP(n) (info[n].i_group)
|
|
#define OP1SIZE(l) (info[INSTR(l)].i_op1)
|
|
#define OP2SIZE(l) (info[INSTR(l)].i_op2)
|
|
#define AVSIZE(l) (info[INSTR(l)].i_av)
|
|
#define REGTYPE(n) (info[n].i_regtype)
|
|
|
|
int instrgroup(line_p lnp)
|
|
{
|
|
if (INSTR(lnp) == op_lor && SHORT(lnp) == 1) {
|
|
/* We can't do anything with the stackpointer. */
|
|
return FIDDLE_STACK;
|
|
}
|
|
if (INSTR(lnp) < sp_fmnem || INSTR(lnp) > sp_lmnem) {
|
|
VI((short) INSTR(lnp));
|
|
return IGNORE;
|
|
}
|
|
return GROUP(INSTR(lnp));
|
|
}
|
|
|
|
bool stack_group(int instr)
|
|
{
|
|
/* Is this an instruction that only does something to the top of
|
|
* the stack?
|
|
*/
|
|
switch (GROUP(instr)) {
|
|
case SIMPLE_LOAD:
|
|
case EXPENSIVE_LOAD:
|
|
case LOAD_ARRAY:
|
|
case UNAIR_OP:
|
|
case BINAIR_OP:
|
|
case TERNAIR_OP:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static offset argw(line_p lnp)
|
|
{
|
|
/* Some EM-instructions have their argument either on the same line,
|
|
* or on top of the stack. We give up when the argument is on top of
|
|
* the stack.
|
|
*/
|
|
struct token dummy;
|
|
|
|
if (TYPE(lnp) != OPNO) {
|
|
return off_set(lnp);
|
|
} else {
|
|
Pop(&dummy, (offset) ws);
|
|
return UNKNOWN_SIZE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
offset op11size(line_p lnp)
|
|
{
|
|
/* Returns the size of the first argument of
|
|
* the unary operator in lnp.
|
|
*/
|
|
|
|
switch (OP1SIZE(lnp)) {
|
|
case ARGW:
|
|
return argw(lnp);
|
|
case WS:
|
|
return ws;
|
|
case PS:
|
|
return ps;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
offset op12size(line_p lnp)
|
|
{
|
|
/* Same for first of binary. */
|
|
|
|
switch (OP1SIZE(lnp)) {
|
|
case ARGW:
|
|
return argw(lnp);
|
|
case PS:
|
|
return ps;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
offset op22size(line_p lnp)
|
|
{
|
|
switch (OP2SIZE(lnp)) {
|
|
case ARGW:
|
|
return argw(lnp);
|
|
case WS:
|
|
return ws;
|
|
case PS:
|
|
return ps;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
/* Ternary operators are op_aar and conversions between types and/or sizes. */
|
|
|
|
offset op13size(line_p lnp)
|
|
{
|
|
/* When the instruction is a conversion, the size of the first
|
|
* operand is the value of the second operand.
|
|
* We only handle the most likely case, namely that the second operand
|
|
* was pushed by a loc-instruction.
|
|
*/
|
|
if (INSTR(lnp) == op_aar) return ps;
|
|
|
|
if (lnp->l_prev != (line_p) 0 &&
|
|
lnp->l_prev->l_prev != (line_p) 0 &&
|
|
INSTR(lnp->l_prev->l_prev) == op_loc
|
|
)
|
|
return off_set(lnp->l_prev->l_prev);
|
|
else
|
|
return UNKNOWN_SIZE;
|
|
}
|
|
|
|
offset op23size(line_p lnp)
|
|
{
|
|
if (INSTR(lnp) == op_aar)
|
|
return argw(lnp);
|
|
else
|
|
return ws;
|
|
}
|
|
|
|
offset op33size(line_p lnp)
|
|
{
|
|
if (INSTR(lnp) == op_aar)
|
|
return ps;
|
|
else
|
|
return ws;
|
|
}
|
|
|
|
offset avsize(line_p lnp)
|
|
{
|
|
/* Returns the size of the result of the instruction in lnp.
|
|
* If the instruction is a conversion this size is given on the stack.
|
|
* We only handle the case that this value was pushed by a loc.
|
|
*/
|
|
offset size;
|
|
|
|
switch (AVSIZE(lnp)) {
|
|
case ARGW:
|
|
return argw(lnp);
|
|
case WS:
|
|
return ws;
|
|
case PS:
|
|
return ps;
|
|
case FEF:
|
|
if ((size = argw(lnp)) != UNKNOWN_SIZE)
|
|
return size + ws;
|
|
else
|
|
return UNKNOWN_SIZE;
|
|
case FIF:
|
|
if ((size = argw(lnp)) != UNKNOWN_SIZE)
|
|
return size + size;
|
|
else
|
|
return UNKNOWN_SIZE;
|
|
case CVT:
|
|
if (lnp->l_prev != (line_p) 0 &&
|
|
INSTR(lnp->l_prev) == op_loc
|
|
)
|
|
return off_set(lnp->l_prev);
|
|
else
|
|
return UNKNOWN_SIZE;
|
|
default:
|
|
assert(FALSE);
|
|
break;
|
|
}
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
int regtype(byte instr)
|
|
{
|
|
switch (REGTYPE(instr & BMASK)) {
|
|
case ANY:
|
|
return reg_any;
|
|
case PTR:
|
|
return reg_pointer;
|
|
case FLT:
|
|
return reg_float;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|