From 7c9b27c048c3ef019d5233d54e340a90b1a5e99c Mon Sep 17 00:00:00 2001 From: uz Date: Fri, 15 Jun 2012 20:51:14 +0000 Subject: [PATCH] Be more flexible when detecting a special sequence that can be optimized. git-svn-id: svn://svn.cc65.org/cc65/trunk@5718 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeent.c | 10 +- src/cc65/codeent.h | 10 ++ src/cc65/codeopt.c | 7 +- src/cc65/coptptrstore.c | 377 ++++++++++++++++++++++------------------ src/cc65/coptptrstore.h | 65 ++++--- 5 files changed, 251 insertions(+), 218 deletions(-) diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index 8c73081b6..61fe1ac8a 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -397,7 +397,7 @@ void CE_SetNumArg (CodeEntry* E, long Num) int CE_IsConstImm (const CodeEntry* E) /* Return true if the argument of E is a constant immediate value */ { - return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0); + return (E->AM == AM65_IMM && CE_HasNumArg (E)); } @@ -407,9 +407,7 @@ int CE_IsKnownImm (const CodeEntry* E, unsigned long Num) * equal to Num. */ { - return E->AM == AM65_IMM && - (E->Flags & CEF_NUMARG) != 0 && - E->Num == Num; + return (E->AM == AM65_IMM && CE_HasNumArg (E) && E->Num == Num); } @@ -1388,7 +1386,7 @@ void CE_Output (const CodeEntry* E) /* Print the mnemonic */ Chars = WriteOutput ("\t%s", D->Mnemo); - + /* Space to leave before the operand */ Space = 9 - Chars; @@ -1453,7 +1451,7 @@ void CE_Output (const CodeEntry* E) } /* Print usage info if requested by the debugging flag */ - if (Debug) { + if (Debug) { char Use [128]; char Chg [128]; WriteOutput ("%*s; USE: %-12s CHG: %-12s SIZE: %u", diff --git a/src/cc65/codeent.h b/src/cc65/codeent.h index db3d17106..303adc7fc 100644 --- a/src/cc65/codeent.h +++ b/src/cc65/codeent.h @@ -183,6 +183,16 @@ INLINE void CE_ResetMark (CodeEntry* E) # define CE_ResetMark(E) ((E)->Flags &= ~CEF_USERMARK) #endif +#if defined(HAVE_INLINE) +INLINE int CE_HasNumArg (const CodeEntry* E) +/* Return true if the instruction has a numeric argument */ +{ + return (E->Flags & CEF_NUMARG) != 0; +} +#else +# define CE_HasNumArg(E) (((E)->Flags & CEF_NUMARG) != 0) +#endif + void CE_SetArg (CodeEntry* E, const char* Arg); /* Replace the argument by the new one. */ diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index def758a8a..16b18965f 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -1200,12 +1200,11 @@ static OptFunc DOptPtrLoad14 = { OptPtrLoad14, "OptPtrLoad14", 108, 0, static OptFunc DOptPtrLoad15 = { OptPtrLoad15, "OptPtrLoad15", 86, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad16 = { OptPtrLoad16, "OptPtrLoad16", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad17 = { OptPtrLoad17, "OptPtrLoad17", 190, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 40, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore3 = { OptPtrStore3, "OptPtrStore3", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore4 = { OptPtrStore4, "OptPtrStore4", 65, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrStore5 = { OptPtrStore5, "OptPtrStore5", 65, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrStore6 = { OptPtrStore6, "OptPtrStore6", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrStore5 = { OptPtrStore5, "OptPtrStore5", 100, 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 }; @@ -1300,7 +1299,6 @@ static OptFunc* OptFuncs[] = { &DOptPtrStore3, &DOptPtrStore4, &DOptPtrStore5, - &DOptPtrStore6, &DOptPush1, &DOptPush2, &DOptPushPop, @@ -1576,7 +1574,6 @@ static unsigned RunOptGroup1 (CodeSeg* S) Changes += RunOptFunc (S, &DOptPtrStore3, 1); Changes += RunOptFunc (S, &DOptPtrStore4, 1); Changes += RunOptFunc (S, &DOptPtrStore5, 1); - Changes += RunOptFunc (S, &DOptPtrStore6, 1); Changes += RunOptFunc (S, &DOptAdd3, 1); /* Before OptPtrLoad5! */ Changes += RunOptFunc (S, &DOptPtrLoad1, 1); Changes += RunOptFunc (S, &DOptPtrLoad2, 1); diff --git a/src/cc65/coptptrstore.c b/src/cc65/coptptrstore.c index 63cfd22d5..aa28200ee 100644 --- a/src/cc65/coptptrstore.c +++ b/src/cc65/coptptrstore.c @@ -36,7 +36,9 @@ #include /* common */ +#include "strbuf.h" #include "xmalloc.h" +#include "xsprintf.h" /* cc65 */ #include "codeent.h" @@ -89,7 +91,7 @@ static unsigned OptPtrStore1Sub (CodeSeg* S, unsigned I, CodeEntry** const L) -static const char* ZPLoadAX (CodeSeg* S, unsigned I) +static const char* LoadAXZP (CodeSeg* S, unsigned I) /* If the two instructions at S/I are a load of A/X from a two byte zero byte * location, return the name of the zero page location. Otherwise return NULL. */ @@ -121,8 +123,74 @@ static const char* ZPLoadAX (CodeSeg* S, unsigned I) +static const char* LoadAXImm (CodeSeg* S, unsigned I) +/* If the two instructions at S/I are a load of A/X of a constant value or a + * wqord sized address label, return the address of the location as a string. + * Beware: In case of a numeric value, the result is returned in static + * storage which is overwritten with each call. + */ +{ + static StrBuf Buf = STATIC_STRBUF_INITIALIZER; + CodeEntry* L[2]; + unsigned Len; + + if (CS_GetEntries (S, L, I, 2) && + ((L[0]->OPC == OP65_LDA && L[1]->OPC == OP65_LDX) || + (L[0]->OPC == OP65_LDX && L[1]->OPC == OP65_LDA)) && + L[0]->AM == AM65_IMM && + L[1]->AM == AM65_IMM && + !CE_HasLabel (L[1])) { + + /* Immediate load of A/X */ + if (CE_HasNumArg (L[0]) && CE_HasNumArg (L[1])) { + + /* Numeric argument - get low and high byte */ + unsigned Hi, Lo; + if (L[0]->OPC == OP65_LDA) { + Lo = (L[0]->Num & 0xFF); + Hi = (L[1]->Num & 0xFF); + } else { + Lo = (L[1]->Num & 0xFF); + Hi = (L[0]->Num & 0xFF); + } + + /* Format into buffer */ + SB_Printf (&Buf, "$%04X", Lo | (Hi << 8)); + + /* Return the address as a string */ + return SB_GetConstBuf (&Buf); + + } else if ((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) { + + /* Load of an address label */ + SB_CopyBuf (&Buf, L[0]->Arg + 2, Len - 3); + SB_Terminate (&Buf); + return SB_GetConstBuf (&Buf); + + } else { + + /* Not found */ + return 0; + + } + + } else { + + /* Not found */ + return 0; + + } +} + + + /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -130,8 +198,6 @@ static const char* ZPLoadAX (CodeSeg* S, unsigned I) unsigned OptPtrStore1 (CodeSeg* S) /* Search for the sequence: * - * lda #<(label+0) - * ldx #>(label+0) * clc * adc xxx * bcc L @@ -144,10 +210,35 @@ unsigned OptPtrStore1 (CodeSeg* S) * * and replace it by: * + * sta ptr1 + * stx ptr1+1 * ldy xxx - * ldx #$00 - * lda yyy - * sta label,y + * ldx #$00 + * lda yyy + * sta (ptr1),y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta label,y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta $xxxx,y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta (zp),y + * + * depending on the two instructions preceeding the sequence above. */ { unsigned Changes = 0; @@ -156,64 +247,95 @@ unsigned OptPtrStore1 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[11]; - unsigned Len; + CodeEntry* L[9]; /* 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, 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_IsKnownImm (L[9], 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) { + 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_BCC || L[2]->OPC == OP65_JCC) && + L[2]->JumpTo != 0 && + L[2]->JumpTo->Owner == L[4] && + L[3]->OPC == OP65_INX && + CE_IsCallTo (L[4], "pushax") && + L[5]->OPC == OP65_LDX && + L[6]->OPC == OP65_LDA && + L[7]->OPC == OP65_LDY && + CE_IsKnownImm (L[7], 0) && + CE_IsCallTo (L[8], "staspidx") && + !CS_RangeHasLabel (S, I+1, 3) && + !CS_RangeHasLabel (S, I+5, 4)) { CodeEntry* X; - char* Label; + const char* Loc; + am_t AM; - /* 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); + /* Track the insertion point */ + unsigned IP = I + 9; - X = NewCodeEntry (OP65_LDX, L[7]->AM, L[7]->Arg, 0, L[7]->LI); - CS_InsertEntry (S, X, I+12); + unsigned DeleteStart = I; + unsigned DeleteCount = 9; + if (I >= 2) { + if ((Loc = LoadAXZP (S, I-2)) != 0) { + /* If the sequence is preceeded by a load of a ZP value, + * we can use this ZP value as a pointer using ZP + * indirect Y addressing. + */ + AM = AM65_ZP_INDY; + DeleteStart -= 2; + DeleteCount += 2; + } else if ((Loc = LoadAXImm (S, I-2)) != 0) { + /* If the sequence is preceeded by a load of an immediate + * value, we can use this absolute value as an address + * using absolute indexed Y addressing. + */ + AM = AM65_ABSY; + DeleteStart -= 2; + DeleteCount += 2; + } + } - X = NewCodeEntry (OP65_LDA, L[8]->AM, L[8]->Arg, 0, L[8]->LI); - CS_InsertEntry (S, X, I+13); + /* If we don't have a zero page location, we use ptr1 with zp + * indirect Y addressing. We must store the value in A/X into + * ptr1 in this case. + */ + if (Loc == 0) { - 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); + /* Must use ptr1 */ + Loc = "ptr1"; + AM = AM65_ZP_INDY; + + X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[8]->LI); + CS_InsertEntry (S, X, IP++); + + X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[8]->LI); + CS_InsertEntry (S, X, IP++); + + } + + X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI); + CS_InsertEntry (S, X, IP++); + + X = NewCodeEntry (OP65_LDX, L[5]->AM, L[5]->Arg, 0, L[5]->LI); + CS_InsertEntry (S, X, IP++); + + X = NewCodeEntry (OP65_LDA, L[6]->AM, L[6]->Arg, 0, L[6]->LI); + CS_InsertEntry (S, X, IP++); + + X = NewCodeEntry (OP65_STA, AM, Loc, 0, L[8]->LI); + CS_InsertEntry (S, X, IP++); /* Remove the old code */ - CS_DelEntries (S, I, 11); + CS_DelEntries (S, DeleteStart, DeleteCount); + + /* Skip most of the generated replacement */ + I += 3; /* Remember, we had changes */ ++Changes; @@ -221,7 +343,7 @@ unsigned OptPtrStore1 (CodeSeg* S) } /* Next entry */ - ++I; + ++I; } @@ -471,116 +593,6 @@ unsigned OptPtrStore3 (CodeSeg* S) unsigned OptPtrStore4 (CodeSeg* S) -/* Search for the sequence: - * - * 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 - * ldy xxx - * ldx #$00 - * lda yyy - * sta (ptr1),y - * - * In case a/x is loaded from the register bank before the clc, we can even - * use the register bank instead of ptr1. - */ -{ - 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_BCC || L[2]->OPC == OP65_JCC) && - L[2]->JumpTo != 0 && - L[2]->JumpTo->Owner == L[4] && - L[3]->OPC == OP65_INX && - CE_IsCallTo (L[4], "pushax") && - L[5]->OPC == OP65_LDX && - L[6]->OPC == OP65_LDA && - L[7]->OPC == OP65_LDY && - CE_IsKnownImm (L[7], 0) && - CE_IsCallTo (L[8], "staspidx") && - !CS_RangeHasLabel (S, I+1, 3) && - !CS_RangeHasLabel (S, I+5, 4)) { - - CodeEntry* X; - const char* ZPLoc; - - /* Track the insertion point */ - unsigned IP = I + 9; - - /* If the sequence is preceeded by a load of a ZP value, we can - * use this ZP value as a pointer. - */ - if (I < 2 || (ZPLoc = ZPLoadAX (S, I-2)) == 0) { - - ZPLoc = "ptr1"; - - /* Must use ptr1 */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[8]->LI); - CS_InsertEntry (S, X, IP++); - - X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[8]->LI); - CS_InsertEntry (S, X, IP++); - - } - - X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI); - CS_InsertEntry (S, X, IP++); - - X = NewCodeEntry (OP65_LDX, L[5]->AM, L[5]->Arg, 0, L[5]->LI); - CS_InsertEntry (S, X, IP++); - - X = NewCodeEntry (OP65_LDA, L[6]->AM, L[6]->Arg, 0, L[6]->LI); - CS_InsertEntry (S, X, IP++); - - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLoc, 0, L[8]->LI); - CS_InsertEntry (S, X, IP++); - - /* Remove the old code */ - CS_DelEntries (S, I, 9); - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - -unsigned OptPtrStore5 (CodeSeg* S) /* Search for the sequence: * * clc @@ -647,23 +659,42 @@ unsigned OptPtrStore5 (CodeSeg* S) CodeEntry* X; const char* Arg; - const char* ZPLoc; + const char* Loc; + am_t AM; /* Track the insertion point */ unsigned IP = I + 10; - /* If the sequence is preceeded by a load of a ZP value, we can - * use this ZP value as a pointer. - */ - if (I < 2 || (ZPLoc = ZPLoadAX (S, I-2)) == 0) { + if (I >= 2) { + if ((Loc = LoadAXZP (S, I-2)) != 0) { + /* If the sequence is preceeded by a load of a ZP value, + * we can use this ZP value as a pointer using ZP + * indirect Y addressing. + */ + AM = AM65_ZP_INDY; + } else if ((Loc = LoadAXImm (S, I-2)) != 0) { + /* If the sequence is preceeded by a load of an immediate + * value, we can use this absolute value as an address + * using absolute indexed Y addressing. + */ + AM = AM65_ABSY; + } + } - ZPLoc = "ptr1"; + /* If we don't have a zero page location, we use ptr1 with zp + * indirect Y addressing. We must store the value in A/X into + * ptr1 in this case. + */ + if (Loc == 0) { /* Must use ptr1 */ - X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[9]->LI); + Loc = "ptr1"; + AM = AM65_ZP_INDY; + + X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[8]->LI); CS_InsertEntry (S, X, IP++); - X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[9]->LI); + X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[8]->LI); CS_InsertEntry (S, X, IP++); } @@ -681,7 +712,7 @@ unsigned OptPtrStore5 (CodeSeg* S) X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI); CS_InsertEntry (S, X, IP++); - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLoc, 0, L[9]->LI); + X = NewCodeEntry (OP65_STA, AM, Loc, 0, L[9]->LI); CS_InsertEntry (S, X, IP++); /* Remove the old code */ @@ -703,7 +734,7 @@ unsigned OptPtrStore5 (CodeSeg* S) -unsigned OptPtrStore6 (CodeSeg* S) +unsigned OptPtrStore5 (CodeSeg* S) /* Search for the sequence: * * jsr pushax diff --git a/src/cc65/coptptrstore.h b/src/cc65/coptptrstore.h index bb21a9966..63568c304 100644 --- a/src/cc65/coptptrstore.h +++ b/src/cc65/coptptrstore.h @@ -52,8 +52,6 @@ unsigned OptPtrStore1 (CodeSeg* S); /* Search for the sequence: * - * lda #<(label+0) - * ldx #>(label+0) * clc * adc xxx * bcc L @@ -66,11 +64,36 @@ unsigned OptPtrStore1 (CodeSeg* S); * * and replace it by: * + * sta ptr1 + * stx ptr1+1 * ldy xxx - * ldx #$00 - * lda yyy - * sta label,y - */ + * ldx #$00 + * lda yyy + * sta (ptr1),y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta label,y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta $xxxx,y + * + * or by + * + * ldy xxx + * ldx #$00 + * lda yyy + * sta (zp),y + * + * depending on the two instructions preceeding the sequence above. + */ unsigned OptPtrStore2 (CodeSeg* S); /* Search for the sequence: @@ -127,32 +150,6 @@ unsigned OptPtrStore3 (CodeSeg* S); */ unsigned OptPtrStore4 (CodeSeg* S); -/* Search for the sequence: - * - * ldy #offs1 - * clc - * adc (sp),y - * bcc L - * inx - * L: jsr pushax - * ldy #offs2 - * ldx #$00 - * lda (sp),y - * ldy #$00 - * jsr staspidx - * - * and replace it by: - * - * sta ptr1 - * stx ptr1+1 - * ldx #$00 - * ldy #offs2-2 - * lda (sp),y - * ldy #offs1 - * sta (ptr1),y - */ - -unsigned OptPtrStore5 (CodeSeg* S); /* Search for the sequence: * * clc @@ -179,8 +176,8 @@ unsigned OptPtrStore5 (CodeSeg* S); * In case a/x is loaded from the register bank before the clc, we can even * use the register bank instead of ptr1. */ - -unsigned OptPtrStore6 (CodeSeg* S); + +unsigned OptPtrStore5 (CodeSeg* S); /* Search for the sequence: * * jsr pushax -- 2.39.5