b1b737ed6c
Enable this in CS for PowerPC; disable it for all other machines. PowerPC has no remainder instruction; the back end uses division to compute remainder. If CS finds both a / b and a % b, then CS now rewrites a % b as a - b * (a / b) and computes a / b only once. This removes an extra division in the PowerPC code, so it saves both time and space. I have not considered whether to enable this optimization for other machines. It might be less useful in machines with a remainder instruction. Also, if a % b occurs before a / b, the EM code gets a DUP. PowerPC ncg handles this DUP well; other back ends might not.
370 lines
10 KiB
C
370 lines
10 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"
|
|
|
|
#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 */ REMAINDER, ARGW, ARGW, ARGW, ANY,
|
|
/* rmu */ REMAINDER, 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:
|
|
case REMAINDER:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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 */
|
|
}
|
|
|
|
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 */
|
|
}
|
|
|
|
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 */
|
|
}
|
|
|
|
/* Ternary operators are op_aar and conversions between types and/or sizes. */
|
|
|
|
offset op13size(lnp)
|
|
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(lnp)
|
|
line_p lnp;
|
|
{
|
|
if (INSTR(lnp) == op_aar)
|
|
return argw(lnp);
|
|
else
|
|
return ws;
|
|
}
|
|
|
|
offset op33size(lnp)
|
|
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 */
|
|
}
|
|
|
|
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 */
|
|
}
|