/*****************************************************************************/ /* */ /* coptptrload.c */ /* */ /* Optimize loads through pointers */ /* */ /* */ /* */ /* (C) 2001-2009 Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ /* warranty. In no event will the authors be held liable for any damages */ /* arising from the use of this software. */ /* */ /* Permission is granted to anyone to use this software for any purpose, */ /* including commercial applications, and to alter it and redistribute it */ /* freely, subject to the following restrictions: */ /* */ /* 1. The origin of this software must not be misrepresented; you must not */ /* claim that you wrote the original software. If you use this software */ /* in a product, an acknowledgment in the product documentation would be */ /* appreciated but is not required. */ /* 2. Altered source versions must be plainly marked as such, and must not */ /* be misrepresented as being the original software. */ /* 3. This notice may not be removed or altered from any source */ /* distribution. */ /* */ /*****************************************************************************/ #include /* common */ #include "xmalloc.h" /* cc65 */ #include "codeent.h" #include "codeinfo.h" #include "coptptrload.h" /*****************************************************************************/ /* Code */ /*****************************************************************************/ unsigned OptPtrLoad1 (CodeSeg* S) /* Search for the sequence: * * clc * adc xxx * tay * txa * adc yyy * tax * tya * ldy #$00 * jsr ldauidx * * and replace it by: * * sta ptr1 * txa * clc * adc yyy * sta ptr1+1 * ldy xxx * ldx #$00 * lda (ptr1),y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[9]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_CLC && CS_GetEntries (S, L+1, I+1, 8) && L[1]->OPC == OP65_ADC && (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP || L[1]->AM == AM65_IMM) && L[2]->OPC == OP65_TAY && L[3]->OPC == OP65_TXA && L[4]->OPC == OP65_ADC && L[5]->OPC == OP65_TAX && L[6]->OPC == OP65_TYA && L[7]->OPC == OP65_LDY && CE_IsKnownImm (L[7], 0) && CE_IsCallTo (L[8], "ldauidx") && !CS_RangeHasLabel (S, I+1, 8)) { CodeEntry* X; CodeEntry* P; /* Track the insertion point */ unsigned IP = I+9; /* sta ptr1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI); CS_InsertEntry (S, X, IP++); /* If the instruction before the clc is a ldx, replace the * txa by an lda with the same location of the ldx. Otherwise * transfer the value in X to A. */ if ((P = CS_GetPrevEntry (S, I)) != 0 && P->OPC == OP65_LDX && !CE_HasLabel (P)) { X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI); } else { X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI); } CS_InsertEntry (S, X, IP++); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* adc yyy */ X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI); CS_InsertEntry (S, X, IP++); /* sta ptr1+1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI); CS_InsertEntry (S, X, IP++); /* ldy xxx */ X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, IP++); /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI); CS_InsertEntry (S, X, IP++); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI); CS_InsertEntry (S, X, IP++); /* Remove the old instructions */ CS_DelEntries (S, I, 9); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad2 (CodeSeg* S) /* Search for the sequence: * * adc xxx * pha * txa * iny * adc yyy * tax * pla * ldy * jsr ldauidx * * and replace it by: * * adc xxx * sta ptr1 * txa * iny * adc yyy * sta ptr1+1 * ldy * ldx #$00 * lda (ptr1),y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[9]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_ADC && CS_GetEntries (S, L+1, I+1, 8) && L[1]->OPC == OP65_PHA && L[2]->OPC == OP65_TXA && L[3]->OPC == OP65_INY && L[4]->OPC == OP65_ADC && L[5]->OPC == OP65_TAX && L[6]->OPC == OP65_PLA && L[7]->OPC == OP65_LDY && CE_IsCallTo (L[8], "ldauidx") && !CS_RangeHasLabel (S, I+1, 8)) { CodeEntry* X; /* Store the low byte and remove the PHA instead */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+1); /* Store the high byte */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI); CS_InsertEntry (S, X, I+6); /* Load high and low byte */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI); CS_InsertEntry (S, X, I+10); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI); CS_InsertEntry (S, X, I+11); /* Delete the old code */ CS_DelEntry (S, I+12); /* jsr ldauidx */ CS_DelEntry (S, I+8); /* pla */ CS_DelEntry (S, I+7); /* tax */ CS_DelEntry (S, I+2); /* pha */ /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad3 (CodeSeg* S) /* Search for the sequence: * * lda #<(label+0) * ldx #>(label+0) * clc * adc xxx * bcc L * inx * L: ldy #$00 * jsr ldauidx * * and replace it by: * * ldy xxx * ldx #$00 * lda label,y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[8]; unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_IMM && CS_GetEntries (S, L+1, I+1, 7) && L[1]->OPC == OP65_LDX && L[1]->AM == AM65_IMM && L[2]->OPC == OP65_CLC && L[3]->OPC == OP65_ADC && (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP) && (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) && L[4]->JumpTo != 0 && L[4]->JumpTo->Owner == L[6] && L[5]->OPC == OP65_INX && L[6]->OPC == OP65_LDY && CE_IsKnownImm (L[6], 0) && CE_IsCallTo (L[7], "ldauidx") && !CS_RangeHasLabel (S, I+1, 5) && !CE_HasLabel (L[7]) && /* Check the label last because this is quite costly */ (Len = strlen (L[0]->Arg)) > 3 && L[0]->Arg[0] == '<' && L[0]->Arg[1] == '(' && strlen (L[1]->Arg) == Len && L[1]->Arg[0] == '>' && memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) { CodeEntry* X; char* Label; /* We will create all the new stuff behind the current one so * we keep the line references. */ X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+8); X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI); CS_InsertEntry (S, X, I+9); Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3); Label[Len-3] = '\0'; X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI); CS_InsertEntry (S, X, I+10); xfree (Label); /* Remove the old code */ CS_DelEntries (S, I, 8); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad4 (CodeSeg* S) /* Search for the sequence: * * lda #<(label+0) * ldx #>(label+0) * ldy #$xx * clc * adc (sp),y * bcc L * inx * L: ldy #$00 * jsr ldauidx * * and replace it by: * * ldy #$xx * lda (sp),y * tay * ldx #$00 * lda label,y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[9]; unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_IMM && CS_GetEntries (S, L+1, I+1, 8) && L[1]->OPC == OP65_LDX && L[1]->AM == AM65_IMM && !CE_HasLabel (L[1]) && L[2]->OPC == OP65_LDY && CE_IsConstImm (L[2]) && !CE_HasLabel (L[2]) && L[3]->OPC == OP65_CLC && !CE_HasLabel (L[3]) && L[4]->OPC == OP65_ADC && L[4]->AM == AM65_ZP_INDY && !CE_HasLabel (L[4]) && (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) && L[5]->JumpTo != 0 && L[5]->JumpTo->Owner == L[7] && !CE_HasLabel (L[5]) && L[6]->OPC == OP65_INX && !CE_HasLabel (L[6]) && L[7]->OPC == OP65_LDY && CE_IsKnownImm (L[7], 0) && CE_IsCallTo (L[8], "ldauidx") && !CE_HasLabel (L[8]) && /* Check the label last because this is quite costly */ (Len = strlen (L[0]->Arg)) > 3 && L[0]->Arg[0] == '<' && L[0]->Arg[1] == '(' && strlen (L[1]->Arg) == Len && L[1]->Arg[0] == '>' && memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) { CodeEntry* X; char* Label; /* Add the lda */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+3); /* Add the tay */ X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* Add the ldx */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI); CS_InsertEntry (S, X, I+5); /* Add the lda */ Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3); Label[Len-3] = '\0'; X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI); CS_InsertEntry (S, X, I+6); xfree (Label); /* Remove the old code */ CS_DelEntries (S, I, 2); CS_DelEntries (S, I+5, 6); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad5 (CodeSeg* S) /* Search for the sequence: * * jsr pushax * ldx #$00 * lda yyy * jsr tosaddax * ldy #$00 * jsr ldauidx * * and replace it by: * * sta ptr1 * stx ptr1+1 * ldy yyy * ldx #$00 * lda (ptr1),y */ { 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 (CE_IsCallTo (L[0], "pushax") && CS_GetEntries (S, L+1, I+1, 5) && L[1]->OPC == OP65_LDX && CE_IsKnownImm (L[1], 0) && L[2]->OPC == OP65_LDA && (L[2]->AM == AM65_ABS || L[2]->AM == AM65_ZP || L[2]->AM == AM65_IMM) && CE_IsCallTo (L[3], "tosaddax") && L[4]->OPC == OP65_LDY && CE_IsKnownImm (L[4], 0) && CE_IsCallTo (L[5], "ldauidx") && !CS_RangeHasLabel (S, I+1, 5)) { CodeEntry* X; /* sta ptr1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+6); /* stx ptr1+1 */ X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); CS_InsertEntry (S, X, I+7); /* ldy yyy */ X = NewCodeEntry (OP65_LDY, L[2]->AM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+8); /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[5]->LI); CS_InsertEntry (S, X, I+9); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[5]->LI); CS_InsertEntry (S, X, I+10); /* Remove the old code */ CS_DelEntries (S, I, 6); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad6 (CodeSeg* S) /* Search for the sequence: * * jsr pushax * ldy #xxx * ldx #$00 * lda (sp),y * jsr tosaddax * ldy #$00 * jsr ldauidx * * and replace it by: * * sta ptr1 * stx ptr1+1 * ldy #xxx-2 * lda (sp),y * tay * ldx #$00 * lda (ptr1),y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[7]; /* 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, 6) && L[1]->OPC == OP65_LDY && CE_IsConstImm (L[1]) && L[1]->Num >= 2 && L[2]->OPC == OP65_LDX && CE_IsKnownImm (L[2], 0) && L[3]->OPC == OP65_LDA && L[3]->AM == AM65_ZP_INDY && CE_IsCallTo (L[4], "tosaddax") && L[5]->OPC == OP65_LDY && CE_IsKnownImm (L[5], 0) && CE_IsCallTo (L[6], "ldauidx") && !CS_RangeHasLabel (S, I+1, 6) && !RegYUsed (S, I+7)) { CodeEntry* X; const char* Arg; /* sta ptr1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+7); /* stx ptr1+1 */ X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); CS_InsertEntry (S, X, I+8); /* ldy #xxx-2 */ Arg = MakeHexArg (L[1]->Num - 2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+9); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+10); /* tay */ X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+11); /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[5]->LI); CS_InsertEntry (S, X, I+12); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI); CS_InsertEntry (S, X, I+13); /* Remove the old code */ CS_DelEntries (S, I, 7); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad7 (CodeSeg* S) /* Search for the sequence: * * jsr aslax1/shlax1 * clc * adc xxx * tay * txa * adc yyy * tax * tya * ldy zzz * jsr ldaxidx * * and replace it by: * * stx tmp1 * asl a * rol tmp1 * clc * adc xxx * sta ptr1 * lda tmp1 * adc yyy * sta ptr1+1 * ldy zzz * lda (ptr1),y * tax * dey * lda (ptr1),y */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[10]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_JSR && (strcmp (L[0]->Arg, "aslax1") == 0 || strcmp (L[0]->Arg, "shlax1") == 0) && CS_GetEntries (S, L+1, I+1, 9) && L[1]->OPC == OP65_CLC && L[2]->OPC == OP65_ADC && L[3]->OPC == OP65_TAY && L[4]->OPC == OP65_TXA && L[5]->OPC == OP65_ADC && L[6]->OPC == OP65_TAX && L[7]->OPC == OP65_TYA && L[8]->OPC == OP65_LDY && CE_IsCallTo (L[9], "ldaxidx") && !CS_RangeHasLabel (S, I+1, 9)) { CodeEntry* X; /* Track the insertion point */ unsigned IP = I + 10; /* If X is zero on entry to aslax1, we can generate: * * asl a * bcc L1 * inx * L1: clc * * instead of the code above. "lda tmp1" needs to be changed * to "txa" in this case. */ int ShortCode = (L[0]->RI->In.RegX == 0); if (ShortCode) { CodeLabel* Lab; /* asl a */ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* Generate clc first, since we need the label */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI); CS_InsertEntry (S, X, IP); /* Get the label */ Lab = CS_GenLabel (S, X); /* bcc Lab */ X = NewCodeEntry (OP65_BCC, AM65_BRA, Lab->Name, Lab, L[0]->LI); CS_InsertEntry (S, X, IP++); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* Skip the clc insn */ ++IP; } else { /* stx tmp1 */ X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* asl a */ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* rol tmp1 */ X = NewCodeEntry (OP65_ROL, AM65_ZP, "tmp1", 0, L[0]->LI); CS_InsertEntry (S, X, IP++); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI); CS_InsertEntry (S, X, IP++); } /* adc xxx */ X = NewCodeEntry (L[2]->OPC, L[2]->AM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, IP++); /* sta ptr1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[9]->LI); CS_InsertEntry (S, X, IP++); if (ShortCode) { /* txa */ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[4]->LI); } else { /* lda tmp1 */ X = NewCodeEntry (OP65_LDA, AM65_ZP, "tmp1", 0, L[4]->LI); } CS_InsertEntry (S, X, IP++); /* adc xxx */ X = NewCodeEntry (L[5]->OPC, L[5]->AM, L[5]->Arg, 0, L[5]->LI); CS_InsertEntry (S, X, IP++); /* sta ptr1+1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* ldy zzz */ X = NewCodeEntry (L[8]->OPC, L[8]->AM, L[8]->Arg, 0, L[8]->LI); CS_InsertEntry (S, X, IP++); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* Remove the old code */ CS_DelEntries (S, I, 10); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad11 (CodeSeg* S) /* Search for the sequence: * * clc * adc xxx * bcc L * inx * L: ldy #$00 * jsr ldauidx * * and replace it by: * * ldy xxx * sta ptr1 * stx ptr1+1 * ldx #$00 * lda (ptr1),y */ { 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_CLC && CS_GetEntries (S, L+1, I+1, 5) && L[1]->OPC == OP65_ADC && (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP || L[1]->AM == AM65_IMM) && (L[2]->OPC == OP65_BCC || L[2]->OPC == OP65_JCC) && L[2]->JumpTo != 0 && L[2]->JumpTo->Owner == L[4] && L[3]->OPC == OP65_INX && L[4]->OPC == OP65_LDY && CE_IsKnownImm (L[4], 0) && CE_IsCallTo (L[5], "ldauidx") && !CS_RangeHasLabel (S, I+1, 3) && !CE_HasLabel (L[5])) { CodeEntry* X; /* We will create all the new stuff behind the current one so * we keep the line references. */ X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+6); /* sta ptr1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+7); /* stx ptr1+1 */ X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); CS_InsertEntry (S, X, I+8); /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI); CS_InsertEntry (S, X, I+9); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+10); /* Remove the old code */ CS_DelEntries (S, I, 6); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad12 (CodeSeg* S) /* Search for the sequence: * * lda regbank+n * ldx regbank+n+1 * sta regsave * stx regsave+1 * clc * adc #$01 * bcc L0005 * inx * L: sta regbank+n * stx regbank+n+1 * lda regsave * ldx regsave+1 * ldy #$00 * jsr ldauidx * * and replace it by: * * ldy #$00 * ldx #$00 * lda (regbank+n),y * inc regbank+n * bne L1 * inc regbank+n+1 * L1: tay <- only if flags are used * * This function must execute before OptPtrLoad7! * */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[15]; unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && strncmp (L[0]->Arg, "regbank+", 8) == 0 && (Len = strlen (L[0]->Arg)) > 0 && CS_GetEntries (S, L+1, I+1, 14) && !CS_RangeHasLabel (S, I+1, 7) && !CS_RangeHasLabel (S, I+9, 5) && L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && strncmp (L[1]->Arg, L[0]->Arg, Len) == 0 && strcmp (L[1]->Arg+Len, "+1") == 0 && L[2]->OPC == OP65_STA && L[2]->AM == AM65_ZP && strcmp (L[2]->Arg, "regsave") == 0 && L[3]->OPC == OP65_STX && L[3]->AM == AM65_ZP && strcmp (L[3]->Arg, "regsave+1") == 0 && L[4]->OPC == OP65_CLC && L[5]->OPC == OP65_ADC && CE_IsKnownImm (L[5], 1) && L[6]->OPC == OP65_BCC && L[6]->JumpTo != 0 && L[6]->JumpTo->Owner == L[8] && L[7]->OPC == OP65_INX && L[8]->OPC == OP65_STA && L[8]->AM == AM65_ZP && strcmp (L[8]->Arg, L[0]->Arg) == 0 && L[9]->OPC == OP65_STX && L[9]->AM == AM65_ZP && strcmp (L[9]->Arg, L[1]->Arg) == 0 && L[10]->OPC == OP65_LDA && L[10]->AM == AM65_ZP && strcmp (L[10]->Arg, "regsave") == 0 && L[11]->OPC == OP65_LDX && L[11]->AM == AM65_ZP && strcmp (L[11]->Arg, "regsave+1") == 0 && L[12]->OPC == OP65_LDY && CE_IsConstImm (L[12]) && CE_IsCallTo (L[13], "ldauidx")) { CodeEntry* X; CodeLabel* Label; /* Check if the instruction following the sequence uses the flags * set by the load. If so, insert a test of the value in the * accumulator. */ if (CE_UseLoadFlags (L[14])) { X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI); CS_InsertEntry (S, X, I+14); } /* Attach a label to L[14]. This may be either the just inserted * instruction, or the one following the sequence. */ Label = CS_GenLabel (S, L[14]); /* ldy #$xx */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI); CS_InsertEntry (S, X, I+14); /* ldx #$xx */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI); CS_InsertEntry (S, X, I+15); /* lda (regbank+n),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI); CS_InsertEntry (S, X, I+16); /* inc regbank+n */ X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI); CS_InsertEntry (S, X, I+17); /* bne ... */ X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI); CS_InsertEntry (S, X, I+18); /* inc regbank+n+1 */ X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI); CS_InsertEntry (S, X, I+19); /* Delete the old code */ CS_DelEntries (S, I, 14); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad13 (CodeSeg* S) /* Search for the sequence: * * lda zp * ldx zp+1 * ldy xx * jsr ldauidx * * and replace it by: * * ldy xx * ldx #$00 * lda (zp),y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[4]; unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && CS_GetEntries (S, L+1, I+1, 3) && !CS_RangeHasLabel (S, I+1, 3) && L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && (Len = strlen (L[0]->Arg)) > 0 && strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && strcmp (L[1]->Arg + Len, "+1") == 0 && L[2]->OPC == OP65_LDY && CE_IsCallTo (L[3], "ldauidx")) { CodeEntry* X; /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI); CS_InsertEntry (S, X, I+3); /* lda (zp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+4); /* Remove the old code */ CS_DelEntry (S, I+5); CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad14 (CodeSeg* S) /* Search for the sequence: * * lda zp * ldx zp+1 * (anything that doesn't change a/x) * ldy xx * jsr ldauidx * * and replace it by: * * lda zp * ldx zp+1 * (anything that doesn't change a/x) * ldy xx * ldx #$00 * lda (zp),y * */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[5]; unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDA && 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_ZP && (Len = strlen (L[0]->Arg)) > 0 && strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && strcmp (L[1]->Arg + Len, "+1") == 0 && (L[2]->Chg & REG_AX) == 0 && L[3]->OPC == OP65_LDY && CE_IsCallTo (L[4], "ldauidx")) { CodeEntry* X; /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI); CS_InsertEntry (S, X, I+5); /* lda (zp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+6); /* Remove the old code */ CS_DelEntry (S, I+4); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad15 (CodeSeg* S) /* Search for the sequence: * * lda zp * ldx zp+1 * jsr pushax <- optional * ldy xx * jsr ldaxidx * * and replace it by: * * lda zp <- only if * ldx zp+1 <- call to * jsr pushax <- pushax present * ldy xx * lda (zp),y * tax * dey * lda (zp),y */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[5]; unsigned Len; /* Check for the start of the sequence */ if (CS_GetEntries (S, L, I, 3) && L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && !CS_RangeHasLabel (S, I+1, 2) && (Len = strlen (L[0]->Arg)) > 0 && strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && strcmp (L[1]->Arg + Len, "+1") == 0) { unsigned PushAX = CE_IsCallTo (L[2], "pushax"); /* Check for the remainder of the sequence */ if (CS_GetEntries (S, L+3, I+3, 1 + PushAX) && !CS_RangeHasLabel (S, I+3, 1 + PushAX) && L[2+PushAX]->OPC == OP65_LDY && CE_IsCallTo (L[3+PushAX], "ldaxidx")) { CodeEntry* X; /* lda (zp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+PushAX+4); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+PushAX+5); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+PushAX+6); /* lda (zp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+PushAX+7); /* Remove the old code */ CS_DelEntry (S, I+PushAX+3); if (!PushAX) { CS_DelEntries (S, I, 2); } /* Remember, we had changes */ ++Changes; } } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; } unsigned OptPtrLoad16 (CodeSeg* S) /* Search for the sequence * * ldy ... * jsr ldauidx * * and replace it by: * * stx ptr1+1 * sta ptr1 * ldy ... * ldx #$00 * lda (ptr1),y * * This step must be executed *after* OptPtrLoad1! */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CS_GetEntries (S, L+1, I+1, 1) && CE_IsCallTo (L[1], "ldauidx") && !CE_HasLabel (L[1])) { CodeEntry* X; /* stx ptr1+1 */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[1]->LI); CS_InsertEntry (S, X, I+2); /* sta ptr1 */ X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* ldy ... */ X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* ldx #$00 */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[1]->LI); CS_InsertEntry (S, X, I+5); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI); CS_InsertEntry (S, X, I+6); /* 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 OptPtrLoad17 (CodeSeg* S) /* Search for the sequence * * ldy ... * jsr ldaxidx * * and replace it by: * * sta ptr1 * stx ptr1+1 * ldy ... * lda (ptr1),y * tax * dey * lda (ptr1),y * * This step must be executed *after* OptPtrLoad9! While code size increases * by more than 200%, inlining will greatly improve visibility for the * optimizer, so often part of the code gets improved later. So we will mark * the step with less than 200% so it gets executed when -Oi is in effect. */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CS_GetEntries (S, L+1, I+1, 1) && CE_IsCallTo (L[1], "ldaxidx") && !CE_HasLabel (L[1])) { CodeEntry* X; /* Store the high byte */ X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); CS_InsertEntry (S, X, I+2); /* Store the low byte */ X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); CS_InsertEntry (S, X, I+3); /* ldy ... */ X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI); CS_InsertEntry (S, X, I+5); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[1]->LI); CS_InsertEntry (S, X, I+6); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI); CS_InsertEntry (S, X, I+7); /* lda (ptr1),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI); CS_InsertEntry (S, X, I+8); /* Delete original sequence */ CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }