unsigned OptBNegAX3 (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 < CS_GetEntryCount (S)) { CodeEntry* L[3]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_LDA && CS_GetEntries (S, L, I+1, 3) && L[0]->OPC == OP65_LDX && !CE_HasLabel (L[0]) && CE_IsCallTo (L[1], "bnegax") && !CE_HasLabel (L[1]) && (L[2]->Info & OF_ZBRA) != 0 && !CE_HasLabel (L[2])) { /* ldx --> ora */ CE_ReplaceOPC (L[0], OP65_ORA); /* Invert the branch */ CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC)); /* Delete the subroutine call */ CS_DelEntry (S, I+2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptBNegA2 (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 < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if ((E->OPC == OP65_ADC || E->OPC == OP65_AND || E->OPC == OP65_DEA || E->OPC == OP65_EOR || E->OPC == OP65_INA || E->OPC == OP65_LDA || E->OPC == OP65_ORA || E->OPC == OP65_PLA || E->OPC == OP65_SBC || E->OPC == OP65_TXA || E->OPC == OP65_TYA) && CS_GetEntries (S, L, I+1, 2) && CE_IsCallTo (L[0], "bnega") && !CE_HasLabel (L[0]) && (L[1]->Info & OF_ZBRA) != 0 && !CE_HasLabel (L[1])) { /* Invert the branch */ CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); /* Delete the subroutine call */ CS_DelEntry (S, I+1); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
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 < CS_GetEntryCount (S)) { CodeEntry* L[5]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_LDA && !CS_RangeHasLabel (S, I+1, 5) && CS_GetEntries (S, L, I+1, 5) && L[0]->OPC == OP65_SEC && L[1]->OPC == OP65_STA && strcmp (L[1]->Arg, "tmp1") == 0 && L[2]->OPC == OP65_LDA && L[3]->OPC == OP65_SBC && strcmp (L[3]->Arg, "tmp1") == 0 && L[4]->OPC == OP65_STA && strcmp (L[4]->Arg, L[2]->Arg) == 0) { /* Remove the store to tmp1 */ CS_DelEntry (S, I+2); /* Remove the subtraction */ CS_DelEntry (S, I+3); /* Move the lda to the position of the subtraction and change the ** op to SBC. */ CS_MoveEntry (S, I, I+3); CE_ReplaceOPC (E, OP65_SBC); /* If the sequence head had a label, move this label back to the ** head. */ if (CE_HasLabel (E)) { CS_MoveLabels (S, E, L[0]); } /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptCmp9 (CodeSeg* S) /* Search for the sequence * * sbc xx * bvs/bvc L * eor #$80 * L: asl a * bcc/bcs somewhere * * If A is not used later (which should be the case), we can branch on the N * flag instead of the carry flag and remove the asl. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[5]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_SBC && CS_GetEntries (S, L+1, I+1, 4) && (L[1]->OPC == OP65_BVC || L[1]->OPC == OP65_BVS) && L[1]->JumpTo != 0 && L[1]->JumpTo->Owner == L[3] && L[2]->OPC == OP65_EOR && CE_IsKnownImm (L[2], 0x80) && L[3]->OPC == OP65_ASL && L[3]->AM == AM65_ACC && (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_BCS || L[4]->OPC == OP65_JCC || L[4]->OPC == OP65_JCS) && !CE_HasLabel (L[4]) && !RegAUsed (S, I+4)) { /* Replace the branch condition */ switch (GetBranchCond (L[4]->OPC)) { case BC_CC: CE_ReplaceOPC (L[4], OP65_JPL); break; case BC_CS: CE_ReplaceOPC (L[4], OP65_JMI); break; default: Internal ("Unknown branch condition in OptCmp9"); } /* Delete the asl insn */ CS_DelEntry (S, I+3); /* Next sequence is somewhat ahead (if any) */ I += 3; /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
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 = CS_GetEntry (S, I); /* Replace the conditional branch */ switch (Cond) { case CMP_EQ: CE_ReplaceOPC (E, OP65_JEQ); break; case CMP_NE: CE_ReplaceOPC (E, OP65_JNE); break; case CMP_GT: /* Replace by * beq @L * jpl Target * @L: ... */ if ((N = CS_GetNextEntry (S, I)) == 0) { /* No such entry */ Internal ("Invalid program flow"); } L = CS_GenLabel (S, N); N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I); CE_ReplaceOPC (E, OP65_JPL); break; case CMP_GE: CE_ReplaceOPC (E, OP65_JPL); break; case CMP_LT: CE_ReplaceOPC (E, OP65_JMI); break; case CMP_LE: /* Replace by * jmi Target * jeq Target */ CE_ReplaceOPC (E, OP65_JMI); L = E->JumpTo; N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I+1); break; case CMP_UGT: /* Replace by * beq @L * jcs Target * @L: ... */ if ((N = CS_GetNextEntry (S, I)) == 0) { /* No such entry */ Internal ("Invalid program flow"); } L = CS_GenLabel (S, N); N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I); CE_ReplaceOPC (E, OP65_JCS); break; case CMP_UGE: CE_ReplaceOPC (E, OP65_JCS); break; case CMP_ULT: CE_ReplaceOPC (E, OP65_JCC); break; case CMP_ULE: /* Replace by * jcc Target * jeq Target */ CE_ReplaceOPC (E, OP65_JCC); L = E->JumpTo; N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I+1); break; default: Internal ("Unknown jump condition: %d", Cond); } }
unsigned OptCmp4 (CodeSeg* S) /* Search for * * lda x * ldx y * cpx #a * bne L1 * cmp #b * L1: 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 < CS_GetEntryCount (S)) { CodeEntry* L[5]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_LDA && CS_GetEntries (S, L, I+1, 5) && L[0]->OPC == OP65_LDX && !CE_HasLabel (L[0]) && IsImmCmp16 (L+1) && !RegAXUsed (S, I+6)) { if ((L[4]->Info & OF_FBRA) != 0 && L[1]->Num == 0 && L[3]->Num == 0) { /* The value is zero, we may use the simple code version. */ CE_ReplaceOPC (L[0], OP65_ORA); CS_DelEntries (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. */ CS_MoveEntry (S, I, I+4); /* We will replace the ldx/cpx by lda/cmp */ CE_ReplaceOPC (L[0], OP65_LDA); CE_ReplaceOPC (L[1], OP65_CMP); /* Beware: If the first LDA instruction had a label, we have * to move this label to the top of the sequence again. */ if (CE_HasLabel (E)) { CS_MoveLabels (S, E, L[0]); } } ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptBNegAX4 (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 < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_JSR && CS_GetEntries (S, L, I+1, 2) && L[0]->OPC == OP65_JSR && strncmp (L[0]->Arg,"bnega",5) == 0 && !CE_HasLabel (L[0]) && (L[1]->Info & OF_ZBRA) != 0 && !CE_HasLabel (L[1])) { CodeEntry* X; /* Check if we're calling bnega or bnegax */ int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0); /* Insert apropriate test code */ if (ByteSized) { /* Test bytes */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, I+2); } else { /* Test words */ X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI); CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI); CS_InsertEntry (S, X, I+3); } /* Delete the subroutine call */ CS_DelEntry (S, I+1); /* Invert the branch */ CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptBNegAX2 (CodeSeg* S) /* Search for the sequence: * * ldy #xx * jsr ldaxysp * jsr bnegax * jne/jeq ... * * and replace it by * * ldy #xx * lda (sp),y * dey * ora (sp),y * jeq/jne ... */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[4]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CE_IsConstImm (L[0]) && !CS_RangeHasLabel (S, I+1, 3) && CS_GetEntries (S, L+1, I+1, 3) && CE_IsCallTo (L[1], "ldaxysp") && CE_IsCallTo (L[2], "bnegax") && (L[3]->Info & OF_ZBRA) != 0) { CodeEntry* X; /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+1); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI); CS_InsertEntry (S, X, I+2); /* ora (sp),y */ X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* Invert the branch */ CE_ReplaceOPC (L[3], GetInverseBranch (L[3]->OPC)); /* Delete the entries no longer needed. */ CS_DelEntries (S, I+4, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }