X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcodeopt.c;h=e26e747f42c2d8451d847e85015fbed322fac581;hb=d6c50c18267881ae4ad4117edeb81e6c36d33f44;hp=9bf94bbd0a67fe54da433a1ee671878974c5e515;hpb=d814a9a6fb85686b62ab68f91aa65434607825e3;p=cc65 diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 9bf94bbd0..e26e747f4 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 2001-2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 2001-2003 Ullrich von Bassewitz */ +/* Römerstraße 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -39,9 +39,9 @@ /* common */ #include "abend.h" #include "chartype.h" +#include "cpu.h" #include "print.h" #include "xmalloc.h" -#include "xsprintf.h" /* cc65 */ #include "asmlabel.h" @@ -53,16 +53,34 @@ #include "coptind.h" #include "coptneg.h" #include "coptpush.h" +#include "coptsize.h" #include "coptstop.h" +#include "coptstore.h" #include "coptsub.h" #include "copttest.h" -#include "cpu.h" #include "error.h" #include "global.h" #include "codeopt.h" +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Shift types */ +enum { + SHIFT_NONE, + SHIFT_ASR_1, + SHIFT_ASL_1, + SHIFT_LSR_1, + SHIFT_LSL_1 +}; + + + /*****************************************************************************/ /* Optimize shifts */ /*****************************************************************************/ @@ -119,13 +137,17 @@ static unsigned OptShift1 (CodeSeg* S) static unsigned OptShift2 (CodeSeg* S) /* A call to the shraxN routine may get replaced by one or more lsr insns - * if the value of X is not used later. + * if the value of X is zero. */ { unsigned Changes = 0; + unsigned I; + + /* Generate register info */ + CS_GenRegInfo (S); /* Walk over the entries */ - unsigned I = 0; + I = 0; while (I < CS_GetEntryCount (S)) { /* Get next entry */ @@ -136,13 +158,13 @@ static unsigned OptShift2 (CodeSeg* S) strncmp (E->Arg, "shrax", 5) == 0 && strlen (E->Arg) == 6 && IsDigit (E->Arg[5]) && - !RegXUsed (S, I+1)) { + E->RI->In.RegX == 0) { /* Insert shift insns */ unsigned Count = E->Arg[5] - '0'; while (Count--) { CodeEntry* X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI); - CS_InsertEntry (S, X, I+1); + CS_InsertEntry (S, X, I+1); } /* Delete the call to shlax */ @@ -158,6 +180,215 @@ static unsigned OptShift2 (CodeSeg* S) } + /* Free the register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + +static unsigned GetShiftType (const char* Sub) +/* Helper function for OptShift3 */ +{ + if (*Sub == 'a') { + if (strcmp (Sub+1, "slax1") == 0) { + return SHIFT_ASL_1; + } else if (strcmp (Sub+1, "srax1") == 0) { + return SHIFT_ASR_1; + } + } else if (*Sub == 's') { + if (strcmp (Sub+1, "hlax1") == 0) { + return SHIFT_LSL_1; + } else if (strcmp (Sub+1, "hrax1") == 0) { + return SHIFT_LSR_1; + } + } + return SHIFT_NONE; +} + + + +static unsigned OptShift3 (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 = GetShiftType (L[2]->Arg)) != SHIFT_NONE&& + 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; +} + + + +/*****************************************************************************/ +/* Optimize loads */ +/*****************************************************************************/ + + + +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; + + /* Generate register info */ + CS_GenRegInfo (S); + + /* 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; + + } + + /* Free the register info */ + CS_FreeRegInfo (S); + /* Return the number of changes made */ return Changes; } @@ -197,7 +428,7 @@ static unsigned OptPtrStore1Sub (CodeSeg* S, unsigned I, CodeEntry** const L) (L[1] = CS_GetNextEntry (S, I)) != 0 && L[1]->OPC == OP65_SBC && !CE_HasLabel (L[1])) { - return 2; + return 2; } @@ -228,6 +459,20 @@ static unsigned OptPtrStore1 (CodeSeg* S) * subop * ldy yyy * sta (ptr1),y + * + * In case a/x is loaded from the register bank before the pushax, we can even + * use the register bank instead of ptr1. + */ +/* + * jsr pushax + * ldy xxx + * jsr ldauidx + * ldx #$00 + * lda (zp),y + * subop + * ldy yyy + * sta (zp),y + * jsr staspidx */ { unsigned Changes = 0; @@ -243,56 +488,90 @@ static unsigned OptPtrStore1 (CodeSeg* S) L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (CE_IsCall (L[0], "pushax") && + if (CE_IsCallTo (L[0], "pushax") && CS_GetEntries (S, L+1, I+1, 3) && L[1]->OPC == OP65_LDY && CE_KnownImm (L[1]) && !CE_HasLabel (L[1]) && - CE_IsCall (L[2], "ldauidx") && + CE_IsCallTo (L[2], "ldauidx") && !CE_HasLabel (L[2]) && (K = OptPtrStore1Sub (S, I+3, L+3)) > 0 && CS_GetEntries (S, L+3+K, I+3+K, 2) && L[3+K]->OPC == OP65_LDY && CE_KnownImm (L[3+K]) && !CE_HasLabel (L[3+K]) && - CE_IsCall (L[4+K], "staspidx") && + CE_IsCallTo (L[4+K], "staspidx") && !CE_HasLabel (L[4+K])) { - CodeEntry* X; - - /* Create and insert the stores */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+1); - X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+2); + const char* RegBank = 0; + const char* ZPLoc = "ptr1"; + CodeEntry* X; - /* Delete the call to pushax */ - CS_DelEntry (S, I); - /* Delete the call to ldauidx */ - CS_DelEntry (S, I+3); - - /* Insert the load from ptr1 */ + /* Get the preceeding two instructions and check them. We check + * for: + * lda regbank+n + * ldx regbank+n+1 + */ + if (I > 1) { + CodeEntry* P[2]; + P[0] = CS_GetEntry (S, I-2); + P[1] = CS_GetEntry (S, I-1); + if (P[0]->OPC == OP65_LDA && + P[0]->AM == AM65_ZP && + P[1]->OPC == OP65_LDX && + P[1]->AM == AM65_ZP && + !CE_HasLabel (P[1]) && + strncmp (P[0]->Arg, "regbank+", 8) == 0) { + + unsigned Len = strlen (P[0]->Arg); + + if (strncmp (P[0]->Arg, P[1]->Arg, Len) == 0 && + P[1]->Arg[Len+0] == '+' && + P[1]->Arg[Len+1] == '1' && + P[1]->Arg[Len+2] == '\0') { + + /* Ok, found. Use the name of the register bank */ + RegBank = ZPLoc = P[0]->Arg; + } + } + } + + /* Insert the load via the zp pointer */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI); CS_InsertEntry (S, X, I+3); - X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[2]->LI); - CS_InsertEntry (S, X, I+4); + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, ZPLoc, 0, L[2]->LI); + CS_InsertEntry (S, X, I+4); - /* Insert the store through ptr1 */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI); - CS_InsertEntry (S, X, I+6+K); + /* Insert the store through the zp pointer */ + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLoc, 0, L[3]->LI); + CS_InsertEntry (S, X, I+6+K); - /* Delete the call to staspidx */ - CS_DelEntry (S, I+7+K); + /* Delete the old code */ + CS_DelEntry (S, I+7+K); /* jsr spaspidx */ + CS_DelEntry (S, I+2); /* jsr ldauidx */ - /* Remember, we had changes */ - ++Changes; + /* Create and insert the stores into the zp pointer if needed */ + if (RegBank == 0) { + X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); + CS_InsertEntry (S, X, I+1); + X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); + CS_InsertEntry (S, X, I+2); + } - } + /* Delete more old code. Do it here to keep a label attached to + * entry I in place. + */ + CS_DelEntry (S, I); /* jsr pushax */ - /* Next entry */ - ++I; + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; } @@ -305,18 +584,24 @@ static unsigned OptPtrStore1 (CodeSeg* S) static unsigned OptPtrStore2 (CodeSeg* S) /* Search for the sequence: * - * jsr pushax - * lda xxx - * ldy yyy - * jsr staspidx + * lda #<(label+0) + * ldx #>(label+0) + * clc + * adc xxx + * bcc L + * inx + * L: jsr pushax + * ldx #$00 + * lda yyy + * ldy #$00 + * jsr staspidx * * and replace it by: * - * sta ptr1 - * stx ptr1+1 - * lda xxx - * ldy yyy - * sta (ptr1),y + * ldy xxx + * ldx #$00 + * lda yyy + * sta label,y */ { unsigned Changes = 0; @@ -325,39 +610,65 @@ static unsigned OptPtrStore2 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[4]; + CodeEntry* L[11]; + unsigned Len; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (CE_IsCall (L[0], "pushax") && - CS_GetEntries (S, L+1, I+1, 3) && - L[1]->OPC == OP65_LDA && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_LDY && - !CE_HasLabel (L[2]) && - CE_IsCall (L[3], "staspidx") && - !CE_HasLabel (L[3])) { + if (L[0]->OPC == OP65_LDA && + L[0]->AM == AM65_IMM && + CS_GetEntries (S, L+1, I+1, 10) && + 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 && + CE_IsCallTo (L[6], "pushax") && + L[7]->OPC == OP65_LDX && + L[8]->OPC == OP65_LDA && + L[9]->OPC == OP65_LDY && + CE_KnownImm (L[9]) && + L[9]->Num == 0 && + CE_IsCallTo (L[10], "staspidx") && + !CS_RangeHasLabel (S, I+1, 5) && + !CS_RangeHasLabel (S, I+7, 4) && + /* 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; - /* Create and insert the stores */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+1); + /* 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+11); - X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+2); + X = NewCodeEntry (OP65_LDX, L[7]->AM, L[7]->Arg, 0, L[7]->LI); + CS_InsertEntry (S, X, I+12); - /* Delete the call to pushax */ - CS_DelEntry (S, I); + X = NewCodeEntry (OP65_LDA, L[8]->AM, L[8]->Arg, 0, L[8]->LI); + CS_InsertEntry (S, X, I+13); - /* Insert the store through ptr1 */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI); - CS_InsertEntry (S, X, I+4); + Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3); + Label[Len-3] = '\0'; + X = NewCodeEntry (OP65_STA, AM65_ABSY, Label, 0, L[10]->LI); + CS_InsertEntry (S, X, I+14); + xfree (Label); - /* Delete the call to staspidx */ - CS_DelEntry (S, I+5); + /* Remove the old code */ + CS_DelEntries (S, I, 11); /* Remember, we had changes */ ++Changes; @@ -384,20 +695,26 @@ static unsigned OptPtrStore2 (CodeSeg* S) static unsigned OptPtrLoad1 (CodeSeg* S) /* Search for the sequence: * + * clc + * adc xxx + * tay + * txa + * adc yyy * tax - * dey - * lda (sp),y # May be any destination - * ldy ... + * tya + * ldy * jsr ldauidx * * and replace it by: * - * sta ptr1+1 - * dey - * lda (sp),y + * clc + * adc xxx * sta ptr1 - * ldy ... - * ldx #$00 + * txa + * adc yyy + * sta ptr1+1 + * ldy + * ldx #$00 * lda (ptr1),y */ { @@ -407,42 +724,69 @@ static unsigned OptPtrLoad1 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[5]; + CodeEntry* L[9]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (L[0]->OPC == OP65_TAX && - CS_GetEntries (S, L+1, I+1, 4) && - L[1]->OPC == OP65_DEY && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_LDA && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_LDY && - !CE_HasLabel (L[3]) && - CE_IsCall (L[4], "ldauidx") && - !CE_HasLabel (L[4])) { + if (L[0]->OPC == OP65_CLC && + CS_GetEntries (S, L+1, I+1, 8) && + L[1]->OPC == OP65_ADC && + 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_IsCallTo (L[8], "ldauidx") && + !CS_RangeHasLabel (S, I+1, 8)) { CodeEntry* X; + CodeEntry* P; - /* Store the high byte and remove the TAX instead */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+1); - CS_DelEntry (S, I); + /* Track the insertion point */ + unsigned IP = I+2; - /* Store the low byte */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI); - CS_InsertEntry (S, X, I+3); + /* sta ptr1 */ + X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI); + CS_InsertEntry (S, X, IP++); - /* Delete the call to ldauidx */ - CS_DelEntry (S, I+5); + /* 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++); - /* Load high and low byte */ - X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI); - CS_InsertEntry (S, X, I+5); - X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI); - CS_InsertEntry (S, X, I+6); + /* 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 ... */ + X = NewCodeEntry (OP65_LDY, L[7]->AM, L[7]->Arg, 0, L[7]->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, IP, 7); /* Remember, we had changes */ ++Changes; @@ -463,22 +807,22 @@ static unsigned OptPtrLoad1 (CodeSeg* S) static unsigned OptPtrLoad2 (CodeSeg* S) /* Search for the sequence: * - * clc * adc xxx - * tay + * pha * txa + * iny * adc yyy * tax - * tya + * pla * ldy * jsr ldauidx * * and replace it by: * - * clc * adc xxx * sta ptr1 * txa + * iny * adc yyy * sta ptr1+1 * ldy @@ -492,68 +836,141 @@ static unsigned OptPtrLoad2 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[9]; + CodeEntry* L[9]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (L[0]->OPC == OP65_CLC && + if (L[0]->OPC == OP65_ADC && CS_GetEntries (S, L+1, I+1, 8) && - L[1]->OPC == OP65_ADC && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_TAY && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_TXA && - !CE_HasLabel (L[3]) && - L[4]->OPC == OP65_ADC && - !CE_HasLabel (L[4]) && - L[5]->OPC == OP65_TAX && - !CE_HasLabel (L[5]) && - L[6]->OPC == OP65_TYA && - !CE_HasLabel (L[6]) && - L[7]->OPC == OP65_LDY && - !CE_HasLabel (L[7]) && - CE_IsCall (L[8], "ldauidx") && - !CE_HasLabel (L[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; - CodeEntry* P; + CodeEntry* X; - /* Store the low byte and remove the TAY instead */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[1]->LI); - CS_InsertEntry (S, X, I+2); - CS_DelEntry (S, I+3); + /* 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+5); + /* Store the high byte */ + X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI); + CS_InsertEntry (S, X, I+6); - /* If the instruction before the adc is a ldx, replace the - * txa by and lda with the same location of the ldx. - */ - if ((P = CS_GetPrevEntry (S, I)) != 0 && - P->OPC == OP65_LDX && - !CE_HasLabel (P)) { + /* 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); - X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI); - CS_InsertEntry (S, X, I+4); - CS_DelEntry (S, I+3); - } + /* 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 */ - /* Delete more transfer insns */ - CS_DelEntry (S, I+7); - CS_DelEntry (S, I+6); + /* Remember, we had changes */ + ++Changes; - /* Delete the call to ldauidx */ - CS_DelEntry (S, I+7); + } - /* Load high and low byte */ - X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[7]->LI); - CS_InsertEntry (S, X, I+7); - X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[7]->LI); + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +static 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_KnownImm (L[6]) && + L[6]->Num == 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; @@ -570,30 +987,26 @@ static unsigned OptPtrLoad2 (CodeSeg* S) -static unsigned OptPtrLoad3 (CodeSeg* S) +static unsigned OptPtrLoad4 (CodeSeg* S) /* Search for the sequence: * - * adc xxx - * pha - * txa - * iny - * adc yyy - * tax - * pla - * ldy - * jsr ldauidx + * lda #<(label+0) + * ldx #>(label+0) + * ldy #$xx + * clc + * adc (sp),y + * bcc L + * inx + * L: ldy #$00 + * jsr ldauidx * * and replace it by: * - * adc xxx - * sta ptr1 - * txa - * iny - * adc yyy - * sta ptr1+1 - * ldy - * ldx #$00 - * lda (ptr1),y + * ldy #$xx + * lda (sp),y + * tay + * ldx #$00 + * lda label,y */ { unsigned Changes = 0; @@ -603,53 +1016,216 @@ static unsigned OptPtrLoad3 (CodeSeg* S) 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_ADC && - CS_GetEntries (S, L+1, I+1, 8) && - L[1]->OPC == OP65_PHA && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_TXA && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_INY && - !CE_HasLabel (L[3]) && - L[4]->OPC == OP65_ADC && - !CE_HasLabel (L[4]) && - L[5]->OPC == OP65_TAX && - !CE_HasLabel (L[5]) && - L[6]->OPC == OP65_PLA && - !CE_HasLabel (L[6]) && - L[7]->OPC == OP65_LDY && - !CE_HasLabel (L[7]) && - CE_IsCall (L[8], "ldauidx") && - !CE_HasLabel (L[8])) { + 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_KnownImm (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_KnownImm (L[7]) && + L[7]->Num == 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; +} + + + +static unsigned OptPtrLoad5 (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 OptPtrLoad5! + * + */ +{ + 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_KnownImm (L[5]) && + L[5]->Num == 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_KnownImm (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); + } - CodeEntry* X; + /* 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]); - /* 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); - CS_DelEntry (S, I+2); + /* ldy #$xx */ + X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI); + CS_InsertEntry (S, X, I+14); - /* Store the high byte */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI); - CS_InsertEntry (S, X, I+5); + /* ldx #$xx */ + X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI); + CS_InsertEntry (S, X, I+15); - /* Delete more transfer and PLA insns */ - CS_DelEntry (S, I+7); - CS_DelEntry (S, I+6); + /* lda (regbank+n),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI); + CS_InsertEntry (S, X, I+16); - /* Delete the call to ldauidx */ - CS_DelEntry (S, I+7); + /* inc regbank+n */ + X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI); + CS_InsertEntry (S, X, I+17); - /* Load high and low byte */ - X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI); - CS_InsertEntry (S, X, I+7); - X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI); - CS_InsertEntry (S, X, I+8); + /* 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; @@ -667,23 +1243,19 @@ static unsigned OptPtrLoad3 (CodeSeg* S) -static unsigned OptPtrLoad4 (CodeSeg* S) +static unsigned OptPtrLoad6 (CodeSeg* S) /* Search for the sequence: * - * lda #<(label+0) - * ldx #>(label+0) - * clc - * adc xxx - * bcc L - * inx - * L: ldy #$00 + * lda zp + * ldx zp+1 + * ldy xx * jsr ldauidx * * and replace it by: * - * ldy xxx + * ldy xx * ldx #$00 - * lda label,y + * lda (zp),y */ { unsigned Changes = 0; @@ -692,63 +1264,36 @@ static unsigned OptPtrLoad4 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[8]; + 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_IMM && - CS_GetEntries (S, L+1, I+1, 7) && - L[1]->OPC == OP65_LDX && - L[1]->AM == AM65_IMM && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_CLC && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_ADC && - (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP) && - !CE_HasLabel (L[3]) && - (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) && - L[4]->JumpTo != 0 && - L[4]->JumpTo->Owner == L[6] && - !CE_HasLabel (L[4]) && - L[5]->OPC == OP65_INX && - !CE_HasLabel (L[5]) && - L[6]->OPC == OP65_LDY && - CE_KnownImm (L[6]) && - L[6]->Num == 0 && - CE_IsCall (L[7], "ldauidx") && - !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) { + 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; - 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); + /* ldx #$00 */ + X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI); + CS_InsertEntry (S, X, I+3); - 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); + /* 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_DelEntries (S, I, 8); + CS_DelEntry (S, I+5); + CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; @@ -766,26 +1311,21 @@ static unsigned OptPtrLoad4 (CodeSeg* S) -static unsigned OptPtrLoad5 (CodeSeg* S) +static unsigned OptPtrLoad7 (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 + * lda zp + * ldx zp+1 + * ldy xx + * jsr ldaxidx * * and replace it by: * - * ldy #$xx - * lda (sp),y - * tay - * ldx #$00 - * lda label,y + * ldy xx + * lda (zp),y + * tax + * dey + * lda (zp),y */ { unsigned Changes = 0; @@ -794,71 +1334,44 @@ static unsigned OptPtrLoad5 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[9]; + 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_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_KnownImm (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_KnownImm (L[7]) && - L[7]->Num == 0 && - CE_IsCall (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) { + 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], "ldaxidx")) { 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); + /* lda (zp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->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); + /* tax */ + X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->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); + /* dey */ + X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI); + CS_InsertEntry (S, X, I+6); + + /* lda (zp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); + CS_InsertEntry (S, X, I+7); /* Remove the old code */ + CS_DelEntry (S, I+3); CS_DelEntries (S, I, 2); - CS_DelEntries (S, I+5, 6); /* Remember, we had changes */ ++Changes; @@ -876,7 +1389,7 @@ static unsigned OptPtrLoad5 (CodeSeg* S) -static unsigned OptPtrLoad6 (CodeSeg* S) +static unsigned OptPtrLoad8 (CodeSeg* S) /* Search for the sequence * * ldy ... @@ -890,7 +1403,7 @@ static unsigned OptPtrLoad6 (CodeSeg* S) * ldx #$00 * lda (ptr1),y * - * This step must be execute *after* OptPtrLoad1! + * This step must be executed *after* OptPtrLoad1! */ { unsigned Changes = 0; @@ -907,7 +1420,7 @@ static unsigned OptPtrLoad6 (CodeSeg* S) /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CS_GetEntries (S, L+1, I+1, 1) && - CE_IsCall (L[1], "ldauidx") && + CE_IsCallTo (L[1], "ldauidx") && !CE_HasLabel (L[1])) { CodeEntry* X; @@ -962,9 +1475,9 @@ static unsigned OptDecouple (CodeSeg* S) * txa -> lda #imm * tay -> ldy #imm * tya -> lda #imm - * lda sreg -> lda #imm - * ldx sreg -> ldx #imm - * ldy sreg -> ldy #imm + * lda zp -> lda #imm + * ldx zp -> ldx #imm + * ldy zp -> ldy #imm * * Provided that the register values are known of course. */ @@ -979,10 +1492,11 @@ static unsigned OptDecouple (CodeSeg* S) I = 0; while (I < CS_GetEntryCount (S)) { - char Buf [16]; + const char* Arg; - /* Get next entry */ + /* Get next entry and it's input register values */ CodeEntry* E = CS_GetEntry (S, I); + const RegContents* In = &E->RI->In; /* Assume we have no replacement */ CodeEntry* X = 0; @@ -990,95 +1504,166 @@ static unsigned OptDecouple (CodeSeg* S) /* Check the instruction */ switch (E->OPC) { + case OP65_DEA: + if (RegValIsKnown (In->RegA)) { + Arg = MakeHexArg ((In->RegA - 1) & 0xFF); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + } + break; + case OP65_DEX: - if (E->RI->In.RegX >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegX - 1) & 0xFF); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI); + if (RegValIsKnown (In->RegX)) { + Arg = MakeHexArg ((In->RegX - 1) & 0xFF); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_DEY: - if (E->RI->In.RegY >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegY - 1) & 0xFF); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI); + if (RegValIsKnown (In->RegY)) { + Arg = MakeHexArg ((In->RegY - 1) & 0xFF); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + } + break; + + case OP65_INA: + if (RegValIsKnown (In->RegA)) { + Arg = MakeHexArg ((In->RegA + 1) & 0xFF); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; case OP65_INX: - if (E->RI->In.RegX >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegX + 1) & 0xFF); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI); + if (RegValIsKnown (In->RegX)) { + Arg = MakeHexArg ((In->RegX + 1) & 0xFF); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_INY: - if (E->RI->In.RegY >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", (E->RI->In.RegY + 1) & 0xFF); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI); + if (RegValIsKnown (In->RegY)) { + Arg = MakeHexArg ((In->RegY + 1) & 0xFF); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } break; case OP65_LDA: if (E->AM == AM65_ZP) { - if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo); - X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI); - } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi); - X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI); + switch (GetKnownReg (E->Use & REG_ZP, In)) { + case REG_TMP1: + Arg = MakeHexArg (In->Tmp1); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_LO: + Arg = MakeHexArg (In->Ptr1Lo); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_HI: + Arg = MakeHexArg (In->Ptr1Hi); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_LO: + Arg = MakeHexArg (In->SRegLo); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_HI: + Arg = MakeHexArg (In->SRegHi); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); + break; } } break; case OP65_LDX: if (E->AM == AM65_ZP) { - if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI); - } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI); + switch (GetKnownReg (E->Use & REG_ZP, In)) { + case REG_TMP1: + Arg = MakeHexArg (In->Tmp1); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_LO: + Arg = MakeHexArg (In->Ptr1Lo); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_HI: + Arg = MakeHexArg (In->Ptr1Hi); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_LO: + Arg = MakeHexArg (In->SRegLo); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_HI: + Arg = MakeHexArg (In->SRegHi); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); + break; } } break; case OP65_LDY: if (E->AM == AM65_ZP) { - if ((E->Use & REG_SREG_LO) != 0 && E->RI->In.SRegLo >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegLo); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI); - } else if ((E->Use & REG_SREG_HI) != 0 && E->RI->In.SRegHi >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.SRegHi); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI); + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Arg = MakeHexArg (In->Tmp1); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_LO: + Arg = MakeHexArg (In->Ptr1Lo); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_PTR1_HI: + Arg = MakeHexArg (In->Ptr1Hi); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_LO: + Arg = MakeHexArg (In->SRegLo); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + break; + + case REG_SREG_HI: + Arg = MakeHexArg (In->SRegHi); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); + break; } } break; case OP65_TAX: if (E->RI->In.RegA >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegA); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Buf, 0, E->LI); + Arg = MakeHexArg (In->RegA); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TAY: if (E->RI->In.RegA >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegA); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, E->LI); + Arg = MakeHexArg (In->RegA); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TXA: if (E->RI->In.RegX >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegX); - X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI); + Arg = MakeHexArg (In->RegX); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TYA: if (E->RI->In.RegY >= 0) { - xsprintf (Buf, sizeof (Buf), "$%02X", E->RI->In.RegY); - X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, E->LI); + Arg = MakeHexArg (In->RegY); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; @@ -1090,220 +1675,7 @@ static unsigned OptDecouple (CodeSeg* S) /* Insert the replacement if we have one */ if (X) { - CS_InsertEntry (S, X, I+1); - CS_DelEntry (S, I); - ++Changes; - } - - /* Next entry */ - ++I; - - } - - /* Free register info */ - CS_FreeRegInfo (S); - - /* Return the number of changes made */ - return Changes; -} - - - -/*****************************************************************************/ -/* Size optimization */ -/*****************************************************************************/ - - - -#if 0 -static unsigned OptSize1 (CodeSeg* S) -/* Do size optimization by calling special subroutines that preload registers. - * This routine does not work standalone, it needs a following register load - * removal pass. - */ -{ - static const char* Func = { - "stax0sp", /* staxysp, y = 0 */ - "addeq0sp", - "ldax0sp", /* ldaxysp, y = 1 */ - "ldeax0sp", /* ldeaxysp, y = 3 */ - "push0", /* pushax, a = 0, x = 0 */ - "pusha0", /* pushax, x = 0 */ - "pushaFF", /* pushax, x = ff */ - "pusha0sp", /* pushaysp, y = 0 */ - "tosadda0", /* tosaddax, x = 0 */ - "tosanda0", /* tosandax, x = 0 */ - "tosdiva0", /* tosdivax, x = 0 */ - "toseqa0", /* toseqax, x = 0 */ - "tosgea0", /* tosgeax, x = 0 */ - "tosgta0", /* tosgtax, x = 0 */ - "tosadd0ax", /* tosaddeax, sreg = 0 */ - "laddeqa", /* laddeq, sreg = 0, x = 0 */ - "laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */ - "laddeq0sp", /* laddeqysp, y = 0 */ - "tosand0ax", /* tosandeax, sreg = 0 */ - "ldaxi", /* ldaxidx, y = 1 */ - "ldeaxi", /* ldeaxidx, y = 3 */ - "ldeax0sp", /* ldeaxysp, y = 3 */ - "tosdiv0ax", /* tosdiveax, sreg = 0 */ - "toslea0", /* tosleax, x = 0 */ - "tosmod0ax", /* tosmodeax, sreg = 0 */ - "tosmul0ax", /* tosmuleax, sreg = 0 */ - "tosumul0ax", /* tosumuleax, sreg = 0 */ - "tosor0ax", /* tosoreax, sreg = 0 */ - "push0ax", /* pusheax, sreg = 0 */ - "tosrsub0ax", /* tosrsubeax, sreg = 0 */ - "tosshl0ax", /* tosshleax, sreg = 0 */ - "tosasl0ax", /* tosasleax, sreg = 0 */ - "tosshr0ax", /* tosshreax, sreg = 0 */ - "tosasr0ax", /* tosasreax, sreg = 0 */ - "tossub0ax", /* tossubeax, sreg = 0 */ - "lsubeqa", /* lsubeq, sreg = 0, x = 0 */ - "lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */ - "lsubeq0sp", /* lsubeqysp, y = 0 */ - "toslta0", /* tosltax, x = 0 */ - "tosudiv0ax", /* tosudiveax, sreg = 0 */ - "tosumod0ax", /* tosumodeax, sreg = 0 */ - "tosxor0ax", /* tosxoreax, sreg = 0 */ - "tosmoda0", /* tosmodax, x = 0 */ - "tosmula0", /* tosmulax, x = 0 */ - "tosumula0", /* tosumulax, x = 0 */ - "tosnea0", /* tosneax, x = 0 */ - "tosora0", /* tosorax, x = 0 */ - "push1", /* pushax, x = 0, a = 1 */ - "push2", /* pushax, x = 0, a = 2 */ - "push3", /* pushax, x = 0, a = 3 */ - "push4", /* pushax, x = 0, a = 4 */ - "push5", /* pushax, x = 0, a = 5 */ - "push6", /* pushax, x = 0, a = 6 */ - "push7", /* pushax, x = 0, a = 7 */ - "pushc0", /* pusha, a = 0 */ - "pushc1", /* pusha, a = 1 */ - "pushc2", /* pusha, a = 2 */ - "tosrsuba0", /* tosrsubax, x = 0 */ - "tosshla0", /* tosshlax, x = 0 */ - "tosasla0", /* tosaslax, x = 0 */ - "tosshra0", /* tosshrax, x = 0 */ - "tosasra0", /* tosasrax, x = 0 */ - "steax0sp", /* steaxsp, y = 0 */ - "tossuba0", /* tossubax, x = 0 */ - "subeq0sp", /* subeqysp, y = 0 */ - "tosudiva0", /* tosudivax, x = 0 */ - "tosugea0", /* tosugeax, x = 0 */ - "tosugta0", /* tosugtax, x = 0 */ - "tosulea0", /* tosuleax, x = 0 */ - "tosulta0", /* tosultax, x = 0 */ - "tosumoda0", /* tosumodax, x = 0 */ - "tosxora0", /* tosxorax, x = 0 */ - }; - - unsigned Changes = 0; - unsigned I; - - /* Generate register info for the following step */ - CS_GenRegInfo (S); - - /* Walk over the entries */ - I = 0; - while (I < CS_GetEntryCount (S)) { - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - - /* Next entry */ - ++I; - - } - - /* Free register info */ - CS_FreeRegInfo (S); - - /* Return the number of changes made */ - return Changes; -} -#endif - - - -static unsigned OptSize2 (CodeSeg* S) -/* Do size optimization by using shorter code sequences, even if this - * introduces relations between instructions. This step must be one of the - * last steps, because it makes further work much more difficult. - */ -{ - unsigned Changes = 0; - unsigned I; - - /* Generate register info for the following step */ - CS_GenRegInfo (S); - - /* Walk over the entries */ - I = 0; - while (I < CS_GetEntryCount (S)) { - - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Assume we have no replacement */ - CodeEntry* X = 0; - - /* Check the instruction */ - switch (E->OPC) { - - case OP65_LDA: - if (CE_KnownImm (E)) { - short Val = (short) E->Num; - if (Val == E->RI->In.RegX) { - X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegY) { - X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegA >= 0 && CPU >= CPU_65C02) { - if (Val == ((E->RI->In.RegA - 1) & 0xFF)) { - X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI); - } else if (Val == ((E->RI->In.RegA + 1) & 0xFF)) { - X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI); - } - } - } - break; - - case OP65_LDX: - if (CE_KnownImm (E)) { - short Val = (short) E->Num; - if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX - 1) & 0xFF)) { - X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX + 1) & 0xFF)) { - X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegA) { - X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI); - } - } - break; - - case OP65_LDY: - if (CE_KnownImm (E)) { - short Val = (short) E->Num; - if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY - 1) & 0xFF)) { - X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY + 1) & 0xFF)) { - X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegA) { - X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI); - } - } - break; - - default: - /* Avoid gcc warnings */ - break; - - } - - /* Insert the replacement if we have one */ - if (X) { - CS_InsertEntry (S, X, I+1); + CS_InsertEntry (S, X, I+1); CS_DelEntry (S, I); ++Changes; } @@ -1351,18 +1723,22 @@ struct OptFunc { /* A list of all the function descriptions */ static OptFunc DOpt65C02BitOps = { Opt65C02BitOps, "Opt65C02BitOps", 66, 0, 0, 0, 0, 0 }; static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 60, 0, 0, 0, 0, 0 }; +static OptFunc DOpt65C02Stores = { Opt65C02Stores, "Opt65C02Stores", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 125, 0, 0, 0, 0, 0 }; static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 200, 0, 0, 0, 0, 0 }; -static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 40, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 90, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd4 = { OptAdd4, "OptAdd4", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd5 = { OptAdd5, "OptAdd5", 40, 0, 0, 0, 0, 0 }; static OptFunc DOptBoolTrans = { OptBoolTrans, "OptBoolTrans", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBranchDist = { OptBranchDist, "OptBranchDist", 0, 0, 0, 0, 0, 0 }; -static OptFunc DOptCmp1 = { OptCmp1, "OptCmp1", 85, 0, 0, 0, 0, 0 }; -static OptFunc DOptCmp2 = { OptCmp2, "OptCmp2", 75, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp1 = { OptCmp1, "OptCmp1", 42, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp2 = { OptCmp2, "OptCmp2", 85, 0, 0, 0, 0, 0 }; static OptFunc DOptCmp3 = { OptCmp3, "OptCmp3", 75, 0, 0, 0, 0, 0 }; -static OptFunc DOptCmp4 = { OptCmp4, "OptCmp4", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp4 = { OptCmp4, "OptCmp4", 75, 0, 0, 0, 0, 0 }; static OptFunc DOptCmp5 = { OptCmp5, "OptCmp5", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptCmp6 = { OptCmp6, "OptCmp6", 85, 0, 0, 0, 0, 0 }; -static OptFunc DOptCmp7 = { OptCmp7, "OptCmp7", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp6 = { OptCmp6, "OptCmp6", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp7 = { OptCmp7, "OptCmp7", 85, 0, 0, 0, 0, 0 }; +static OptFunc DOptCmp8 = { OptCmp8, "OptCmp8", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptCondBranches = { OptCondBranches, "OptCondBranches", 80, 0, 0, 0, 0, 0 }; static OptFunc DOptDeadCode = { OptDeadCode, "OptDeadCode", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptDeadJumps = { OptDeadJumps, "OptDeadJumps", 100, 0, 0, 0, 0, 0 }; @@ -1370,6 +1746,7 @@ static OptFunc DOptDecouple = { OptDecouple, "OptDecouple", 100, 0, static OptFunc DOptDupLoads = { OptDupLoads, "OptDupLoads", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptJumpTarget = { OptJumpTarget, "OptJumpTarget", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptRTS = { OptRTS, "OptRTS", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptRTSJumps1 = { OptRTSJumps1, "OptRTSJumps1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptRTSJumps2 = { OptRTSJumps2, "OptRTSJumps2", 100, 0, 0, 0, 0, 0 }; @@ -1379,25 +1756,36 @@ static OptFunc DOptNegAX1 = { OptNegAX1, "OptNegAX1", 100, 0, static OptFunc DOptNegAX2 = { OptNegAX2, "OptNegAX2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX3 = { OptNegAX3, "OptNegAX3", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX4 = { OptNegAX4, "OptNegAX4", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPrecalc = { OptPrecalc, "OptPrecalc", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad1 = { OptPtrLoad1, "OptPtrLoad1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad2 = { OptPtrLoad2, "OptPtrLoad2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad3 = { OptPtrLoad3, "OptPtrLoad3", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad4 = { OptPtrLoad4, "OptPtrLoad4", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad5 = { OptPtrLoad5, "OptPtrLoad5", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad5 = { OptPtrLoad5, "OptPtrLoad5", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 65, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad7 = { OptPtrLoad7, "OptPtrLoad7", 86, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad8 = { OptPtrLoad8, "OptPtrLoad8", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 40, 0, 0, 0, 0, 0 }; static OptFunc DOptPush1 = { OptPush1, "OptPush1", 65, 0, 0, 0, 0, 0 }; +static OptFunc DOptPush2 = { OptPush2, "OptPush2", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptPushPop = { OptPushPop, "OptPushPop", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptShift1 = { OptShift1, "OptShift1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptShift2 = { OptShift2, "OptShift2", 100, 0, 0, 0, 0, 0 }; -/*static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 };*/ +static OptFunc DOptShift3 = { OptShift3, "OptShift3", 110, 0, 0, 0, 0, 0 }; +static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSize2 = { OptSize2, "OptSize2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore1 = { OptStore1, "OptStore1", 70, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore2 = { OptStore2, "OptStore2", 220, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore3 = { OptStore3, "OptStore3", 120, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore4 = { OptStore4, "OptStore4", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptTest1 = { OptTest1, "OptTest1", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptTransfers = { OptTransfers, "OptTransfers", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptTransfers1 = { OptTransfers1, "OptTransfers1", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptTransfers2 = { OptTransfers2, "OptTransfers2", 60, 0, 0, 0, 0, 0 }; static OptFunc DOptUnusedLoads = { OptUnusedLoads, "OptUnusedLoads", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0, 0 }; @@ -1406,9 +1794,12 @@ static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, static OptFunc* OptFuncs[] = { &DOpt65C02BitOps, &DOpt65C02Ind, + &DOpt65C02Stores, &DOptAdd1, &DOptAdd2, &DOptAdd3, + &DOptAdd4, + &DOptAdd5, &DOptBoolTrans, &DOptBranchDist, &DOptCmp1, @@ -1418,6 +1809,7 @@ static OptFunc* OptFuncs[] = { &DOptCmp5, &DOptCmp6, &DOptCmp7, + &DOptCmp8, &DOptCondBranches, &DOptDeadCode, &DOptDeadJumps, @@ -1425,34 +1817,46 @@ static OptFunc* OptFuncs[] = { &DOptDupLoads, &DOptJumpCascades, &DOptJumpTarget, + &DOptLoad1, &DOptNegA1, &DOptNegA2, &DOptNegAX1, &DOptNegAX2, &DOptNegAX3, &DOptNegAX4, + &DOptPrecalc, &DOptPtrLoad1, &DOptPtrLoad2, &DOptPtrLoad3, &DOptPtrLoad4, &DOptPtrLoad5, &DOptPtrLoad6, + &DOptPtrLoad7, + &DOptPtrLoad8, &DOptPtrStore1, &DOptPtrStore2, &DOptPush1, + &DOptPush2, + &DOptPushPop, &DOptRTS, &DOptRTSJumps1, &DOptRTSJumps2, &DOptShift1, &DOptShift2, - /*&DOptSize1,*/ + &DOptShift3, + &DOptSize1, &DOptSize2, &DOptStackOps, + &DOptStore1, + &DOptStore2, + &DOptStore3, + &DOptStore4, &DOptStoreLoad, &DOptSub1, &DOptSub2, &DOptTest1, - &DOptTransfers, + &DOptTransfers1, + &DOptTransfers2, &DOptUnusedLoads, &DOptUnusedStores, }; @@ -1621,15 +2025,21 @@ static void WriteOptStats (const char* Name) return; } - /* Write the file */ + /* Write a header */ + fprintf (F, + "; Optimizer Total Last Total Last\n" + "; Step Runs Runs Chg Chg\n"); + + + /* Write the data */ for (I = 0; I < OPTFUNC_COUNT; ++I) { - const OptFunc* O = OptFuncs[I]; - fprintf (F, - "%-20s %6lu %6lu %6lu %6lu\n", - O->Name, + const OptFunc* O = OptFuncs[I]; + fprintf (F, + "%-20s %10lu %10lu %10lu %10lu\n", + O->Name, O->TotalRuns, O->LastRuns, - O->TotalChanges, + O->TotalChanges, O->LastChanges); } @@ -1647,7 +2057,7 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max) /* Don't run the function if it is disabled or if it is prohibited by the * code size factor */ - if (F->Disabled || CodeSizeFactor < F->CodeSizeFactor) { + if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) { return 0; } @@ -1689,14 +2099,22 @@ static unsigned RunOptGroup1 (CodeSeg* S) Changes += RunOptFunc (S, &DOptPtrLoad3, 1); Changes += RunOptFunc (S, &DOptPtrLoad4, 1); Changes += RunOptFunc (S, &DOptPtrLoad5, 1); + Changes += RunOptFunc (S, &DOptPtrLoad6, 1); + Changes += RunOptFunc (S, &DOptPtrLoad7, 1); Changes += RunOptFunc (S, &DOptNegAX1, 1); Changes += RunOptFunc (S, &DOptNegAX2, 1); Changes += RunOptFunc (S, &DOptNegAX3, 1); Changes += RunOptFunc (S, &DOptNegAX4, 1); Changes += RunOptFunc (S, &DOptAdd1, 1); Changes += RunOptFunc (S, &DOptAdd2, 1); + Changes += RunOptFunc (S, &DOptAdd3, 1); + Changes += RunOptFunc (S, &DOptStore4, 1); Changes += RunOptFunc (S, &DOptShift1, 1); Changes += RunOptFunc (S, &DOptShift2, 1); + Changes += RunOptFunc (S, &DOptShift3, 1); + Changes += RunOptFunc (S, &DOptStore1, 1); + Changes += RunOptFunc (S, &DOptStore2, 5); + Changes += RunOptFunc (S, &DOptStore3, 5); /* Return the number of changes */ return Changes; @@ -1733,12 +2151,13 @@ static unsigned RunOptGroup3 (CodeSeg* S) do { C = 0; - C += RunOptFunc (S, &DOptPtrLoad6, 1); + C += RunOptFunc (S, &DOptPtrLoad8, 1); C += RunOptFunc (S, &DOptNegA1, 1); C += RunOptFunc (S, &DOptNegA2, 1); C += RunOptFunc (S, &DOptSub1, 1); C += RunOptFunc (S, &DOptSub2, 1); - C += RunOptFunc (S, &DOptAdd3, 1); + C += RunOptFunc (S, &DOptAdd4, 1); + C += RunOptFunc (S, &DOptAdd5, 1); C += RunOptFunc (S, &DOptStackOps, 1); C += RunOptFunc (S, &DOptJumpCascades, 1); C += RunOptFunc (S, &DOptDeadJumps, 1); @@ -1755,12 +2174,16 @@ static unsigned RunOptGroup3 (CodeSeg* S) C += RunOptFunc (S, &DOptCmp5, 1); C += RunOptFunc (S, &DOptCmp6, 1); C += RunOptFunc (S, &DOptCmp7, 1); + C += RunOptFunc (S, &DOptCmp8, 1); C += RunOptFunc (S, &DOptTest1, 1); + C += RunOptFunc (S, &DOptLoad1, 1); C += RunOptFunc (S, &DOptUnusedLoads, 1); C += RunOptFunc (S, &DOptUnusedStores, 1); C += RunOptFunc (S, &DOptDupLoads, 1); C += RunOptFunc (S, &DOptStoreLoad, 1); - C += RunOptFunc (S, &DOptTransfers, 1); + C += RunOptFunc (S, &DOptTransfers1, 1); + C += RunOptFunc (S, &DOptPushPop, 1); + C += RunOptFunc (S, &DOptPrecalc, 1); Changes += C; @@ -1775,17 +2198,17 @@ static unsigned RunOptGroup3 (CodeSeg* S) static unsigned RunOptGroup4 (CodeSeg* S) /* 65C02 specific optimizations. */ { - unsigned C; unsigned Changes = 0; - if (CPU >= CPU_65C02) { + if (CPUIsets[CPU] & CPU_ISET_65SC02) { Changes += RunOptFunc (S, &DOpt65C02BitOps, 1); - /* Replace (zp),y by (zp) if Y is zero. If we have changes, run register - * load optimization again, since loads of Y may have become unnecessary. - */ - C = RunOptFunc (S, &DOpt65C02Ind, 1); - Changes += C; - if (C) { + Changes += RunOptFunc (S, &DOpt65C02Ind, 1); + Changes += RunOptFunc (S, &DOpt65C02Stores, 1); + if (Changes) { + /* The 65C02 replacement codes do often make the use of a register + * value unnecessary, so if we have changes, run another load + * removal pass. + */ Changes += RunOptFunc (S, &DOptUnusedLoads, 1); } } @@ -1804,6 +2227,9 @@ static unsigned RunOptGroup5 (CodeSeg* S) unsigned Changes = 0; Changes += RunOptFunc (S, &DOptPush1, 1); + Changes += RunOptFunc (S, &DOptPush2, 1); + Changes += RunOptFunc (S, &DOptUnusedLoads, 1); + Changes += RunOptFunc (S, &DOptTransfers2, 1); /* Return the number of changes */ return Changes; @@ -1818,16 +2244,30 @@ static unsigned RunOptGroup6 (CodeSeg* S) unsigned Changes = 0; unsigned C; - /* Optimize for size, that is replace operations by shorter ones, even - * if this does hinder further optimizations (no problem since we're - * done soon). - */ - Changes += RunOptFunc (S, &DOptSize2, 1); - - /* Run the jump target optimization again, since the size optimization - * above may have opened new oportunities. - */ - Changes += RunOptFunc (S, &DOptJumpTarget, 5); + if (S->CodeSizeFactor <= 100) { + /* Optimize for size, that is replace operations by shorter ones, even + * if this does hinder further optimizations (no problem since we're + * done soon). + */ + C = RunOptFunc (S, &DOptSize1, 1); + if (C) { + Changes += C; + /* Run some optimization passes again, since the size optimizations + * may have opened new oportunities. + */ + Changes += RunOptFunc (S, &DOptUnusedLoads, 1); + Changes += RunOptFunc (S, &DOptJumpTarget, 5); + } + } + C = RunOptFunc (S, &DOptSize2, 1); + if (C) { + Changes += C; + /* Run some optimization passes again, since the size optimizations + * may have opened new oportunities. + */ + Changes += RunOptFunc (S, &DOptUnusedLoads, 1); + Changes += RunOptFunc (S, &DOptJumpTarget, 5); + } /* Adjust branch distances */ Changes += RunOptFunc (S, &DOptBranchDist, 3); @@ -1853,7 +2293,7 @@ void RunOpt (CodeSeg* S) const char* StatFileName; /* If we shouldn't run the optimizer, bail out */ - if (!Optimize) { + if (!S->Optimize) { return; }