From: cuz Date: Sun, 21 Oct 2001 13:53:20 +0000 (+0000) Subject: Working on the optimizations X-Git-Tag: V2.12.0~2531 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=3c90e33414e5280501f5963150ffd8718fb77a7b;p=cc65 Working on the optimizations git-svn-id: svn://svn.cc65.org/cc65/trunk@1069 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 2b61e7a2a..9627f39cd 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -742,16 +742,8 @@ void g_getlocal (unsigned flags, int offs) AddCodeLine ("dey"); AddCodeLine ("ora (sp),y"); } else { - if (CodeSizeFactor > 180) { - ldyconst (offs + 1); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("tax"); - AddCodeLine ("dey"); - AddCodeLine ("lda (sp),y"); - } else { - ldyconst (offs+1); - AddCodeLine ("jsr ldaxysp"); - } + ldyconst (offs+1); + AddCodeLine ("jsr ldaxysp"); } break; diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 896baaf21..179d6c757 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -120,7 +120,7 @@ static const FuncInfo FuncInfoTable[] = { { "ldax0sp", REG_Y, REG_AX }, { "ldaxi", REG_AX, REG_AXY | REG_PTR1 }, { "ldaxidx", REG_AXY, REG_AXY | REG_PTR1 }, - { "ldaxysp", REG_Y, REG_AX }, + { "ldaxysp", REG_Y, REG_AXY }, { "leaasp", REG_A, REG_AX }, { "negax", REG_AX, REG_AX }, { "pusha", REG_A, REG_Y }, diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 4797e8b51..739644bd9 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -52,6 +52,7 @@ #include "coptcmp.h" #include "coptind.h" #include "coptneg.h" +#include "coptpush.h" #include "coptstop.h" #include "coptsub.h" #include "copttest.h" @@ -1352,8 +1353,8 @@ struct OptFunc { /* A list of all the function descriptions */ static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 60, 0, 0, 0, 0, 0 }; +static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBoolTrans = { OptBoolTrans, "OptBoolTrans", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBranchDist = { OptBranchDist, "OptBranchDist", 100, 0, 0, 0, 0, 0 }; @@ -1388,6 +1389,7 @@ static OptFunc DOptPtrLoad5 = { OptPtrLoad5, "OptPtrLoad5", 100, 0, static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 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 DOptPush1 = { OptPush1, "OptPush1", 65, 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 };*/ @@ -1438,6 +1440,7 @@ static OptFunc* OptFuncs[] = { &DOptPtrLoad6, &DOptPtrStore1, &DOptPtrStore2, + &DOptPush1, &DOptRTS, &DOptRTSJumps1, &DOptRTSJumps2, @@ -1584,7 +1587,7 @@ static void ReadOptStats (const char* Name) /* Parse the line */ if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) { - /* Syntax error */ + /* Syntax error */ continue; } @@ -1626,7 +1629,7 @@ static void WriteOptStats (const char* Name) "%-20s %6lu %6lu %6lu %6lu\n", O->Name, O->TotalRuns, - O->LastRuns, + O->LastRuns, O->TotalChanges, O->LastChanges); } @@ -1642,7 +1645,7 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max) { unsigned Changes, C; - /* Don't run the function if it is disabled or if it is prohibited by the + /* 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) { @@ -1671,131 +1674,174 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max) -static void RunOptGroup1 (CodeSeg* S) +static unsigned RunOptGroup1 (CodeSeg* S) /* Run the first group of optimization steps. These steps translate known * patterns emitted by the code generator into more optimal patterns. Order * of the steps is important, because some of the steps done earlier cover * the same patterns as later steps as subpatterns. */ { - RunOptFunc (S, &DOptPtrStore1, 1); - RunOptFunc (S, &DOptPtrStore2, 1); - RunOptFunc (S, &DOptPtrLoad1, 1); - RunOptFunc (S, &DOptPtrLoad2, 1); - RunOptFunc (S, &DOptPtrLoad3, 1); - RunOptFunc (S, &DOptPtrLoad4, 1); - RunOptFunc (S, &DOptPtrLoad5, 1); - RunOptFunc (S, &DOptNegAX1, 1); - RunOptFunc (S, &DOptNegAX2, 1); - RunOptFunc (S, &DOptNegAX3, 1); - RunOptFunc (S, &DOptNegAX4, 1); - RunOptFunc (S, &DOptAdd1, 1); - RunOptFunc (S, &DOptAdd2, 1); - RunOptFunc (S, &DOptShift1, 1); - RunOptFunc (S, &DOptShift2, 1); + unsigned Changes = 0; + + Changes += RunOptFunc (S, &DOptPtrStore1, 1); + Changes += RunOptFunc (S, &DOptPtrStore2, 1); + Changes += RunOptFunc (S, &DOptPtrLoad1, 1); + Changes += RunOptFunc (S, &DOptPtrLoad2, 1); + Changes += RunOptFunc (S, &DOptPtrLoad3, 1); + Changes += RunOptFunc (S, &DOptPtrLoad4, 1); + Changes += RunOptFunc (S, &DOptPtrLoad5, 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, &DOptShift1, 1); + Changes += RunOptFunc (S, &DOptShift2, 1); + + /* Return the number of changes */ + return Changes; } -static void RunOptGroup2 (CodeSeg* S) +static unsigned RunOptGroup2 (CodeSeg* S) /* Run one group of optimization steps. This step involves just decoupling * instructions by replacing them by instructions that do not depend on * previous instructions. This makes it easier to find instructions that * aren't used. */ { - RunOptFunc (S, &DOptDecouple, 1); -} + unsigned Changes = 0; + + Changes += RunOptFunc (S, &DOptDecouple, 1); + /* Return the number of changes */ + return Changes; +} -static void RunOptGroup3 (CodeSeg* S) +static unsigned RunOptGroup3 (CodeSeg* S) /* Run one group of optimization steps. These steps depend on each other, * that means that one step may allow another step to do additional work, * so we will repeat the steps as long as we see any changes. */ { - unsigned Changes; + unsigned Changes, C; + Changes = 0; do { - Changes = 0; - - Changes += RunOptFunc (S, &DOptPtrLoad6, 1); - Changes += RunOptFunc (S, &DOptNegA1, 1); - Changes += RunOptFunc (S, &DOptNegA2, 1); - Changes += RunOptFunc (S, &DOptSub1, 1); - Changes += RunOptFunc (S, &DOptSub2, 1); - Changes += RunOptFunc (S, &DOptAdd3, 1); - Changes += RunOptFunc (S, &DOptStackOps, 1); - Changes += RunOptFunc (S, &DOptJumpCascades, 1); - Changes += RunOptFunc (S, &DOptDeadJumps, 1); - Changes += RunOptFunc (S, &DOptRTS, 1); - Changes += RunOptFunc (S, &DOptDeadCode, 1); - Changes += RunOptFunc (S, &DOptJumpTarget, 1); - Changes += RunOptFunc (S, &DOptCondBranches, 1); - Changes += RunOptFunc (S, &DOptRTSJumps1, 1); - Changes += RunOptFunc (S, &DOptBoolTrans, 1); - Changes += RunOptFunc (S, &DOptCmp1, 1); - Changes += RunOptFunc (S, &DOptCmp2, 1); - Changes += RunOptFunc (S, &DOptCmp3, 1); - Changes += RunOptFunc (S, &DOptCmp4, 1); - Changes += RunOptFunc (S, &DOptCmp5, 1); - Changes += RunOptFunc (S, &DOptCmp6, 1); - Changes += RunOptFunc (S, &DOptCmp7, 1); - Changes += RunOptFunc (S, &DOptTest1, 1); - Changes += RunOptFunc (S, &DOptUnusedLoads, 1); - Changes += RunOptFunc (S, &DOptUnusedStores, 1); - Changes += RunOptFunc (S, &DOptDupLoads, 1); - Changes += RunOptFunc (S, &DOptStoreLoad, 1); - Changes += RunOptFunc (S, &DOptTransfers, 1); - - } while (Changes); + C = 0; + + C += RunOptFunc (S, &DOptPtrLoad6, 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, &DOptStackOps, 1); + C += RunOptFunc (S, &DOptJumpCascades, 1); + C += RunOptFunc (S, &DOptDeadJumps, 1); + C += RunOptFunc (S, &DOptRTS, 1); + C += RunOptFunc (S, &DOptDeadCode, 1); + C += RunOptFunc (S, &DOptJumpTarget, 1); + C += RunOptFunc (S, &DOptCondBranches, 1); + C += RunOptFunc (S, &DOptRTSJumps1, 1); + C += RunOptFunc (S, &DOptBoolTrans, 1); + C += RunOptFunc (S, &DOptCmp1, 1); + C += RunOptFunc (S, &DOptCmp2, 1); + C += RunOptFunc (S, &DOptCmp3, 1); + C += RunOptFunc (S, &DOptCmp4, 1); + C += RunOptFunc (S, &DOptCmp5, 1); + C += RunOptFunc (S, &DOptCmp6, 1); + C += RunOptFunc (S, &DOptCmp7, 1); + C += RunOptFunc (S, &DOptTest1, 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); + + Changes += C; + + } while (C); + + /* Return the number of changes */ + return Changes; } -static void RunOptGroup4 (CodeSeg* S) +static unsigned RunOptGroup4 (CodeSeg* S) /* 65C02 specific optimizations. */ { - if (CPU < CPU_65C02) { - return; - } + unsigned Changes = 0; - /* 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. - */ - if (RunOptFunc (S, &DOpt65C02Ind, 1) > 0) { - RunOptFunc (S, &DOptUnusedLoads, 1); + if (CPU >= CPU_65C02) { + /* 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. + */ + unsigned C = RunOptFunc (S, &DOpt65C02Ind, 1); + Changes += C; + if (C) { + Changes += RunOptFunc (S, &DOptUnusedLoads, 1); + } } + + /* Return the number of changes */ + return Changes; } -static void RunOptGroup5 (CodeSeg* S) +static unsigned RunOptGroup5 (CodeSeg* S) +/* Run another round of pattern replacements. These are done late, since there + * may be better replacements before. + */ +{ + unsigned Changes = 0; + + Changes += RunOptFunc (S, &DOptPush1, 1); + + /* Return the number of changes */ + return Changes; +} + + + +static unsigned RunOptGroup6 (CodeSeg* S) /* The last group of optimization steps. Adjust branches, do size optimizations. */ { + 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). */ - RunOptFunc (S, &DOptSize2, 1); + Changes += RunOptFunc (S, &DOptSize2, 1); /* Run the jump target optimization again, since the size optimization * above may have opened new oportunities. */ - RunOptFunc (S, &DOptJumpTarget, 5); + Changes += RunOptFunc (S, &DOptJumpTarget, 5); /* Adjust branch distances */ - RunOptFunc (S, &DOptBranchDist, 3); + Changes += RunOptFunc (S, &DOptBranchDist, 3); /* Replace conditional branches to RTS. If we had changes, we must run dead * code elimination again, since the change may have introduced dead code. */ - if (RunOptFunc (S, &DOptRTSJumps2, 1)) { - RunOptFunc (S, &DOptDeadCode, 1); + C = RunOptFunc (S, &DOptRTSJumps2, 1); + Changes += C; + if (C) { + Changes += RunOptFunc (S, &DOptDeadCode, 1); } + + /* Return the number of changes */ + return Changes; } @@ -1807,7 +1853,7 @@ void RunOpt (CodeSeg* S) /* If we shouldn't run the optimizer, bail out */ if (!Optimize) { - return; + return; } /* Check if we are requested to write optimizer statistics */ @@ -1829,6 +1875,7 @@ void RunOpt (CodeSeg* S) RunOptGroup3 (S); RunOptGroup4 (S); RunOptGroup5 (S); + RunOptGroup6 (S); /* Write statistics */ if (StatFileName) { diff --git a/src/cc65/coptadd.c b/src/cc65/coptadd.c index ebda0fb5d..7e9f92d6c 100644 --- a/src/cc65/coptadd.c +++ b/src/cc65/coptadd.c @@ -146,25 +146,22 @@ unsigned OptAdd1 (CodeSeg* S) unsigned OptAdd2 (CodeSeg* S) /* Search for the sequence * - * ldy #yy - * lda (sp),y - * tax - * ldy #xx - * lda (sp),y - * ldy #zz + * ldy #xx + * jsr ldaxysp + * ldy #yy * jsr addeqysp * * and replace it by: * - * ldy #xx + * ldy #xx-1 * lda (sp),y - * ldy #zz + * ldy #yy * clc * adc (sp),y * sta (sp),y - * ldy #yy + * ldy #xx * lda (sp),y - * ldy #zz+1 + * ldy #yy+1 * adc (sp),y * sta (sp),y * @@ -177,7 +174,7 @@ unsigned OptAdd2 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[7]; + CodeEntry* L[4]; /* Get next entry */ L[0] = CS_GetEntry (S, I); @@ -185,66 +182,66 @@ unsigned OptAdd2 (CodeSeg* S) /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CE_KnownImm (L[0]) && - CS_GetEntries (S, L+1, I+1, 6) && - L[1]->OPC == OP65_LDA && - L[1]->AM == AM65_ZP_INDY && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_TAX && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_LDY && - CE_KnownImm (L[3]) && - !CE_HasLabel (L[3]) && - L[4]->OPC == OP65_LDA && - L[4]->AM == AM65_ZP_INDY && - !CE_HasLabel (L[4]) && - L[5]->OPC == OP65_LDY && - CE_KnownImm (L[5]) && - !CE_HasLabel (L[5]) && - CE_IsCall (L[6], "addeqysp") && - !CE_HasLabel (L[6]) && - (GetRegInfo (S, I+7, REG_AX) & REG_AX) == 0) { + !CS_RangeHasLabel (S, I+1, 3) && + CS_GetEntries (S, L+1, I+1, 3) && + CE_IsCall (L[1], "ldaxysp") && + L[2]->OPC == OP65_LDY && + CE_KnownImm (L[2]) && + CE_IsCall (L[3], "addeqysp") && + (GetRegInfo (S, I+4, REG_AX) & REG_AX) == 0) { + /* Insert new code behind the addeqysp */ char Buf [20]; CodeEntry* X; + /* ldy #xx-1 */ + xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[0]->Num-1)); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); + CS_InsertEntry (S, X, I+4); + + /* lda (sp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+5); - /* Insert new code behind the addeqysp */ - X = NewCodeEntry (OP65_LDY, AM65_IMM, L[3]->Arg, 0, L[3]->LI); + /* ldy #yy */ + X = NewCodeEntry (OP65_LDY, AM65_IMM, L[2]->Arg, 0, L[2]->LI); + CS_InsertEntry (S, X, I+6); + + /* clc */ + X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); - X = NewCodeEntry (OP65_LDA, L[4]->AM, L[4]->Arg, 0, L[4]->LI); + /* adc (sp),y */ + X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+8); - X = NewCodeEntry (OP65_LDY, AM65_IMM, L[5]->Arg, 0, L[5]->LI); + /* sta (sp),y */ + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+9); - X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[6]->LI); + /* ldy #xx */ + X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+10); - X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[6]->LI); + /* lda (sp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+11); - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[6]->LI); + /* ldy #yy+1 */ + xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[2]->Num+1)); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[2]->LI); CS_InsertEntry (S, X, I+12); - X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); + /* adc (sp),y */ + X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+13); - X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); + /* sta (sp),y */ + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+14); - xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[5]->Num+1)); - X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[5]->LI); - CS_InsertEntry (S, X, I+15); - - X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[6]->LI); - CS_InsertEntry (S, X, I+16); - - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[6]->LI); - CS_InsertEntry (S, X, I+17); - /* Delete the old code */ - CS_DelEntries (S, I, 7); + CS_DelEntries (S, I, 4); /* Remember, we had changes */ ++Changes; diff --git a/src/cc65/coptcmp.c b/src/cc65/coptcmp.c index dd24c48c4..a88e7047d 100644 --- a/src/cc65/coptcmp.c +++ b/src/cc65/coptcmp.c @@ -283,63 +283,6 @@ static int GetCmpRegVal (const CodeEntry* E) -static int IsCmpToZero (const CodeEntry* E) -/* Check if the given instrcuction is a compare to zero instruction */ -{ - return (E->OPC == OP65_CMP && - E->AM == AM65_IMM && - (E->Flags & CEF_NUMARG) != 0 && - E->Num == 0); -} - - - -static int IsSpLoad (const CodeEntry* E) -/* Return true if this is the load of A from the stack */ -{ - return E->OPC == OP65_LDA && E->AM == AM65_ZP_INDY && strcmp (E->Arg, "sp") == 0; -} - - - -static int IsLocalLoad16 (CodeSeg* S, unsigned Index, - CodeEntry** L, unsigned Count) -/* Check if a 16 bit load of a local variable follows: - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * - * If so, read Count entries following the first ldy into L and return true - * if this is possible. Otherwise return false. - */ -{ - /* Be sure we read enough entries for the check */ - CHECK (Count >= 5); - - /* Read the first entry */ - L[0] = CS_GetEntry (S, Index); - - /* Check for the sequence */ - return (L[0]->OPC == OP65_LDY && - CE_KnownImm (L[0]) && - CS_GetEntries (S, L+1, Index+1, Count-1) && - IsSpLoad (L[1]) && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_TAX && - !CE_HasLabel (L[2]) && - L[3]->OPC == OP65_LDY && - CE_KnownImm (L[3]) && - L[3]->Num == L[0]->Num - 1 && - !CE_HasLabel (L[3]) && - IsSpLoad (L[4]) && - !CE_HasLabel (L[4])); -} - - - /*****************************************************************************/ /* Remove calls to the bool transformer subroutines */ /*****************************************************************************/ @@ -434,13 +377,12 @@ unsigned OptCmp1 (CodeSeg* S) /* Check for the sequence */ if (E->OPC == OP65_STX && + !CS_RangeHasLabel (S, I+1, 2) && CS_GetEntries (S, L, I+1, 2) && L[0]->OPC == OP65_STX && strcmp (L[0]->Arg, "tmp1") == 0 && - !CE_HasLabel (L[0]) && L[1]->OPC == OP65_ORA && - strcmp (L[1]->Arg, "tmp1") == 0 && - !CE_HasLabel (L[1])) { + strcmp (L[1]->Arg, "tmp1") == 0) { /* Remove the remaining instructions */ CS_DelEntries (S, I+1, 2); @@ -484,37 +426,93 @@ unsigned OptCmp2 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[2]; + CodeEntry* L[3]; /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); + L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if ((E->OPC == OP65_ADC || - E->OPC == OP65_AND || - E->OPC == OP65_DEA || - E->OPC == OP65_EOR || - E->OPC == OP65_INA || - E->OPC == OP65_LDA || - E->OPC == OP65_ORA || - E->OPC == OP65_PLA || - E->OPC == OP65_SBC || - E->OPC == OP65_TXA || - E->OPC == OP65_TYA) && - CS_GetEntries (S, L, I+1, 2) && - IsCmpToZero (L[0]) && - !CE_HasLabel (L[0]) && - ((L[1]->Info & OF_FBRA) != 0 || - (L[1]->OPC == OP65_JSR && - FindBoolCmpCond (L[1]->Arg) != CMP_INV)) && - !CE_HasLabel (L[1])) { - - /* Remove the compare */ - CS_DelEntry (S, I+1); + if ((L[0]->OPC == OP65_ADC || + L[0]->OPC == OP65_AND || + L[0]->OPC == OP65_DEA || + L[0]->OPC == OP65_EOR || + L[0]->OPC == OP65_INA || + L[0]->OPC == OP65_LDA || + L[0]->OPC == OP65_ORA || + L[0]->OPC == OP65_PLA || + L[0]->OPC == OP65_SBC || + L[0]->OPC == OP65_TXA || + L[0]->OPC == OP65_TYA) && + !CS_RangeHasLabel (S, I+1, 2) && + CS_GetEntries (S, L+1, I+1, 2) && + L[1]->OPC == OP65_CMP && + CE_KnownImm (L[1]) && + L[1]->Num == 0) { + + /* Check for the call to boolxx. We cannot remove the compare if + * the carry flag is evaluated later, because the load will not + * set the carry flag. + */ + if (L[2]->OPC == OP65_JSR) { + switch (FindBoolCmpCond (L[2]->Arg)) { + + case CMP_EQ: + case CMP_NE: + case CMP_GT: + case CMP_GE: + case CMP_LT: + case CMP_LE: + /* Remove the compare */ + CS_DelEntry (S, I+1); + ++Changes; + break; + + case CMP_UGT: + case CMP_UGE: + case CMP_ULT: + case CMP_ULE: + case CMP_INV: + /* Leave it alone */ + break; + } - /* Remember, we had changes */ - ++Changes; + } else { + /* Check for a branch on conditions that are set by the load. + * Beware: The insn may branch to another conditional branch + * that evaluates other flags, so check that. + */ + CodeEntry* E = L[2]; + int Delete = 0; + while (1) { + if ((E->Info & (OF_CBRA|OF_UBRA)) != 0) { + /* A conditional branch. Check if it jumps on a + * condition not set by the load. + */ + if ((E->Info & (OF_FBRA|OF_UBRA)) == 0) { + /* Invalid branch */ + break; + } else if (E->JumpTo == 0) { + /* Jump to external */ + Delete = 1; + break; + } else { + /* Check target of branch */ + E = E->JumpTo->Owner; + } + } else { + /* Some other insn */ + Delete = 1; + break; + } + } + + /* Delete the compare if we can */ + if (Delete) { + CS_DelEntry (S, I+1); + ++Changes; + } + } } /* Next entry */ @@ -562,7 +560,7 @@ unsigned OptCmp3 (CodeSeg* S) /* Check for the sequence */ if (E->OPC == OP65_LDA && - CS_GetEntries (S, L, I+1, 5) && + CS_GetEntries (S, L, I+1, 5) && L[0]->OPC == OP65_LDX && !CE_HasLabel (L[0]) && IsImmCmp16 (L+1) && @@ -610,10 +608,7 @@ unsigned OptCmp4 (CodeSeg* S) /* Optimize compares of local variables: * * ldy #o - * lda (sp),y - * tax - * dey - * lda (sp),y + * jsr ldaxysp * cpx #a * bne L1 * cmp #b @@ -626,42 +621,81 @@ unsigned OptCmp4 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[9]; + CodeEntry* L[6]; + + /* Get the next entry */ + L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) { + if (L[0]->OPC == OP65_LDY && + CE_KnownImm (L[0]) && + CS_GetEntries (S, L+1, I+1, 5) && + !CE_HasLabel (L[1]) && + CE_IsCall (L[1], "ldaxysp") && + IsImmCmp16 (L+2)) { - if ((L[8]->Info & OF_FBRA) != 0 && L[5]->Num == 0 && L[7]->Num == 0) { + if ((L[5]->Info & OF_FBRA) != 0 && L[2]->Num == 0 && L[4]->Num == 0) { - /* The value is zero, we may use the simple code version: - * ldy #o - * lda (sp),y + CodeEntry* X; + char Buf[20]; + + /* The value is zero, we may use the simple code version: * ldy #o-1 + * lda (sp),y + * ldy #o * ora (sp),y * jne/jeq ... */ - CE_ReplaceOPC (L[4], OP65_ORA); + sprintf (Buf, "$%02X", (int)(L[0]->Num-1)); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); + CS_InsertEntry (S, X, I+1); + + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+2); + + X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); + CS_InsertEntry (S, X, I+3); + + X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+4); + CS_DelEntries (S, I+5, 3); /* cpx/bne/cmp */ - CS_DelEntry (S, I+2); /* tax */ + CS_DelEntry (S, I); /* ldy */ } else { + CodeEntry* X; + char Buf[20]; + /* Change the code to just use the A register. Move the load * of the low byte after the first branch if possible: * - * ldy #o + * ldy #o-1 * lda (sp),y * cmp #a * bne L1 - * ldy #o-1 + * ldy #o * lda (sp),y * cmp #b * jne/jeq ... */ - CS_DelEntry (S, I+2); /* tax */ - CE_ReplaceOPC (L[5], OP65_CMP); /* cpx -> cmp */ - CS_MoveEntry (S, I+4, I+2); /* cmp */ - CS_MoveEntry (S, I+5, I+3); /* bne */ + sprintf (Buf, "$%02X", (int)(L[0]->Num-1)); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); + CS_InsertEntry (S, X, I+3); + + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+4); + + X = NewCodeEntry (OP65_CMP, L[2]->AM, L[2]->Arg, 0, L[2]->LI); + CS_InsertEntry (S, X, I+5); + + X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); + CS_InsertEntry (S, X, I+7); + + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+8); + + CS_DelEntries (S, I, 3); /* ldy/jsr/cpx */ } @@ -901,3 +935,4 @@ NextEntry: + diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 838f82cde..605c70317 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -726,10 +726,10 @@ unsigned OptUnusedStores (CodeSeg* S) if ((GetRegInfo (S, I+1, R) & R) == 0) { /* Register value is not used, remove the load */ - CS_DelEntry (S, I); + CS_DelEntry (S, I); - /* Remember, we had changes */ - ++Changes; + /* Remember, we had changes */ + ++Changes; } } @@ -861,7 +861,7 @@ unsigned OptDupLoads (CodeSeg* S) * that in the A register, replace the store by a STA. The * optimizer will then remove the load instruction for Y * later. If replacement by A is not possible try a - * replacement by X, but check for invalid addressing modes + * replacement by X, but check for invalid addressing modes * in this case. */ } else if (In->RegY >= 0) { @@ -1033,7 +1033,7 @@ unsigned OptTransfers (CodeSeg* S) goto NextEntry; } if ((X->Info & OF_FBRA) != 0) { - if (I == 0) { + if (I == 0) { /* No preceeding entry */ goto NextEntry; } diff --git a/src/cc65/coptneg.c b/src/cc65/coptneg.c index 6aed9ccc2..7ca08249e 100644 --- a/src/cc65/coptneg.c +++ b/src/cc65/coptneg.c @@ -185,12 +185,11 @@ unsigned OptNegAX1 (CodeSeg* S) CodeEntry* E = CS_GetEntry (S, I); /* Check if this is a call to bnegax, and if X is known and zero */ - if (E->RI->In.RegX == 0 && - CE_IsCall (E, "bnegax")) { + if (E->RI->In.RegX == 0 && CE_IsCall (E, "bnegax")) { - /* We're cheating somewhat here ... */ - E->Arg[5] = '\0'; - E->Use &= ~REG_X; + CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI); + CS_InsertEntry (S, X, I+1); + CS_DelEntry (S, I); /* We had changes */ ++Changes; @@ -213,18 +212,17 @@ unsigned OptNegAX1 (CodeSeg* S) unsigned OptNegAX2 (CodeSeg* S) /* Search for the sequence: * - * lda (xx),y - * tax - * dey - * lda (xx),y + * ldy #xx + * jsr ldaxysp * jsr bnegax * jne/jeq ... * * and replace it by * - * lda (xx),y + * ldy #xx + * lda (sp),y * dey - * ora (xx),y + * ora (sp),y * jeq/jne ... */ { @@ -234,37 +232,39 @@ unsigned OptNegAX2 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[5]; + CodeEntry* L[4]; /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); + L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (E->OPC == OP65_LDA && - E->AM == AM65_ZP_INDY && - CS_GetEntries (S, L, I+1, 5) && - L[0]->OPC == OP65_TAX && - L[1]->OPC == OP65_DEY && - L[2]->OPC == OP65_LDA && - L[2]->AM == AM65_ZP_INDY && - strcmp (L[2]->Arg, E->Arg) == 0 && - !CE_HasLabel (L[2]) && - CE_IsCall (L[3], "bnegax") && - !CE_HasLabel (L[3]) && - (L[4]->Info & OF_ZBRA) != 0 && - !CE_HasLabel (L[4])) { - - /* lda --> ora */ - CE_ReplaceOPC (L[2], OP65_ORA); + if (L[0]->OPC == OP65_LDY && + CE_KnownImm (L[0]) && + !CS_RangeHasLabel (S, I+1, 3) && + CS_GetEntries (S, L+1, I+1, 3) && + CE_IsCall (L[1], "ldaxysp") && + CE_IsCall (L[2], "bnegax") && + (L[3]->Info & OF_ZBRA) != 0) { + + CodeEntry* X; + + /* lda (sp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+1); + + /* dey */ + X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI); + CS_InsertEntry (S, X, I+2); + + /* ora (sp),y */ + X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+3); /* Invert the branch */ - CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC)); + CE_ReplaceOPC (L[3], GetInverseBranch (L[3]->OPC)); - /* Delete the entries no longer needed. Beware: Deleting entries - * will change the indices. - */ - CS_DelEntry (S, I+4); /* jsr bnegax */ - CS_DelEntry (S, I+1); /* tax */ + /* Delete the entries no longer needed. */ + CS_DelEntries (S, I+4, 2); /* Remember, we had changes */ ++Changes; diff --git a/src/cc65/coptpush.c b/src/cc65/coptpush.c new file mode 100644 index 000000000..187db0fd6 --- /dev/null +++ b/src/cc65/coptpush.c @@ -0,0 +1,119 @@ +/*****************************************************************************/ +/* */ +/* coptpush.c */ +/* */ +/* Optimize push sequences */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +/* common */ +#include "xsprintf.h" + +/* cc65 */ +#include "codeent.h" +#include "codeinfo.h" +#include "coptpush.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +unsigned OptPush1 (CodeSeg* S) +/* Given a sequence + * + * ldy #xx + * jsr ldaxysp + * jsr pushax + * + * If a/x are not used later, replace that by + * + * ldy #xx+2 + * jsr pushwysp + * + * saving 3 bytes and several cycles. + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[3]; + + /* Get next entry */ + L[0] = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (L[0]->OPC == OP65_LDY && + CE_KnownImm (L[0]) && + L[0]->Num < 0xFE && + !CS_RangeHasLabel (S, I+1, 2) && + CS_GetEntries (S, L+1, I+1, 2) && + CE_IsCall (L[1], "ldaxysp") && + CE_IsCall (L[2], "pushax") && + (GetRegInfo (S, I+3, REG_AX) & REG_AX) == 0) { + + /* Insert new code behind the pushax */ + char Buf [20]; + CodeEntry* X; + + /* ldy #xx+1 */ + xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[0]->Num+2)); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI); + CS_InsertEntry (S, X, I+3); + + /* jsr pushwysp */ + X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwysp", 0, L[2]->LI); + CS_InsertEntry (S, X, I+4); + + /* Delete the old code */ + CS_DelEntries (S, I, 3); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + diff --git a/src/cc65/coptpush.h b/src/cc65/coptpush.h new file mode 100644 index 000000000..399051376 --- /dev/null +++ b/src/cc65/coptpush.h @@ -0,0 +1,74 @@ +/*****************************************************************************/ +/* */ +/* coptpush.h */ +/* */ +/* Optimize push sequences */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* 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. */ +/* */ +/*****************************************************************************/ + + + +#ifndef COPTPUSH_H +#define COPTPUSH_H + + + +/* cc65 */ +#include "codeseg.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +unsigned OptPush1 (CodeSeg* S); +/* Given a sequence + * + * ldy #xx + * jsr ldaxysp + * jsr pushax + * + * If a/x are not used later, replace that by + * + * ldy #xx+2 + * jsr pushwysp + * + * saving 3 bytes and several cycles. + */ + + + +/* End of coptpush.h */ + +#endif + + + diff --git a/src/cc65/coptsub.c b/src/cc65/coptsub.c index 1aeaabea3..cbd09caa0 100644 --- a/src/cc65/coptsub.c +++ b/src/cc65/coptsub.c @@ -129,20 +129,16 @@ unsigned OptSub2 (CodeSeg* S) /* Check for the sequence */ if (E->OPC == OP65_LDA && + !CS_RangeHasLabel (S, I+1, 5) && CS_GetEntries (S, L, I+1, 5) && L[0]->OPC == OP65_SEC && - !CE_HasLabel (L[0]) && L[1]->OPC == OP65_STA && strcmp (L[1]->Arg, "tmp1") == 0 && - !CE_HasLabel (L[1]) && L[2]->OPC == OP65_LDA && - !CE_HasLabel (L[2]) && L[3]->OPC == OP65_SBC && strcmp (L[3]->Arg, "tmp1") == 0 && - !CE_HasLabel (L[3]) && L[4]->OPC == OP65_STA && - strcmp (L[4]->Arg, L[2]->Arg) == 0 && - !CE_HasLabel (L[4])) { + strcmp (L[4]->Arg, L[2]->Arg) == 0) { /* Remove the store to tmp1 */ CS_DelEntry (S, I+2); diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 34ab9af3a..a22ae93e5 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -39,6 +39,7 @@ OBJS = anonname.o \ coptcmp.o \ coptind.o \ coptneg.o \ + coptpush.o \ coptstop.o \ coptsub.o \ copttest.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 2fcc6431b..5fb562d4c 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -84,6 +84,7 @@ OBJS = anonname.obj \ coptcmp.obj \ coptind.obj \ coptneg.obj \ + coptpush.obj \ coptstop.obj \ coptsub.obj \ copttest.obj \ @@ -162,6 +163,7 @@ FILE coptc02.obj FILE coptcmp.obj FILE coptind.obj FILE coptneg.obj +FILE coptpush.obj FILE coptstop.obj FILE coptsub.obj FILE copttest.obj