home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff384.lzh
/
NorthC
/
Example2.LZH
/
top
/
data.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-30
|
9KB
|
356 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
/*
* Routines for data flow analysis of a single instruction
*/
#include "top.h"
/*
* idata
*
* For each instruction, we have some global information, as well
* as flags indicating what the instruction does with its operands.
* We need to know if each operand is set and/or referenced. If the
* instruction has side-effects not directly related to its operands,
* we need to know that as well, so "special case" code can deal with
* that as well.
*/
struct idata {
char iflag; /* flags regarding the entire instruction */
#define SIDE 0x01 /* inst. has side-effects */
#define CC 0x02 /* inst. munges condition codes */
char op1f; /* flags for the first and second operands */
char op2f;
#define SET 0x01 /* operand is set */
#define REF 0x02 /* operand is referenced */
} idata[] =
{
{ CC, REF, REF|SET }, /* OR */
{ CC, REF, REF }, /* BTST */
{ 0, REF, SET }, /* MOVEP */
{ CC, REF, REF|SET }, /* BCHG */
{ CC, REF, REF|SET }, /* BCLR */
{ CC, REF, REF|SET }, /* BSET */
{ CC, REF, REF|SET }, /* AND */
{ CC, REF, REF|SET }, /* SUB */
{ CC, REF, REF|SET }, /* ADD */
{ CC, REF, REF|SET }, /* EOR */
{ CC, REF, REF }, /* CMP */
{ CC, REF, SET }, /* MOVE */
{ CC, REF|SET, 0 }, /* NEGX */
{ CC, REF, REF }, /* CHK */
{ 0, REF, SET }, /* LEA */
{ CC, SET, 0 }, /* CLR */
{ CC, REF|SET, 0 }, /* NEG */
{ CC, REF|SET, 0 }, /* NOT */
{ CC, REF|SET, 0 }, /* NBCD */
{ CC, REF|SET, 0 }, /* SWAP */
{ SIDE, REF, 0 }, /* PEA */
{ CC, REF|SET, 0 }, /* EXT */
{ SIDE, REF, SET }, /* MOVEM */
{ CC, REF, 0 }, /* TST */
{ CC, REF|SET, 0 }, /* TAS */
{ 0, REF, 0 }, /* TRAP */
{ SIDE, REF|SET, REF }, /* LINK */
{ SIDE, REF|SET, 0 }, /* UNLK */
{ 0, 0, 0 }, /* RESET */
{ 0, 0, 0 }, /* NOP */
{ CC, REF, 0 }, /* STOP */
{ SIDE|CC, 0, 0 }, /* RTE */
{ SIDE, 0, 0 }, /* RTS */
{ 0, 0, 0 }, /* TRAPV */
{ SIDE|CC, 0, 0 }, /* RTR */
{ SIDE, REF, 0 }, /* JSR */
{ 0, REF, 0 }, /* JMP */
{ CC, REF, REF|SET }, /* ADDQ */
{ 0, SET, 0 }, /* ST */
{ CC, REF|SET, REF }, /* DBT */
{ CC, REF, REF|SET }, /* SUBQ */
{ 0, SET, 0 }, /* SF */
{ CC, REF|SET, REF }, /* DBRA (dbf) */
{ 0, SET, 0 }, /* SHI */
{ CC, REF|SET, REF }, /* DBHI */
{ 0, SET, 0 }, /* SLS */
{ CC, REF|SET, REF }, /* DBLS */
{ 0, SET, 0 }, /* SCC */
{ CC, REF|SET, REF }, /* DBCC */
{ 0, SET, 0 }, /* SCS */
{ CC, REF|SET, REF }, /* DBCS */
{ 0, SET, 0 }, /* SNE */
{ CC, REF|SET, REF }, /* DBNE */
{ 0, SET, 0 }, /* SEQ */
{ CC, REF|SET, REF }, /* DBEQ */
{ 0, SET, 0 }, /* SVC */
{ CC, REF|SET, REF }, /* DBVC */
{ 0, SET, 0 }, /* SVS */
{ CC, REF|SET, REF }, /* DBVS */
{ 0, SET, 0 }, /* SPL */
{ 0, SET, 0 }, /* SMI */
{ CC, REF|SET, REF }, /* DBMI */
{ 0, SET, 0 }, /* SGE */
{ CC, REF|SET, REF }, /* DBGE */
{ 0, SET, 0 }, /* SLT */
{ CC, REF|SET, REF }, /* DBLT */
{ 0, SET, 0 }, /* SGT */
{ CC, REF|SET, REF }, /* DBGT */
{ 0, SET, 0 }, /* SLE */
{ CC, REF|SET, REF }, /* DBLE */
{ 0, REF, 0 }, /* BRA */
{ SIDE, REF, 0 }, /* BSR */
{ 0, REF, 0 }, /* BHI */
{ 0, REF, 0 }, /* BLS */
{ 0, REF, 0 }, /* BCC */
{ 0, REF, 0 }, /* BCS */
{ 0, REF, 0 }, /* BNE */
{ 0, REF, 0 }, /* BEQ */
{ 0, REF, 0 }, /* BVC */
{ 0, REF, 0 }, /* BVS */
{ 0, REF, 0 }, /* BPL */
{ 0, REF, 0 }, /* BMI */
{ 0, REF, 0 }, /* BGE */
{ 0, REF, 0 }, /* BLT */
{ 0, REF, 0 }, /* BGT */
{ 0, REF, 0 }, /* BLE */
{ CC, REF, SET }, /* MOVEQ */
{ CC, REF, REF|SET }, /* DIVU */
{ CC, REF, REF|SET }, /* SBCD */
{ CC, REF, REF|SET }, /* DIVS */
{ CC, REF, REF|SET }, /* SUBX */
{ CC, REF, REF }, /* CMPM */
{ CC, REF, REF|SET }, /* MULU */
{ CC, REF, REF|SET }, /* ABCD */
{ 0, REF|SET, REF|SET }, /* EXG */
{ CC, REF, REF|SET }, /* MULS */
{ CC, REF, REF|SET }, /* ADDX */
{ CC, REF, REF|SET }, /* ASR */
{ CC, REF, REF|SET }, /* LSR */
{ CC, REF, REF|SET }, /* ROXR */
{ CC, REF, REF|SET }, /* ROR */
{ CC, REF, REF|SET }, /* ASL */
{ CC, REF, REF|SET }, /* LSL */
{ CC, REF, REF|SET }, /* ROXL */
{ CC, REF, REF|SET }, /* ROL */
{ 0, 0, 0 }, /* DC */
{ 0, 0, 0 }, /* XREF */
{ 0, 0, 0 }, /* XDEF */
};
/*
* chkset(op) - check to see if operand 'op' sets a register
*
* This given operand is set by an instruction. Depending on the
* addressing mode used, this may set a register. If so, return
* an appropriate mask. This only happens with register direct
* addressing.
*/
int
chkset(op)
struct opnd *op;
{
switch (M(op->amode)) {
case REG:
return RM(op->areg);
case REGI:
if (op->amode & (INC|DEC))
return RM(op->areg);
else
return 0;
default:
return 0;
}
}
/*
* chkref(op) - check to see if operand 'op' references a register
*
* Checks for register references in source or destination
* operands, since they can occur in either.
*/
int
chkref(op, is_src)
struct opnd *op;
bool is_src; /* is the operand a source? */
{
switch (M(op->amode)) {
case NONE:
case IMM:
case ABS:
case PCD:
return 0;
case REG:
if (is_src)
return RM(op->areg);
else
return 0;
case REGI:
case REGID:
return RM(op->areg);
case REGIDX:
return (RM(op->areg) | RM(op->ireg));
case PCDX:
return RM(op->ireg);
default:
fprintf(stderr, "illegal mode in chkref() %d\n", M(op->amode));
exit(EXIT_FAILURE);
}
}
/*
* chkside(ip, type) - check for side-effects of 'ip'
*
* Return a mask of registers set or referenced (depending on 'type')
* by the given instruction. For example, "pea" sets and references
* the stack pointer.
*/
int
chkside(ip, type)
INST *ip;
int type;
{
switch (ip->opcode) {
case PEA: /* refs/sets the stack pointer */
return RM(SP);
case LINK: /* refs/sets SP */
return RM(SP);
case UNLK:
if (type == SET)
return RM(SP);
else
return 0;
case RTE:
case RTS:
case RTR:
return RM(SP);
case JSR:
case BSR:
/*
* We have to account, here, for what the called
* routine might do. Registers D0-3 and A0-3 may
* be munged.
*/
if (type == SET)
return RM(A0)|RM(A1)|RM(A2)|RM(A3)|
RM(D0)|RM(D1)|RM(D2)|RM(D3)|RM(SP);
else
return RM(SP);
case MOVEM:
/*
* We should really check for a register mask spec.
* here and parse it. The simple solution is to assume
* that all the registers used for register variables
* are referenced or modified.
*/
return RM(A4)|RM(A5)|RM(A7)|RM(D4)|RM(D5)|RM(D6)|RM(D7);
default:
fprintf(stderr, "chkside() - unknown opcode\n");
exit(EXIT_FAILURE);
}
}
/*
* reg_set(ip) - return mask of regs set by 'ip'
*/
int
reg_set(ip)
INST *ip;
{
int mask = 0; /* build up a register mask */
if (idata[ip->opcode].op1f & SET)
mask |= chkset(&ip->src);
if (idata[ip->opcode].op1f & REF) {
if ((ip->src.amode & (INC|DEC)) != 0)
mask |= RM(ip->src.areg);
}
if (idata[ip->opcode].op2f & SET)
mask |= chkset(&ip->dst);
if (idata[ip->opcode].op2f & REF) {
if ((ip->dst.amode & (INC|DEC)) != 0)
mask |= RM(ip->dst.areg);
}
if (idata[ip->opcode].iflag & SIDE)
mask |= chkside(ip, SET);
return mask;
}
/*
* reg_ref(ip) - return mask of regs referenced by 'ip'
*/
int
reg_ref(ip)
INST *ip;
{
int mask = 0; /* build up a register mask */
mask |= chkref(&ip->src, idata[ip->opcode].op1f & REF);
mask |= chkref(&ip->dst, idata[ip->opcode].op2f & REF);
if (idata[ip->opcode].iflag & SIDE)
mask |= chkside(ip, REF);
return mask;
}
/*
* sets(ip, reg) - is 'reg' set by the instruction 'ip'?
*/
bool
sets(ip, reg)
INST *ip;
int reg;
{
return ((reg_set(ip) & RM(reg)) != 0);
}
/*
* refs(ip, reg) - is 'reg' referenced by the instruction 'ip'?
*/
bool
refs(ip, reg)
INST *ip;
int reg;
{
return ((reg_ref(ip) & RM(reg)) != 0);
}
/*
* uses(ip, ref) - is 'reg' used by the instruction 'ip'?
*/
bool
uses(ip, reg)
INST *ip;
int reg;
{
return sets(ip, reg) || refs(ip, reg);
}