unsigned OptCmp1 (CodeSeg* S) /* Search for the sequence * * ldx xx * stx tmp1 * ora tmp1 * * and replace it by * * ora xx */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[3]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDX && !CS_RangeHasLabel (S, I+1, 2) && CS_GetEntries (S, L+1, I+1, 2) && L[1]->OPC == OP65_STX && strcmp (L[1]->Arg, "tmp1") == 0 && L[2]->OPC == OP65_ORA && strcmp (L[2]->Arg, "tmp1") == 0) { CodeEntry* X; /* Insert the ora instead */ X = NewCodeEntry (OP65_ORA, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I); /* Remove all other instructions */ CS_DelEntries (S, I+1, 3); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptStore4 (CodeSeg* S) /* Search for the sequence ** ** sta xx ** stx yy ** lda xx ** ldx yy ** ** and remove the useless load, provided that the next insn doesn't use flags ** from the load. */ { unsigned Changes = 0; /* Walk over the entries */ unsigned 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_STA && (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) && !CS_RangeHasLabel (S, I+1, 3) && CS_GetEntries (S, L+1, I+1, 4) && L[1]->OPC == OP65_STX && L[1]->AM == L[0]->AM && L[2]->OPC == OP65_LDA && L[2]->AM == L[0]->AM && L[3]->OPC == OP65_LDX && L[3]->AM == L[1]->AM && strcmp (L[0]->Arg, L[2]->Arg) == 0 && strcmp (L[1]->Arg, L[3]->Arg) == 0 && !CE_UseLoadFlags (L[4])) { /* Register has already the correct value, remove the loads */ CS_DelEntries (S, I+2, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptStore1 (CodeSeg* S) /* Search for the sequence ** ** ldy #n ** jsr staxysp ** ldy #n+1 ** jsr ldaxysp ** ** and remove the useless load. */ { 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]) && L[0]->Num < 0xFF && !CS_RangeHasLabel (S, I+1, 3) && CS_GetEntries (S, L+1, I+1, 3) && CE_IsCallTo (L[1], "staxysp") && L[2]->OPC == OP65_LDY && CE_IsKnownImm (L[2], L[0]->Num + 1) && CE_IsCallTo (L[3], "ldaxysp")) { /* Register has already the correct value, remove the loads */ CS_DelEntries (S, I+2, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptStore5 (CodeSeg* S) /* Search for the sequence ** ** lda foo ** ldx bar ** sta something ** stx something-else ** ** and replace it by ** ** lda foo ** sta something ** lda bar ** sta something-else ** ** if X is not used later. This replacement doesn't save any cycles or bytes, ** but it keeps the value of X, which may be reused later. */ { 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_LDA && !CS_RangeHasLabel (S, I+1, 3) && CS_GetEntries (S, L+1, I+1, 3) && L[1]->OPC == OP65_LDX && L[2]->OPC == OP65_STA && L[3]->OPC == OP65_STX && !RegXUsed (S, I+4)) { CodeEntry* X; /* Insert the code after the sequence */ X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+4); X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+5); /* Delete the old code */ CS_DelEntry (S, I+3); 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 Opt65C02BitOps (CodeSeg* S) /* Use special bit op instructions of the C02 */ { unsigned Changes = 0; unsigned I; /* Generate register info for this step */ CS_GenRegInfo (S); /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[3]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && (L[0]->AM == AM65_ZP || L[0]->AM == AM65_ABS) && !CS_RangeHasLabel (S, I+1, 2) && CS_GetEntries (S, L+1, I+1, 2) && (L[1]->OPC == OP65_AND || L[1]->OPC == OP65_ORA) && CE_IsConstImm (L[1]) && L[2]->OPC == OP65_STA && L[2]->AM == L[0]->AM && strcmp (L[2]->Arg, L[0]->Arg) == 0 && !RegAUsed (S, I+3)) { char Buf[32]; CodeEntry* X; /* Use TRB for AND and TSB for ORA */ if (L[1]->OPC == OP65_AND) { /* LDA #XX */ sprintf (Buf, "$%02X", (int) ((~L[1]->Num) & 0xFF)); X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* TRB */ X = NewCodeEntry (OP65_TRB, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); } else { /* LDA #XX */ sprintf (Buf, "$%02X", (int) L[1]->Num); X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* TSB */ X = NewCodeEntry (OP65_TSB, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); } /* Delete the old stuff */ CS_DelEntries (S, I, 3); /* We had changes */ ++Changes; } /* Next entry */ ++I; } /* Free register info */ CS_FreeRegInfo (S); /* Return the number of changes made */ return Changes; }
static unsigned OptLoad2 (CodeSeg* S) /* Replace calls to ldaxysp by inline code */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[3]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "ldaxysp")) { CodeEntry* X; /* Followed by sta abs/stx abs? */ if (CS_GetEntries (S, L+1, I+1, 2) && L[1]->OPC == OP65_STA && L[2]->OPC == OP65_STX && (L[1]->Arg == 0 || L[2]->Arg == 0 || strcmp (L[1]->Arg, L[2]->Arg) != 0) && !CS_RangeHasLabel (S, I+1, 2) && !RegXUsed (S, I+3)) { /* A/X are stored into memory somewhere and X is not used ** later */ /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI); CS_InsertEntry (S, X, I+3); /* sta abs */ X = NewCodeEntry (OP65_STA, L[2]->AM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+4); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, I+5); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI); CS_InsertEntry (S, X, I+6); /* sta abs */ X = NewCodeEntry (OP65_STA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+7); /* Now remove the call to the subroutine and the sta/stx */ CS_DelEntries (S, I, 3); } else { /* Standard replacement */ /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI); CS_InsertEntry (S, X, I+1); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, I+2); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, I+3); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* Now remove the call to the subroutine */ CS_DelEntry (S, I); } /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptCmp3 (CodeSeg* S) /* Search for * * lda/and/ora/eor ... * cmp #$00 * jeq/jne * or * lda/and/ora/eor ... * cmp #$00 * jsr boolxx * * and remove the cmp. */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[3]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if ((L[0]->OPC == OP65_ADC || L[0]->OPC == OP65_AND || L[0]->OPC == OP65_ASL || L[0]->OPC == OP65_DEA || L[0]->OPC == OP65_EOR || L[0]->OPC == OP65_INA || L[0]->OPC == OP65_LDA || L[0]->OPC == OP65_LSR || L[0]->OPC == OP65_ORA || L[0]->OPC == OP65_PLA || L[0]->OPC == OP65_SBC || L[0]->OPC == OP65_TXA || L[0]->OPC == OP65_TYA) && !CS_RangeHasLabel (S, I+1, 2) && CS_GetEntries (S, L+1, I+1, 2) && L[1]->OPC == OP65_CMP && CE_IsKnownImm (L[1], 0)) { int Delete = 0; /* Check for the call to boolxx. We only remove the compare if * the carry flag is not evaluated later, because the load will * not set the carry flag. */ if (L[2]->OPC == OP65_JSR) { switch (FindBoolCmpCond (L[2]->Arg)) { case CMP_EQ: case CMP_NE: case CMP_GT: case CMP_GE: case CMP_LT: case CMP_LE: /* Remove the compare */ Delete = 1; break; case CMP_UGT: case CMP_UGE: case CMP_ULT: case CMP_ULE: case CMP_INV: /* Leave it alone */ break; } } else if ((L[2]->Info & OF_FBRA) != 0) { /* The following insn branches on the condition of the load, * so the compare instruction might be removed. For safety, * do some more checks if the carry isn't used later, since * the compare does set the carry, but the load does not. */ CodeEntry* E; CodeEntry* N; if ((E = CS_GetNextEntry (S, I+2)) != 0 && L[2]->JumpTo != 0 && (N = L[2]->JumpTo->Owner) != 0 && N->OPC != OP65_BCC && N->OPC != OP65_BCS && N->OPC != OP65_JCC && N->OPC != OP65_JCS && (N->OPC != OP65_JSR || FindBoolCmpCond (N->Arg) == CMP_INV)) { /* The following insn branches on the condition of a load, * and there's no use of the carry flag in sight, so the * compare instruction can be removed. */ Delete = 1; } } /* Delete the compare if we can */ if (Delete) { CS_DelEntry (S, I+1); ++Changes; } } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptShift5 (CodeSeg* S) /* Search for the sequence * * lda xxx * ldx yyy * jsr aslax1/asrax1/shlax1/shrax1 * sta aaa * stx bbb * * and replace it by * * lda xxx * asl a * sta aaa * lda yyy * rol a * sta bbb * * or similar, provided that a/x is not used later */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { unsigned ShiftType; CodeEntry* L[5]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) && CS_GetEntries (S, L+1, I+1, 4) && !CS_RangeHasLabel (S, I+1, 4) && L[1]->OPC == OP65_LDX && (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP) && L[2]->OPC == OP65_JSR && (ShiftType = GetShift (L[2]->Arg)) != SHIFT_NONE && SHIFT_COUNT(ShiftType) == 1 && L[3]->OPC == OP65_STA && (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP) && L[4]->OPC == OP65_STX && (L[4]->AM == AM65_ABS || L[4]->AM == AM65_ZP) && !RegAXUsed (S, I+5)) { CodeEntry* X; /* Handle the four shift types differently */ switch (ShiftType) { case SHIFT_ASR_1: X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+5); X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, L[2]->LI); CS_InsertEntry (S, X, I+6); X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+7); X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+8); X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+9); X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+10); X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+11); CS_DelEntries (S, I, 5); break; case SHIFT_LSR_1: X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+5); X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+6); X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+7); X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+8); X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+9); X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+10); CS_DelEntries (S, I, 5); break; case SHIFT_LSL_1: case SHIFT_ASL_1: /* These two are identical */ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+1); X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+3); X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+4); X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+5); CS_DelEntries (S, I+6, 4); break; } /* 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; }
unsigned OptShift3 (CodeSeg* S) /* The sequence * * bcc L * inx * L: jsr shrax1 * * may get replaced by * * ror a * * if X is zero on entry. For shift counts > 1, more * * shr a * * must be added. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { unsigned Shift; unsigned Count; CodeEntry* L[3]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if ((L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) && L[0]->JumpTo != 0 && L[0]->RI->In.RegX == 0 && CS_GetEntries (S, L+1, I+1, 2) && L[1]->OPC == OP65_INX && L[0]->JumpTo->Owner == L[2] && !CS_RangeHasLabel (S, I, 2) && L[2]->OPC == OP65_JSR && (Shift = GetShift (L[2]->Arg)) != SHIFT_NONE && SHIFT_DIR (Shift) == SHIFT_DIR_RIGHT && (Count = SHIFT_COUNT (Shift)) > 0) { /* Add the replacement insn instead */ CodeEntry* X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+3); while (--Count) { X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, L[2]->LI); CS_InsertEntry (S, X, I+4); } /* Remove the bcs/dex/jsr */ CS_DelEntries (S, I, 3); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd1 (CodeSeg* S) /* Search for the sequence * * ldy #xx * jsr ldaxysp * jsr pushax * ldy #yy * jsr ldaxysp * jsr tosaddax * * and replace it by: * * ldy #xx-1 * lda (sp),y * ldy #yy-3 * clc * adc (sp),y * pha * ldy #xx * lda (sp),y * ldy #yy-2 * adc (sp),y * tax * pla */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[6]; /* 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, 5) && CS_GetEntries (S, L+1, I+1, 5) && CE_IsCallTo (L[1], "ldaxysp") && CE_IsCallTo (L[2], "pushax") && L[3]->OPC == OP65_LDY && CE_IsConstImm (L[3]) && CE_IsCallTo (L[4], "ldaxysp") && CE_IsCallTo (L[5], "tosaddax")) { CodeEntry* X; const char* Arg; /* Correct the stack of the first Y register load */ CE_SetNumArg (L[0], L[0]->Num - 1); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+1); /* ldy #yy-3 */ Arg = MakeHexArg (L[3]->Num - 3); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+2); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+3); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI); CS_InsertEntry (S, X, I+4); /* pha */ X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+5); /* ldy #xx (beware: L[0] has changed) */ Arg = MakeHexArg (L[0]->Num + 1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+6); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+7); /* ldy #yy-2 */ Arg = MakeHexArg (L[3]->Num - 2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+8); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI); CS_InsertEntry (S, X, I+9); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+10); /* pla */ X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+11); /* Delete the old code */ CS_DelEntries (S, I+12, 5); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd4 (CodeSeg* S) /* Search for the sequence * * jsr pushax * lda xxx * ldx yyy * jsr tosaddax * * and replace it by * * clc * adc xxx * pha * txa * adc yyy * tax * pla */ { 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 (CE_IsCallTo (L[0], "pushax") && CS_GetEntries (S, L+1, I+1, 3) && !CS_RangeHasLabel (S, I+1, 3) && L[1]->OPC == OP65_LDA && (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP) && L[2]->OPC == OP65_LDX && (L[2]->AM == AM65_ABS || L[2]->AM == AM65_ZP) && CE_IsCallTo (L[3], "tosaddax")) { CodeEntry* X; /* Insert new code behind the sequence */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+4); /* adc xxx */ X = NewCodeEntry (OP65_ADC, L[1]->AM, L[1]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+5); /* pha */ X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+6); /* txa */ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); /* adc yyy */ X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+8); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+9); /* pla */ X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+10); /* Delete the old code */ CS_DelEntries (S, I, 4); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd3 (CodeSeg* S) /* Search for the sequence * * jsr pushax * ldx #$00 * lda xxx * jsr tosaddax * * and replace it by * * clc * adc xxx * bcc L1 * inx * L1: */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[5]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "pushax") && CS_GetEntries (S, L+1, I+1, 4) && !CS_RangeHasLabel (S, I+1, 3) && L[1]->OPC == OP65_LDX && CE_IsKnownImm (L[1], 0) && L[2]->OPC == OP65_LDA && CE_IsCallTo (L[3], "tosaddax")) { CodeEntry* X; CodeLabel* Label; /* Insert new code behind the sequence */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+4); /* adc xxx */ X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+5); /* bcc L1 */ Label = CS_GenLabel (S, L[4]); X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI); CS_InsertEntry (S, X, I+6); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); /* Delete the old code */ CS_DelEntries (S, I, 4); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd2 (CodeSeg* S) /* Search for the sequence * * ldy #xx * jsr ldaxysp * ldy #yy * jsr addeqysp * * and replace it by: * * ldy #xx-1 * lda (sp),y * ldy #yy * clc * adc (sp),y * sta (sp),y * ldy #xx * lda (sp),y * ldy #yy+1 * adc (sp),y * sta (sp),y * * provided that a/x is not used later. */ { 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") && L[2]->OPC == OP65_LDY && CE_IsConstImm (L[2]) && CE_IsCallTo (L[3], "addeqysp") && (GetRegInfo (S, I+4, REG_AX) & REG_AX) == 0) { /* Insert new code behind the addeqysp */ const char* Arg; CodeEntry* X; /* ldy #xx-1 */ Arg = MakeHexArg (L[0]->Num-1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+5); /* ldy #yy */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+6); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+8); /* sta (sp),y */ X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+9); /* ldy #xx */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+10); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+11); /* ldy #yy+1 */ Arg = MakeHexArg (L[2]->Num+1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+12); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+13); /* sta (sp),y */ X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+14); /* Delete the old code */ CS_DelEntries (S, I, 4); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }