/*****************************************************************************/
-/* Helper functions */
+/* Helper functions */
/*****************************************************************************/
-static cmp_t FindCmpCond (const char* Suffix)
-/* Map a condition suffix to a code. Return the code or CMP_INV on failure */
+static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
+/* Search for a compare condition by the given code using the given length */
{
- int I;
+ unsigned I;
/* Linear search */
for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
- if (strcmp (Suffix, CmpSuffixTab [I]) == 0) {
+ if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
/* Found */
- return I;
- }
+ return I;
+ }
}
/* Not found */
+static cmp_t FindBoolCmpCond (const char* Name)
+/* Map a condition suffix to a code. Return the code or CMP_INV on failure */
+{
+ /* Check for the correct subroutine name */
+ if (strncmp (Name, "bool", 4) == 0) {
+ /* Name is ok, search for the code in the table */
+ return FindCmpCond (Name+4, strlen(Name)-4);
+ } else {
+ /* Not found */
+ return CMP_INV;
+ }
+}
+
+
+
+static cmp_t FindTosCmpCond (const char* Name)
+/* Check if this is a call to one of the TOS compare functions (tosgtax).
+ * Return the condition code or CMP_INV on failure.
+ */
+{
+ unsigned Len = strlen (Name);
+
+ /* Check for the correct subroutine name */
+ if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
+ /* Name is ok, search for the code in the table */
+ return FindCmpCond (Name+3, Len-3-2);
+ } else {
+ /* Not found */
+ return CMP_INV;
+ }
+}
+
+
+
+static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
+/* Helper function for the replacement of routines that return a boolean
+ * followed by a conditional jump. Instead of the boolean value, the condition
+ * codes are evaluated directly.
+ * I is the index of the conditional branch, the sequence is already checked
+ * to be correct.
+ */
+{
+ CodeEntry* N;
+ CodeLabel* L;
+
+ /* Get the entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Replace the conditional branch */
+ switch (Cond) {
+
+ case CMP_EQ:
+ ReplaceOPC (E, OPC_JEQ);
+ break;
+
+ case CMP_NE:
+ ReplaceOPC (E, OPC_JNE);
+ break;
+
+ case CMP_GT:
+ /* Replace by
+ * beq @L
+ * jpl Target
+ * @L: ...
+ */
+ if ((N = GetNextCodeEntry (S, I)) == 0) {
+ /* No such entry */
+ Internal ("Invalid program flow");
+ }
+ L = GenCodeLabel (S, N);
+ N = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L, E->LI);
+ InsertCodeEntry (S, N, I);
+ ReplaceOPC (E, OPC_JPL);
+ break;
+
+ case CMP_GE:
+ ReplaceOPC (E, OPC_JPL);
+ break;
+
+ case CMP_LT:
+ ReplaceOPC (E, OPC_JMI);
+ break;
+
+ case CMP_LE:
+ /* Replace by
+ * jmi Target
+ * jeq Target
+ */
+ ReplaceOPC (E, OPC_JMI);
+ L = E->JumpTo;
+ N = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L, E->LI);
+ InsertCodeEntry (S, N, I+1);
+ break;
+
+ case CMP_UGT:
+ /* Replace by
+ * beq @L
+ * jcs Target
+ * @L: ...
+ */
+ if ((N = GetNextCodeEntry (S, I)) == 0) {
+ /* No such entry */
+ Internal ("Invalid program flow");
+ }
+ L = GenCodeLabel (S, N);
+ N = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L, E->LI);
+ InsertCodeEntry (S, N, I);
+ ReplaceOPC (E, OPC_JCS);
+ break;
+
+ case CMP_UGE:
+ ReplaceOPC (E, OPC_JCS);
+ break;
+
+ case CMP_ULT:
+ ReplaceOPC (E, OPC_JCC);
+ break;
+
+ case CMP_ULE:
+ /* Replace by
+ * jcc Target
+ * jeq Target
+ */
+ ReplaceOPC (E, OPC_JCC);
+ L = E->JumpTo;
+ N = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L, E->LI);
+ InsertCodeEntry (S, N, I+1);
+ break;
+
+ default:
+ Internal ("Unknown jump condition: %d", Cond);
+
+ }
+
+}
+
+
+
+static int IsUnsignedCmp (int Code)
+/* Check if this is an unsigned compare */
+{
+ CHECK (Code >= 0);
+ return CmpSignedTab [Code] == 0;
+}
+
+
+
+static int IsBitOp (const CodeEntry* E)
+/* Check if E is one of the bit operations (and, or, eor) */
+{
+ return (E->OPC == OPC_AND || E->OPC == OPC_ORA || E->OPC == OPC_EOR);
+}
+
+
+
+static int IsCmpToZero (const CodeEntry* E)
+/* Check if the given instrcuction is a compare to zero instruction */
+{
+ return (E->OPC == OPC_CMP &&
+ E->AM == AM_IMM &&
+ (E->Flags & CEF_NUMARG) != 0 &&
+ E->Num == 0);
+}
+
+
+
+static int IsSpLoad (const CodeEntry* E)
+/* Return true if this is the load of A from the stack */
+{
+ return E->OPC == OPC_LDA && E->AM == AM_ZP_INDY && strcmp (E->Arg, "sp") == 0;
+}
+
+
+
+static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
+ CodeEntry** L, unsigned Count)
+/* Check if a 16 bit load of a local variable follows:
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ *
+ * If so, read Count entries following the first ldy into L and return true
+ * if this is possible. Otherwise return false.
+ */
+{
+ /* Be sure we read enough entries for the check */
+ CHECK (Count >= 5);
+
+ /* Read the first entry */
+ L[0] = GetCodeEntry (S, Index);
+
+ /* Check for the sequence */
+ return (L[0]->OPC == OPC_LDY &&
+ L[0]->AM == AM_IMM &&
+ (L[0]->Flags & CEF_NUMARG) != 0 &&
+ GetCodeEntries (S, L+1, Index+1, Count-1) &&
+ IsSpLoad (L[1]) &&
+ !CodeEntryHasLabel (L[1]) &&
+ L[2]->OPC == OPC_TAX &&
+ !CodeEntryHasLabel (L[2]) &&
+ L[3]->OPC == OPC_DEY &&
+ !CodeEntryHasLabel (L[3]) &&
+ IsSpLoad (L[4]) &&
+ !CodeEntryHasLabel (L[4]));
+}
+
+
+
+static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
+/* Check if the instructions at L are an immidiate compare of a/x:
+ *
+ *
+ */
+{
+ return (L[0]->OPC == OPC_CPX &&
+ L[0]->AM == AM_IMM &&
+ (L[0]->Flags & CEF_NUMARG) != 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ (L[1]->OPC == OPC_JNE || L[1]->OPC == OPC_BNE) &&
+ L[1]->JumpTo != 0 &&
+ !CodeEntryHasLabel (L[1]) &&
+ L[2]->OPC == OPC_CMP &&
+ L[2]->AM == AM_IMM &&
+ (L[2]->Flags & CEF_NUMARG) != 0 &&
+ (L[3]->Info & OF_ZBRA) != 0 &&
+ L[3]->JumpTo != 0 &&
+ (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
+}
+
+
+
/*****************************************************************************/
-/* Remove calls to the bool transformer subroutines */
+/* Remove calls to the bool transformer subroutines */
/*****************************************************************************/
/* Check for a boolean transformer */
if (E->OPC == OPC_JSR &&
- strncmp (E->Arg, "bool", 4) == 0 &&
+ (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
(N = GetNextCodeEntry (S, I)) != 0 &&
- (N->Info & OF_ZBRA) != 0 &&
- (Cond = FindCmpCond (E->Arg+4)) != CMP_INV) {
-
- CodeEntry* X;
- CodeLabel* L;
+ (N->Info & OF_ZBRA) != 0) {
/* Make the boolean transformer unnecessary by changing the
* the conditional jump to evaluate the condition flags that
}
/* Check if we can replace the code by something better */
- switch (Cond) {
-
- case CMP_EQ:
- ReplaceOPC (N, OPC_JEQ);
- break;
-
- case CMP_NE:
- ReplaceOPC (N, OPC_JNE);
- break;
-
- case CMP_GT:
- /* Replace by
- * beq @L
- * jpl Target
- * @L: ...
- */
- if ((X = GetNextCodeEntry (S, I+1)) == 0) {
- /* No such entry */
- goto NextEntry;
- }
- L = GenCodeLabel (S, X);
- X = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L);
- InsertCodeEntry (S, X, I+1);
- ReplaceOPC (N, OPC_JPL);
- break;
-
- case CMP_GE:
- ReplaceOPC (N, OPC_JPL);
- break;
-
- case CMP_LT:
- ReplaceOPC (N, OPC_JMI);
- break;
-
- case CMP_LE:
- /* Replace by
- * jmi Target
- * jeq Target
- */
- ReplaceOPC (N, OPC_JMI);
- L = N->JumpTo;
- X = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L);
- InsertCodeEntry (S, X, I+2);
- break;
-
- case CMP_UGT:
- /* Replace by
- * beq @L
- * jcs Target
- * @L: ...
- */
- if ((X = GetNextCodeEntry (S, I+1)) == 0) {
- /* No such entry */
- goto NextEntry;
- }
- L = GenCodeLabel (S, X);
- X = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L);
- InsertCodeEntry (S, X, I+1);
- ReplaceOPC (N, OPC_JCS);
- break;
-
- case CMP_UGE:
- ReplaceOPC (N, OPC_JCS);
- break;
-
- case CMP_ULT:
- ReplaceOPC (N, OPC_JCC);
- break;
-
- case CMP_ULE:
- /* Replace by
- * jcc Target
- * jeq Target
- */
- ReplaceOPC (N, OPC_JCC);
- L = N->JumpTo;
- X = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L);
- InsertCodeEntry (S, X, I+2);
- break;
-
- default:
- Internal ("Unknown jump condition: %d", Cond);
+ ReplaceCmp (S, I+1, Cond);
+
+ /* Remove the call to the bool transformer */
+ DelCodeEntry (S, I);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* Optimize subtractions */
+/*****************************************************************************/
+
+
+
+static unsigned OptSub1 (CodeSeg* S)
+/* Search for the sequence
+ *
+ * sbc ...
+ * bcs L
+ * dex
+ * L:
+ *
+ * and remove the handling of the high byte if X is not used later.
+ */
+{
+ 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_SBC &&
+ GetCodeEntries (S, L, I+1, 3) &&
+ (L[0]->OPC == OPC_BCS || L[0]->OPC == OPC_JCS) &&
+ L[0]->JumpTo != 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ L[1]->OPC == OPC_DEX &&
+ !CodeEntryHasLabel (L[1]) &&
+ L[0]->JumpTo->Owner == L[2] &&
+ !RegXUsed (S, I+3)) {
+
+ /* Remove the bcs/dex */
+ DelCodeEntries (S, I+1, 2);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptSub2 (CodeSeg* S)
+/* Search for the sequence
+ *
+ * lda xx
+ * sec
+ * sta tmp1
+ * lda yy
+ * sbc tmp1
+ * sta yy
+ *
+ * and replace it by
+ *
+ * sec
+ * lda yy
+ * sbc xx
+ * sta yy
+ */
+{
+ 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 &&
+ GetCodeEntries (S, L, I+1, 5) &&
+ L[0]->OPC == OPC_SEC &&
+ !CodeEntryHasLabel (L[0]) &&
+ L[1]->OPC == OPC_STA &&
+ strcmp (L[1]->Arg, "tmp1") == 0 &&
+ !CodeEntryHasLabel (L[1]) &&
+ L[2]->OPC == OPC_LDA &&
+ !CodeEntryHasLabel (L[2]) &&
+ L[3]->OPC == OPC_SBC &&
+ strcmp (L[3]->Arg, "tmp1") == 0 &&
+ !CodeEntryHasLabel (L[3]) &&
+ L[4]->OPC == OPC_STA &&
+ strcmp (L[4]->Arg, L[2]->Arg) == 0 &&
+ !CodeEntryHasLabel (L[4])) {
+
+ /* Remove the store to tmp1 */
+ DelCodeEntry (S, I+2);
+
+ /* Remove the subtraction */
+ DelCodeEntry (S, I+3);
+
+ /* Move the lda to the position of the subtraction and change the
+ * op to SBC.
+ */
+ MoveCodeEntry (S, I, I+3);
+ ReplaceOPC (E, OPC_SBC);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* Optimize additions */
+/*****************************************************************************/
+
+
+
+static unsigned OptAdd1 (CodeSeg* S)
+/* Search for the sequence
+ *
+ * adc ...
+ * bcc L
+ * inx
+ * L:
+ *
+ * and remove the handling of the high byte if X is not used later.
+ */
+{
+ 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_ADC &&
+ GetCodeEntries (S, L, I+1, 3) &&
+ (L[0]->OPC == OPC_BCC || L[0]->OPC == OPC_JCC) &&
+ L[0]->JumpTo != 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ L[1]->OPC == OPC_INX &&
+ !CodeEntryHasLabel (L[1]) &&
+ L[0]->JumpTo->Owner == L[2] &&
+ !RegXUsed (S, I+3)) {
+
+ /* Remove the bcs/dex */
+ DelCodeEntries (S, I+1, 2);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* Optimizations for compares */
+/*****************************************************************************/
+
+
+
+static unsigned OptCmp1 (CodeSeg* S)
+/* Search for the sequence
+ *
+ * stx xx
+ * stx tmp1
+ * ora tmp1
+ *
+ * and replace it by
+ *
+ * stx xx
+ * ora xx
+ */
+{
+ 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_STX &&
+ GetCodeEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OPC_STX &&
+ strcmp (L[0]->Arg, "tmp1") == 0 &&
+ !CodeEntryHasLabel (L[0]) &&
+ L[1]->OPC == OPC_ORA &&
+ strcmp (L[1]->Arg, "tmp1") == 0 &&
+ !CodeEntryHasLabel (L[1])) {
+
+ /* Remove the remaining instructions */
+ DelCodeEntries (S, I+1, 2);
+
+ /* Insert the ora instead */
+ InsertCodeEntry (S, NewCodeEntry (OPC_ORA, E->AM, E->Arg, 0, E->LI), I+1);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptCmp2 (CodeSeg* S)
+/* Search for
+ *
+ * lda/and/ora/eor ...
+ * cmp #$00
+ * jeq/jne
+ *
+ * and remove the cmp.
+ */
+{
+ 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 || IsBitOp (E)) &&
+ GetCodeEntries (S, L, I+1, 2) &&
+ IsCmpToZero (L[0]) &&
+ !CodeEntryHasLabel (L[0]) &&
+ (L[1]->Info & OF_FBRA) != 0 &&
+ !CodeEntryHasLabel (L[1])) {
+
+ /* Remove the compare */
+ DelCodeEntry (S, I+1);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptCmp3 (CodeSeg* S)
+/* Search for
+ *
+ * lda x
+ * ldx y
+ * cpx #a
+ * bne L1
+ * cmp #b
+ * jne/jeq L2
+ *
+ * If a is zero, we may remove the compare. If a and b are both zero, we may
+ * replace it by the sequence
+ *
+ * lda x
+ * ora x+1
+ * jne/jeq ...
+ *
+ * L1 may be either the label at the branch instruction, or the target label
+ * of this instruction.
+ */
+{
+ 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 &&
+ GetCodeEntries (S, L, I+1, 5) &&
+ L[0]->OPC == OPC_LDX &&
+ !CodeEntryHasLabel (L[0]) &&
+ IsImmCmp16 (S, L+1)) {
+
+ if (L[1]->Num == 0 && L[3]->Num == 0) {
+ /* The value is zero, we may use the simple code version. */
+ ReplaceOPC (L[0], OPC_ORA);
+ DelCodeEntries (S, I+2, 3);
+ } else {
+ /* Move the lda instruction after the first branch. This will
+ * improve speed, since the load is delayed after the first
+ * test.
+ */
+ MoveCodeEntry (S, I, I+4);
+
+ /* We will replace the ldx/cpx by lda/cmp */
+ ReplaceOPC (L[0], OPC_LDA);
+ ReplaceOPC (L[1], OPC_CMP);
}
- /* Remove the call to the bool transformer */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptCmp4 (CodeSeg* S)
+/* Optimize compares of local variables:
+ *
+ * ldy #o
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * cpx #a
+ * bne L1
+ * cmp #b
+ * jne/jeq L2
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* L[9];
+
+ /* Check for the sequence */
+ if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
+
+ if (L[5]->Num == 0 && L[7]->Num == 0) {
+
+ /* The value is zero, we may use the simple code version:
+ * ldy #o
+ * lda (sp),y
+ * dey
+ * ora (sp),y
+ * jne/jeq ...
+ */
+ ReplaceOPC (L[4], OPC_ORA);
+ DelCodeEntries (S, I+5, 3); /* cpx/bne/cmp */
+ DelCodeEntry (S, I+2); /* tax */
+
+ } else {
+
+ /* Change the code to just use the A register. Move the load
+ * of the low byte after the first branch if possible:
+ *
+ * ldy #o
+ * lda (sp),y
+ * cmp #a
+ * bne L1
+ * dey
+ * lda (sp),y
+ * cmp #b
+ * jne/jeq ...
+ */
+ DelCodeEntry (S, I+2); /* tax */
+ ReplaceOPC (L[5], OPC_CMP); /* cpx -> cmp */
+ MoveCodeEntry (S, I+4, I+2); /* cmp */
+ MoveCodeEntry (S, I+5, I+3); /* bne */
+
+ }
+
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptCmp5 (CodeSeg* S)
+/* Search for calls to compare subroutines followed by a conditional branch
+ * and replace them by cheaper versions, since the branch means that the
+ * boolean value returned by these routines is not needed (we may also check
+ * that explicitly, but for the current code generator it is always true).
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < GetCodeEntryCount (S)) {
+
+ CodeEntry* N;
+ cmp_t Cond;
+
+ /* Get next entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OPC_JSR &&
+ (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
+ (N = GetNextCodeEntry (S, I)) != 0 &&
+ (N->Info & OF_ZBRA) != 0 &&
+ !CodeEntryHasLabel (N)) {
+
+ /* The tos... functions will return a boolean value in a/x and
+ * the Z flag says if this value is zero or not. We will call
+ * a cheaper subroutine instead, one that does not return a
+ * boolean value but only valid flags. Note: jeq jumps if
+ * the condition is not met, jne jumps if the condition is met.
+ * Invert the code if we jump on condition not met.
+ */
+ if (GetBranchCond (N->OPC) == BC_EQ) {
+ /* Jumps if condition false, invert condition */
+ Cond = CmpInvertTab [Cond];
+ }
+
+ /* Replace the subroutine call. */
+ E = NewCodeEntry (OPC_JSR, AM_ABS, "tosicmp", 0, E->LI);
+ InsertCodeEntry (S, E, I+1);
DelCodeEntry (S, I);
+ /* Replace the conditional branch */
+ ReplaceCmp (S, I+1, Cond);
+
/* Remember, we had changes */
++Changes;
}
-NextEntry:
/* Next entry */
++I;
/*****************************************************************************/
-/* nega optimizations */
+/* nega optimizations */
/*****************************************************************************/
CodeEntry* E = GetCodeEntry (S, I);
/* Check for the sequence */
- if (E->OPC == OPC_JSR &&
- E->Arg[0] == '_' &&
- GetCodeEntries (S, L, I+1, 2) &&
+ 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]) &&
+ strncmp (L[0]->Arg,"bnega",5) == 0 &&
+ !CodeEntryHasLabel (L[0]) &&
(L[1]->Info & OF_ZBRA) != 0) {
+ CodeEntry* X;
+
/* 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);
+ X = NewCodeEntry (OPC_TAX, AM_IMP, 0, 0, L[0]->LI);
+ InsertCodeEntry (S, X, I+2);
} 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);
+ X = NewCodeEntry (OPC_STX, AM_ZP, "tmp1", 0, L[0]->LI);
+ InsertCodeEntry (S, X, I+2);
+ X = NewCodeEntry (OPC_ORA, AM_ZP, "tmp1", 0, L[0]->LI);
+ InsertCodeEntry (S, X, I+3);
}
+ /* Delete the subroutine call */
+ DelCodeEntry (S, I+1);
+
/* Invert the branch */
ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
/* Table with optimizer steps - are called in this order */
static OptFunc OptFuncs [] = {
+ /* Optimize subtractions */
+ { OptSub1, "OptSub1", 0 },
+ { OptSub2, "OptSub2", 0 },
+ /* Optimize additions */
+ { OptAdd1, "OptAdd1", 0 },
/* Optimize jump cascades */
{ OptJumpCascades, "OptJumpCascades", 0 },
/* Remove dead jumps */
{ 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 },
+ /* Optimize compares */
+ { OptCmp1, "OptCmp1", 0 },
+ { OptCmp2, "OptCmp2", 0 },
+ { OptCmp3, "OptCmp3", 0 },
+ { OptCmp4, "OptCmp4", 0 },
+ { OptCmp5, "OptCmp5", 0 },
/* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 },
/* Optimize branch distance */
void DisableOpt (const char* Name)
/* Disable the optimization with the given name */
{
- OptFunc* F = FindOptStep (Name);
- F->Disabled = 1;
+ if (strcmp (Name, "any") == 0) {
+ unsigned I;
+ for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
+ OptFuncs[I].Disabled = 1;
+ }
+ } else {
+ OptFunc* F = FindOptStep (Name);
+ F->Disabled = 1;
+ }
}
void EnableOpt (const char* Name)
/* Enable the optimization with the given name */
{
- OptFunc* F = FindOptStep (Name);
- F->Disabled = 0;
+ if (strcmp (Name, "any") == 0) {
+ unsigned I;
+ for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
+ OptFuncs[I].Disabled = 0;
+ }
+ } else {
+ OptFunc* F = FindOptStep (Name);
+ F->Disabled = 0;
+ }
}