ack/util/ego/cs/cs_partit.c
2015-06-24 23:41:47 +01:00

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;
}