369 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			369 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/utils.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 */
 | 
						|
}
 |