+/*****************************************************************************/
+/* Macros */
+/*****************************************************************************/
+
+
+
+/* Macro to increment and decrement register contents if they're valid */
+#define INC(reg,val) if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
+#define DEC(reg,val) if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
+
+
+
+/*****************************************************************************/
+/* Helpers */
+/*****************************************************************************/
+
+
+
+static int IsKnownImm (const CodeEntry* E)
+/* Return true if the argument of E is a known immediate value */
+{
+ return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
+}
+
+
+
/*****************************************************************************/
/* Replace jumps to RTS by RTS */
/*****************************************************************************/
/* Check which sort of load or transfer it is */
unsigned R;
switch (E->OPC) {
- case OP65_TXA:
- case OP65_TYA:
- case OP65_LDA: R = REG_A; break;
- case OP65_TAX:
+ case OP65_TXA:
+ case OP65_TYA:
+ case OP65_LDA: R = REG_A; break;
+ case OP65_TAX:
case OP65_LDX: R = REG_X; break;
- case OP65_TAY:
- case OP65_LDY: R = REG_Y; break;
- default: goto NextEntry; /* OOPS */
+ case OP65_TAY:
+ case OP65_LDY: R = REG_Y; break;
+ default: goto NextEntry; /* OOPS */
}
/* Get register usage and check if the register value is used later */
if ((GetRegInfo (S, I+1) & R) == 0) {
- /* Register value is not used, remove the load */
+ /* Register value is not used, remove the load */
CS_DelEntry (S, I);
/* Remember, we had changes */
}
NextEntry:
- /* Next entry */
- ++I;
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptDuplicateLoads (CodeSeg* S)
+/* Remove loads of registers where the value loaded is already in the register. */
+{
+ unsigned Changes = 0;
+
+ /* Remember the last load instructions for all registers */
+ int RegA = -1;
+ int RegX = -1;
+ int RegY = -1;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ unsigned char Use, Chg;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Assume we won't delete the entry */
+ int Delete = 0;
+
+ /* If this entry has a label attached, remove all knownledge about the
+ * register contents. This may be improved but for now it's ok.
+ */
+ if (CE_HasLabel (E)) {
+ RegA = RegX = RegY = -1;
+ }
+
+ /* Handle the different instructions */
+ switch (E->OPC) {
+
+ case OP65_ADC:
+ /* We don't know the value of the carry, so the result is
+ * always unknown.
+ */
+ RegA = -1;
+ break;
+
+ case OP65_AND:
+ if (RegA >= 0) {
+ if (IsKnownImm (E)) {
+ RegA &= (int) E->Num;
+ } else {
+ RegA = -1;
+ }
+ }
+ break;
+
+ case OP65_ASL:
+ if (RegA >= 0) {
+ RegA = (RegA << 1) & 0xFF;
+ }
+ break;
+
+ case OP65_BCC:
+ break;
+
+ case OP65_BCS:
+ break;
+
+ case OP65_BEQ:
+ break;
+
+ case OP65_BIT:
+ break;
+
+ case OP65_BMI:
+ break;
+
+ case OP65_BNE:
+ break;
+
+ case OP65_BPL:
+ break;
+
+ case OP65_BRA:
+ break;
+
+ case OP65_BRK:
+ break;
+
+ case OP65_BVC:
+ break;
+
+ case OP65_BVS:
+ break;
+
+ case OP65_CLC:
+ break;
+
+ case OP65_CLD:
+ break;
+
+ case OP65_CLI:
+ break;
+
+ case OP65_CLV:
+ break;
+
+ case OP65_CMP:
+ break;
+
+ case OP65_CPX:
+ break;
+
+ case OP65_CPY:
+ break;
+
+ case OP65_DEA:
+ DEC (RegA, 1);
+ break;
+
+ case OP65_DEC:
+ break;
+
+ case OP65_DEX:
+ DEC (RegX, 1);
+ break;
+
+ case OP65_DEY:
+ DEC (RegY, 1);
+ break;
+
+ case OP65_EOR:
+ if (RegA >= 0) {
+ if (IsKnownImm (E)) {
+ RegA ^= (int) E->Num;
+ } else {
+ RegA = -1;
+ }
+ }
+ break;
+
+ case OP65_INA:
+ INC (RegA, 1);
+ break;
+
+ case OP65_INC:
+ break;
+
+ case OP65_INX:
+ INC (RegX, 1);
+ break;
+
+ case OP65_INY:
+ INC (RegY, 1);
+ break;
+
+ case OP65_JCC:
+ break;
+
+ case OP65_JCS:
+ break;
+
+ case OP65_JEQ:
+ break;
+
+ case OP65_JMI:
+ break;
+
+ case OP65_JMP:
+ break;
+
+ case OP65_JNE:
+ break;
+
+ case OP65_JPL:
+ break;
+
+ case OP65_JSR:
+ /* Get the code info for the function */
+ GetFuncInfo (E->Arg, &Use, &Chg);
+ if (Chg & REG_A) {
+ RegA = -1;
+ }
+ if (Chg & REG_X) {
+ RegX = -1;
+ }
+ if (Chg & REG_Y) {
+ RegY = -1;
+ }
+ break;
+
+ case OP65_JVC:
+ break;
+
+ case OP65_JVS:
+ break;
+
+ case OP65_LDA:
+ if (IsKnownImm (E)) {
+ CodeEntry* N = CS_GetNextEntry (S, I);
+ if (RegA >= 0 && RegA == E->Num && N && (N->Info & OF_FBRA) == 0) {
+ Delete = 1;
+ } else {
+ RegA = (unsigned char) E->Num;
+ }
+ } else {
+ /* A is now unknown */
+ RegA = -1;
+ }
+ break;
+
+ case OP65_LDX:
+ if (IsKnownImm (E)) {
+ CodeEntry* N = CS_GetNextEntry (S, I);
+ if (RegX >= 0 && RegX == E->Num && N && (N->Info & OF_FBRA) == 0) {
+ Delete = 1;
+ } else {
+ RegX = (unsigned char) E->Num;
+ }
+ } else {
+ /* X is now unknown */
+ RegX = -1;
+ }
+ break;
+
+ case OP65_LDY:
+ if (IsKnownImm (E)) {
+ CodeEntry* N = CS_GetNextEntry (S, I);
+ if (RegY >= 0 && RegY == E->Num && N && (N->Info & OF_FBRA) == 0) {
+ Delete = 1;
+ } else {
+ RegY = (unsigned char) E->Num;
+ }
+ } else {
+ /* Y is now unknown */
+ RegY = -1;
+ }
+ break;
+
+ case OP65_LSR:
+ if (RegA >= 0) {
+ RegA = (RegA >> 1) & 0xFF;
+ }
+ break;
+
+ case OP65_NOP:
+ break;
+
+ case OP65_ORA:
+ if (RegA >= 0) {
+ if (IsKnownImm (E)) {
+ RegA |= (unsigned char) E->Num;
+ } else {
+ /* A is now unknown */
+ RegA = -1;
+ }
+ }
+ break;
+
+ case OP65_PHA:
+ break;
+
+ case OP65_PHP:
+ break;
+
+ case OP65_PHX:
+ break;
+
+ case OP65_PHY:
+ break;
+
+ case OP65_PLA:
+ RegA = -1;
+ break;
+
+ case OP65_PLP:
+ break;
+
+ case OP65_PLX:
+ RegX = -1;
+ break;
+
+ case OP65_PLY:
+ RegY = -1;
+ break;
+
+ case OP65_ROL:
+ RegA = -1;
+ break;
+
+ case OP65_ROR:
+ RegA = -1;
+ break;
+
+ case OP65_RTI:
+ break;
+
+ case OP65_RTS:
+ break;
+
+ case OP65_SBC:
+ RegA = -1;
+ break;
+
+ case OP65_SEC:
+ break;
+
+ case OP65_SED:
+ break;
+
+ case OP65_SEI:
+ break;
+
+ case OP65_STA:
+ break;
+
+ case OP65_STX:
+ /* If the value in the X register is known and the same as
+ * that in the A register, replace the store by a STA. The
+ * optimizer will then remove the load instruction for X
+ * later. STX does support the zeropage,y addressing mode,
+ * so be sure to check for that.
+ */
+ if (RegX >= 0 && RegX == RegA &&
+ E->AM != AM65_ABSY && E->AM != AM65_ZPY) {
+ /* Use the A register instead */
+ CE_ReplaceOPC (E, OP65_STA);
+ }
+ break;
+
+ case OP65_STY:
+ /* If the value in the Y register is known and the same as
+ * that in the A register, replace the store by a STA. The
+ * optimizer will then remove the load instruction for Y
+ * later.
+ */
+ if (RegY >= 0 && RegY == RegA) {
+ CE_ReplaceOPC (E, OP65_STA);
+ }
+ break;
+
+ case OP65_TAX:
+ RegX = RegA;
+ break;
+
+ case OP65_TAY:
+ RegY = RegA;
+ break;
+
+ case OP65_TRB:
+ break;
+
+ case OP65_TSB:
+ break;
+
+ case OP65_TSX:
+ RegX = -1;
+ break;
+
+ case OP65_TXA:
+ RegA = RegX;
+ break;
+
+ case OP65_TXS:
+ break;
+
+ case OP65_TYA:
+ RegA = RegY;
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Delete the entry if requested */
+ if (Delete) {
+
+ /* Register value is not used, remove the load */
+ CS_DelEntry (S, I);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ } else {
+
+ /* Next entry */
+ ++I;
+
+ }
}
unsigned J = I;
while (J < TI) {
CodeEntry* N = CS_GetEntry (S, J++);
- Distance += N->Size;
+ Distance += N->Size;
}
} else {
/* Backward branch */