unsigned OptPush2 (CodeSeg* S) /* A sequence * * jsr ldaxidx * jsr pushax * * may get replaced by * * jsr pushwidx * */ { unsigned I; unsigned Changes = 0; /* Generate register info */ CS_GenRegInfo (S); /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "ldaxidx") && (L[1] = CS_GetNextEntry (S, I)) != 0 && !CE_HasLabel (L[1]) && CE_IsCallTo (L[1], "pushax")) { /* Insert new code behind the pushax */ CodeEntry* X; /* jsr pushwidx */ X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwidx", 0, L[1]->LI); CS_InsertEntry (S, X, I+2); /* Delete the old code */ CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Free the register info */ CS_FreeRegInfo (S); /* 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 OptBNegAX1 (CodeSeg* S) /* On a call to bnegax, if X is zero, the result depends only on the value in * A, so change the call to a call to bnega. This will get further optimized * later if possible. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if this is a call to bnegax, and if X is known and zero */ if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "bnegax")) { CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI); CS_InsertEntry (S, X, I+1); CS_DelEntry (S, I); /* We had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
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 OptNegAX1 (CodeSeg* S) /* Search for a call to negax and replace it by * * eor #$FF * clc * adc #$01 * * if X isn't used later. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if this is a call to negax, and if X isn't used later */ if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) { CodeEntry* X; /* Add replacement code behind */ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI); CS_InsertEntry (S, X, I+1); X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI); CS_InsertEntry (S, X, I+3); /* Delete the call to negax */ CS_DelEntry (S, I); /* Skip the generated code */ I += 2; /* We had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
static unsigned OptLoad1 (CodeSeg* S) /* Search for a call to ldaxysp where X is not used later and replace it by ** a load of just the A register. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* E; /* Get next entry */ E = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (E, "ldaxysp") && RegValIsKnown (E->RI->In.RegY) && !RegXUsed (S, I+1)) { CodeEntry* X; /* Reload the Y register */ const char* Arg = MakeHexArg (E->RI->In.RegY - 1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); CS_InsertEntry (S, X, I+1); /* Load from stack */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI); CS_InsertEntry (S, X, I+2); /* 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 OptBNegA1 (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 < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for a ldx */ if (E->OPC == OP65_LDX && E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0 && E->Num == 0 && CS_GetEntries (S, L, I+1, 2) && L[0]->OPC == OP65_LDA && (L[0]->Use & REG_X) == 0 && !CE_HasLabel (L[0]) && CE_IsCallTo (L[1], "bnega") && !CE_HasLabel (L[1])) { /* Remove the ldx instruction */ CS_DelEntry (S, I); /* 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; }
unsigned OptStore3 (CodeSeg* S) /* Search for a call to steaxysp. If the eax register is not used later, and ** the value is constant, just use the A register and store directly into the ** stack. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Get the input registers */ const RegInfo* RI = E->RI; /* Check for the call */ if (CE_IsCallTo (E, "steaxysp") && RegValIsKnown (RI->In.RegA) && RegValIsKnown (RI->In.RegX) && RegValIsKnown (RI->In.RegY) && RegValIsKnown (RI->In.SRegLo) && RegValIsKnown (RI->In.SRegHi) && !RegEAXUsed (S, I+1)) { /* Get the register values */ unsigned char A = (unsigned char) RI->In.RegA; unsigned char X = (unsigned char) RI->In.RegX; unsigned char Y = (unsigned char) RI->In.RegY; unsigned char L = (unsigned char) RI->In.SRegLo; unsigned char H = (unsigned char) RI->In.SRegHi; /* Setup other variables */ unsigned Done = 0; CodeEntry* N; unsigned IP = I + 1; /* Insertion point */ /* Replace the store. We will not remove the loads, since this is ** too complex and will be done by other optimizer steps. */ N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x01; /* Check if we can store one of the other bytes */ if (A == X && (Done & 0x02) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x02; } if (A == L && (Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } if (A == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the second byte */ if ((Done & 0x02) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x02; } /* Check if we can store one of the other bytes */ if (X == L && (Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } if (X == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the third byte */ if ((Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } /* Check if we can store one of the other bytes */ if (L == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the fourth byte */ if ((Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Remove the call */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* 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 OptCmp5 (CodeSeg* S) /* Optimize compares of local variables: * * ldy #o * jsr ldaxysp * cpx #a * bne L1 * cmp #b * jne/jeq L2 */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[6]; /* Get the next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CE_IsConstImm (L[0]) && CS_GetEntries (S, L+1, I+1, 5) && !CE_HasLabel (L[1]) && CE_IsCallTo (L[1], "ldaxysp") && IsImmCmp16 (L+2)) { if ((L[5]->Info & OF_FBRA) != 0 && L[2]->Num == 0 && L[4]->Num == 0) { CodeEntry* X; char Buf[20]; /* The value is zero, we may use the simple code version: * ldy #o-1 * lda (sp),y * ldy #o * ora (sp),y * jne/jeq ... */ sprintf (Buf, "$%02X", (int)(L[0]->Num-1)); X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); CS_InsertEntry (S, X, I+1); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+3); X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+4); CS_DelEntries (S, I+5, 3); /* cpx/bne/cmp */ CS_DelEntry (S, I); /* ldy */ } else { CodeEntry* X; char Buf[20]; /* 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 * ldy #o-1 * lda (sp),y * cmp #b * jne/jeq ... */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+3); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+4); X = NewCodeEntry (OP65_CMP, L[2]->AM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+5); sprintf (Buf, "$%02X", (int)(L[0]->Num-1)); X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); CS_InsertEntry (S, X, I+7); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+8); CS_DelEntries (S, I, 3); /* ldy/jsr/cpx */ } ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptPush1 (CodeSeg* S) /* Given a sequence * * jsr ldaxysp * jsr pushax * * If a/x are not used later, and Y is known, replace that by * * ldy #xx+2 * jsr pushwysp * * saving 3 bytes and several cycles. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "ldaxysp") && RegValIsKnown (L[0]->RI->In.RegY) && L[0]->RI->In.RegY < 0xFE && (L[1] = CS_GetNextEntry (S, I)) != 0 && !CE_HasLabel (L[1]) && CE_IsCallTo (L[1], "pushax") && !RegAXUsed (S, I+2)) { /* Insert new code behind the pushax */ const char* Arg; CodeEntry* X; /* ldy #xx+1 */ Arg = MakeHexArg (L[0]->RI->In.RegY+2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+2); /* jsr pushwysp */ X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwysp", 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* Delete the old code */ CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptNegAX2 (CodeSeg* S) /* Search for a call to negax and replace it by * * ldx #$FF * eor #$FF * clc * adc #$01 * bne L1 * inx * L1: * * if X is known and zero on entry. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* P; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if this is a call to negax, and if X is known and zero */ if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "negax") && (P = CS_GetNextEntry (S, I)) != 0) { CodeEntry* X; CodeLabel* L; /* Add replacement code behind */ /* ldx #$FF */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$FF", 0, E->LI); CS_InsertEntry (S, X, I+1); /* eor #$FF */ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI); CS_InsertEntry (S, X, I+2); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+3); /* adc #$01 */ X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI); CS_InsertEntry (S, X, I+4); /* Get the label attached to the insn following the call */ L = CS_GenLabel (S, P); /* bne L */ X = NewCodeEntry (OP65_BNE, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, X, I+5); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+6); /* Delete the call to negax */ CS_DelEntry (S, I); /* Skip the generated code */ I += 5; /* 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 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 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 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; }