/* $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 #include #include #include #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; }