+/*****************************************************************************/
+/* nega optimizations */
+/*****************************************************************************/
+
+
+
+static unsigned OptNegA1 (CodeSeg* S)
+/* Check for
+ *
+ * ldx #$00
+ * lda ..
+ * jsr bnega
+ *
+ * Remove the ldx if the lda does not use it.
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for a ldx */
+ if (E->OPC == OPC_LDX &&
+ E->AM == AM_IMM &&
+ (E->Flags & CEF_NUMARG) != 0 &&
+ E->Num == 0 &&
+ GetCodeEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OPC_LDA &&
+ (L[0]->Use & REG_X) == 0 &&
+ L[1]->OPC == OPC_JSR &&
+ strcmp (L[1]->Arg, "bnega") == 0) {
+
+ /* Remove the ldx instruction */
+ DelCodeEntry (S, I);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptNegA2 (CodeSeg* S)
+/* Check for
+ *
+ * lda ..
+ * jsr bnega
+ * jeq/jne ..
+ *
+ * Adjust the conditional branch and remove the call to the subroutine.
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OPC_LDA &&
+ GetCodeEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OPC_JSR &&
+ strcmp (L[0]->Arg, "bnega") == 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ (L[1]->Info & OF_ZBRA) != 0) {
+
+ /* Invert the branch */
+ ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+
+ /* Delete the subroutine call */
+ DelCodeEntry (S, I+1);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* negax optimizations */
+/*****************************************************************************/
+
+
+
+static unsigned OptNegAX1 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * lda (xx),y
+ * tax
+ * dey
+ * lda (xx),y
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda (xx),y
+ * dey
+ * ora (xx),y
+ * jeq/jne ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[5];
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OPC_LDA &&
+ E->AM == AM_ZP_INDY &&
+ GetCodeEntries (S, L, I+1, 5) &&
+ L[0]->OPC == OPC_TAX &&
+ L[1]->OPC == OPC_DEY &&
+ L[2]->OPC == OPC_LDA &&
+ L[2]->AM == AM_ZP_INDY &&
+ strcmp (L[2]->Arg, E->Arg) == 0 &&
+ !CodeEntryHasLabel (L[2]) &&
+ L[3]->OPC == OPC_JSR &&
+ strcmp (L[3]->Arg, "bnegax") == 0 &&
+ !CodeEntryHasLabel (L[3]) &&
+ (L[4]->Info & OF_ZBRA) != 0) {
+
+ /* lda --> ora */
+ ReplaceOPC (L[2], OPC_ORA);
+
+ /* Invert the branch */
+ ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
+
+ /* Delete the entries no longer needed. Beware: Deleting entries
+ * will change the indices.
+ */
+ DelCodeEntry (S, I+4); /* jsr bnegax */
+ DelCodeEntry (S, I+1); /* tax */
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptNegAX2 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * lda xx
+ * ldx yy
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda xx
+ * ora xx+1
+ * jeq/jne ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[3];
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OPC_LDA &&
+ GetCodeEntries (S, L, I+1, 3) &&
+ L[0]->OPC == OPC_LDX &&
+ !CodeEntryHasLabel (L[0]) &&
+ L[1]->OPC == OPC_JSR &&
+ strcmp (L[1]->Arg, "bnegax") == 0 &&
+ !CodeEntryHasLabel (L[1]) &&
+ (L[2]->Info & OF_ZBRA) != 0) {
+
+ /* ldx --> ora */
+ ReplaceOPC (L[0], OPC_ORA);
+
+ /* Invert the branch */
+ ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
+
+ /* Delete the subroutine call */
+ DelCodeEntry (S, I+2);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptNegAX3 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * jsr _xxx
+ * jsr bnega(x)
+ * jeq/jne ...
+ *
+ * and replace it by:
+ *
+ * jsr _xxx
+ * <boolean test>
+ * jne/jeq ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OPC_JSR &&
+ E->Arg[0] == '_' &&
+ GetCodeEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OPC_JSR &&
+ strncmp (L[0]->Arg,"bnega",5) == 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ (L[1]->Info & OF_ZBRA) != 0) {
+
+ /* Check if we're calling bnega or bnegax */
+ int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
+
+ /* Delete the subroutine call */
+ DelCodeEntry (S, I+1);
+
+ /* Insert apropriate test code */
+ if (ByteSized) {
+ /* Test bytes */
+ InsertCodeEntry (S, NewCodeEntry (OPC_TAX, AM_IMP, 0, 0), I+1);
+ } else {
+ /* Test words */
+ InsertCodeEntry (S, NewCodeEntry (OPC_STX, AM_ZP, "tmp1", 0), I+1);
+ InsertCodeEntry (S, NewCodeEntry (OPC_ORA, AM_ZP, "tmp1", 0), I+2);
+ }
+
+ /* Invert the branch */
+ ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/* Optimize jump targets */
{ OptJumpTarget, "OptJumpTarget", 0 },
/* Optimize conditional branches */
- { OptCondBranches, "OptCondBranches", 0 },
+ { OptCondBranches, "OptCondBranches", 0 },
+ /* Replace jumps to RTS by RTS */
+ { OptRTSJumps, "OptRTSJumps", 0 },
/* Remove calls to the bool transformer subroutines */
{ OptBoolTransforms, "OptBoolTransforms", 0 },
+ /* Optimize calls to nega */
+ { OptNegA1, "OptNegA1", 0 },
+ /* Optimize calls to nega */
+ { OptNegA2, "OptNegA2", 0 },
+ /* Optimize calls to negax */
+ { OptNegAX1, "OptNegAX1", 0 },
+ /* Optimize calls to negax */
+ { OptNegAX2, "OptNegAX2", 0 },
+ /* Optimize calls to negax */
+ { OptNegAX3, "OptNegAX3", 0 },
/* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 },
/* Optimize branch distance */
-/* Mapper table, mnemonic --> opcode */
-static const OPCDesc OPCTable[OPC_COUNT] = {
- { OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
- { OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
- { OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
- { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
- { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
- { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_CPX, "cpx", 0, REG_X, REG_NONE, OF_NONE },
- { OPC_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
- { OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
- { OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
- { OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
- { OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
- { OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
- { OPC_INA, "ina", 1, REG_A, REG_A, OF_NONE },
- { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
- { OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
- { OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
- { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA },
- { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
- { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
- { OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
- { OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
- { OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
- { OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
- { OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
- { OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
- { OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
- { OPC_PHY, "phy", 1, REG_Y, REG_NONE, OF_NONE },
- { OPC_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
- { OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
- { OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
- { OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
- { OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
- { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
- { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
- { OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
- { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_STA, "sta", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
- { OPC_STY, "sty", 0, REG_Y, REG_NONE, OF_NONE },
- { OPC_TAX, "tax", 1, REG_A, REG_X, OF_NONE },
- { OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
- { OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_TSB, "tsb", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_TSX, "tsx", 1, REG_NONE, REG_X, OF_NONE },
- { OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
- { OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
- { OPC_TYA, "tya", 1, REG_A, REG_A, OF_NONE },
+/* Opcode description table */
+const OPCDesc OPCTable[OPC_COUNT] = {
+ { OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
+ { OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
+ { OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
+ { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA },
+ { OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
+ { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA },
+ { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
+ { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
+ { OPC_CPX, "cpx", 0, REG_X, REG_NONE, OF_NONE },
+ { OPC_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
+ { OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
+ { OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
+ { OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
+ { OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
+ { OPC_INA, "ina", 1, REG_A, REG_A, OF_NONE },
+ { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
+ { OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
+ { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA },
+ { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA },
+ { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA },
+ { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
+ { OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
+ { OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
+ { OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
+ { OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
+ { OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
+ { OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
+ { OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
+ { OPC_PHY, "phy", 1, REG_Y, REG_NONE, OF_NONE },
+ { OPC_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
+ { OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
+ { OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
+ { OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
+ { OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
+ { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
+ { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
+ { OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
+ { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_STA, "sta", 0, REG_A, REG_NONE, OF_NONE },
+ { OPC_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
+ { OPC_STY, "sty", 0, REG_Y, REG_NONE, OF_NONE },
+ { OPC_TAX, "tax", 1, REG_A, REG_X, OF_NONE },
+ { OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
+ { OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
+ { OPC_TSB, "tsb", 0, REG_A, REG_NONE, OF_NONE },
+ { OPC_TSX, "tsx", 1, REG_NONE, REG_X, OF_NONE },
+ { OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
+ { OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
+ { OPC_TYA, "tya", 1, REG_A, REG_A, OF_NONE },
};
-const OPCDesc* GetOPCDesc (opc_t OPC)
-/* Get an opcode description */
-{
- /* Check the range */
- PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
-
- /* Return the description */
- return &OPCTable [OPC];
-}
-
-
-
-unsigned char GetOPCInfo (opc_t OPC)
-/* Get opcode information */
-{
- /* Check the range */
- PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
-
- /* Return the info */
- return OPCTable[OPC].Info;
-}
-
-
-
unsigned char GetAMUseInfo (am_t AM)
/* Get usage info for the given addressing mode (addressing modes that use
* index registers return REG_r info for these registers).