+/* 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), 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]) &&
+ L[1]->OPC == OPC_CPX &&
+ L[1]->AM == AM_IMM &&
+ (L[1]->Flags & CEF_NUMARG) != 0 &&
+ !CodeEntryHasLabel (L[1]) &&
+ (L[2]->OPC == OPC_JNE || L[2]->OPC == OPC_BNE) &&
+ L[2]->JumpTo != 0 &&
+ !CodeEntryHasLabel (L[2]) &&
+ L[3]->OPC == OPC_CMP &&
+ L[3]->AM == AM_IMM &&
+ (L[3]->Flags & CEF_NUMARG) != 0 &&
+ (L[4]->Info & OF_ZBRA) != 0 &&
+ L[4]->JumpTo != 0 &&
+ (L[2]->JumpTo->Owner == L[4] || L[2]->JumpTo == L[4]->JumpTo)) {
+
+ /* Get the compare value */
+ unsigned Val = ((L[1]->Num & 0xFF) << 8) | (L[3]->Num & 0xFF);
+
+ if (Val == 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 */
+ CodeEntry* N = RetrieveCodeEntry (S, I);
+ InsertCodeEntry (S, N, I+3);
+
+ /* Replace the ldx/cpx by lda/cmp */
+ ReplaceOPC (L[0], OPC_LDA);
+ ReplaceOPC (L[1], OPC_CMP);
+
+ /* The high byte is zero, remove the CMP */
+ if ((Val & 0xFF00) == 0) {
+ DelCodeEntry (S, I+1);
+ }
+ }
+
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* nega optimizations */