home *** CD-ROM | disk | FTP | other *** search
- /* 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);
- }
-