X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptcmp.c;h=b99c1a69a48c544d0829ad63f83351bca560ba52;hb=7aefd9b4e7b67908b7b3c38b6003c7f1a8d3ee2d;hp=c185ecc27ad9432bf3b5afb1b8374723ed661190;hpb=5f8c0269d6d6905250ae0eadc4b95268555bc054;p=cc65 diff --git a/src/cc65/coptcmp.c b/src/cc65/coptcmp.c index c185ecc27..b99c1a69a 100644 --- a/src/cc65/coptcmp.c +++ b/src/cc65/coptcmp.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@cc65.org */ +/* (C) 2001-2012, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -49,26 +49,6 @@ -/* Defines for the conditions in a compare */ -typedef enum { - CMP_INV = -1, - CMP_EQ, - CMP_NE, - CMP_GT, - CMP_GE, - CMP_LT, - CMP_LE, - CMP_UGT, - CMP_UGE, - CMP_ULT, - CMP_ULE -} cmp_t; - -/* Table with the compare suffixes */ -static const char CmpSuffixTab [][4] = { - "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule" -}; - /* Table used to invert a condition, indexed by condition */ static const unsigned char CmpInvertTab [] = { CMP_NE, CMP_EQ, @@ -76,11 +56,6 @@ static const unsigned char CmpInvertTab [] = { CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT }; -/* Table to show which compares are signed (use the N flag) */ -static const char CmpSignedTab [] = { - 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 -}; - /*****************************************************************************/ @@ -89,59 +64,6 @@ static const char CmpSignedTab [] = { -static cmp_t FindCmpCond (const char* Code, unsigned CodeLen) -/* Search for a compare condition by the given code using the given length */ -{ - unsigned I; - - /* Linear search */ - for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) { - if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) { - /* Found */ - return I; - } - } - - /* Not found */ - return CMP_INV; -} - - - -static cmp_t FindBoolCmpCond (const char* Name) -/* Map a condition suffix to a code. Return the code or CMP_INV on failure */ -{ - /* Check for the correct subroutine name */ - if (strncmp (Name, "bool", 4) == 0) { - /* Name is ok, search for the code in the table */ - return FindCmpCond (Name+4, strlen(Name)-4); - } else { - /* Not found */ - return CMP_INV; - } -} - - - -static cmp_t FindTosCmpCond (const char* Name) -/* Check if this is a call to one of the TOS compare functions (tosgtax). - * Return the condition code or CMP_INV on failure. - */ -{ - unsigned Len = strlen (Name); - - /* Check for the correct subroutine name */ - if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) { - /* Name is ok, search for the code in the table */ - return FindCmpCond (Name+3, Len-3-2); - } else { - /* Not found */ - return CMP_INV; - } -} - - - static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond) /* Helper function for the replacement of routines that return a boolean * followed by a conditional jump. Instead of the boolean value, the condition @@ -309,7 +231,7 @@ unsigned OptBoolTrans (CodeSeg* S) /* Check for a boolean transformer */ if (E->OPC == OP65_JSR && (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV && - (N = CS_GetNextEntry (S, I)) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && (N->Info & OF_ZBRA) != 0) { /* Make the boolean transformer unnecessary by changing the @@ -352,6 +274,63 @@ unsigned OptBoolTrans (CodeSeg* S) unsigned OptCmp1 (CodeSeg* S) +/* Search for the sequence + * + * ldx xx + * stx tmp1 + * ora tmp1 + * + * and replace it by + * + * ora xx + */ +{ + 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_LDX && + !CS_RangeHasLabel (S, I+1, 2) && + CS_GetEntries (S, L+1, I+1, 2) && + L[1]->OPC == OP65_STX && + strcmp (L[1]->Arg, "tmp1") == 0 && + L[2]->OPC == OP65_ORA && + strcmp (L[2]->Arg, "tmp1") == 0) { + + CodeEntry* X; + + /* Insert the ora instead */ + X = NewCodeEntry (OP65_ORA, L[0]->AM, L[0]->Arg, 0, L[0]->LI); + CS_InsertEntry (S, X, I); + + /* Remove all other instructions */ + CS_DelEntries (S, I+1, 3); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptCmp2 (CodeSeg* S) /* Search for the sequence * * stx xx @@ -376,12 +355,12 @@ unsigned OptCmp1 (CodeSeg* S) CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ - if (E->OPC == OP65_STX && + if (E->OPC == OP65_STX && !CS_RangeHasLabel (S, I+1, 2) && CS_GetEntries (S, L, I+1, 2) && - L[0]->OPC == OP65_STX && + L[0]->OPC == OP65_STX && strcmp (L[0]->Arg, "tmp1") == 0 && - L[1]->OPC == OP65_ORA && + L[1]->OPC == OP65_ORA && strcmp (L[1]->Arg, "tmp1") == 0) { /* Remove the remaining instructions */ @@ -406,7 +385,7 @@ unsigned OptCmp1 (CodeSeg* S) -unsigned OptCmp2 (CodeSeg* S) +unsigned OptCmp3 (CodeSeg* S) /* Search for * * lda/and/ora/eor ... @@ -434,85 +413,64 @@ unsigned OptCmp2 (CodeSeg* S) /* Check for the sequence */ if ((L[0]->OPC == OP65_ADC || L[0]->OPC == OP65_AND || + L[0]->OPC == OP65_ASL || L[0]->OPC == OP65_DEA || L[0]->OPC == OP65_EOR || L[0]->OPC == OP65_INA || L[0]->OPC == OP65_LDA || + L[0]->OPC == OP65_LSR || 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) && + CS_GetEntries (S, L+1, I+1, 2) && L[1]->OPC == OP65_CMP && - CE_KnownImm (L[1]) && - L[1]->Num == 0) { + CE_IsKnownImm (L[1], 0)) { - /* Check for the call to boolxx. We cannot remove the compare if + int Delete = 0; + + /* Check for the call to boolxx. We only 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: + 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 */ + Delete = 1; + break; + + case CMP_UGT: case CMP_UGE: - case CMP_ULT: - case CMP_ULE: - case CMP_INV: - /* Leave it alone */ - break; - } - - } 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; - } - } + case CMP_ULT: + case CMP_ULE: + case CMP_INV: + /* Leave it alone */ + break; + } + + } else if ((L[2]->Info & OF_FBRA) != 0) { + + /* The following insn branches on the condition of a load, so + * the compare instruction can be removed. + */ + Delete = 1; + + } + + /* Delete the compare if we can */ + if (Delete) { + CS_DelEntry (S, I+1); + ++Changes; + } } /* Next entry */ @@ -526,7 +484,7 @@ unsigned OptCmp2 (CodeSeg* S) -unsigned OptCmp3 (CodeSeg* S) +unsigned OptCmp4 (CodeSeg* S) /* Search for * * lda x @@ -604,7 +562,7 @@ unsigned OptCmp3 (CodeSeg* S) -unsigned OptCmp4 (CodeSeg* S) +unsigned OptCmp5 (CodeSeg* S) /* Optimize compares of local variables: * * ldy #o @@ -628,10 +586,10 @@ unsigned OptCmp4 (CodeSeg* S) /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && - CE_KnownImm (L[0]) && + CE_IsConstImm (L[0]) && CS_GetEntries (S, L+1, I+1, 5) && !CE_HasLabel (L[1]) && - CE_IsCall (L[1], "ldaxysp") && + CE_IsCallTo (L[1], "ldaxysp") && IsImmCmp16 (L+2)) { if ((L[5]->Info & OF_FBRA) != 0 && L[2]->Num == 0 && L[4]->Num == 0) { @@ -713,7 +671,7 @@ unsigned OptCmp4 (CodeSeg* S) -unsigned OptCmp5 (CodeSeg* S) +unsigned OptCmp6 (CodeSeg* S) /* Search for calls to compare subroutines followed by a conditional branch * and replace them by cheaper versions, since the branch means that the * boolean value returned by these routines is not needed (we may also check @@ -775,7 +733,7 @@ unsigned OptCmp5 (CodeSeg* S) -unsigned OptCmp6 (CodeSeg* S) +unsigned OptCmp7 (CodeSeg* S) /* Search for a sequence ldx/txa/branch and remove the txa if A is not * used later. */ @@ -819,7 +777,7 @@ unsigned OptCmp6 (CodeSeg* S) -unsigned OptCmp7 (CodeSeg* S) +unsigned OptCmp8 (CodeSeg* S) /* Check for register compares where the contents of the register and therefore * the result of the compare is known. */ @@ -827,9 +785,6 @@ unsigned OptCmp7 (CodeSeg* S) unsigned Changes = 0; unsigned I; - /* Generate register info for this step */ - CS_GenRegInfo (S); - /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { @@ -842,7 +797,7 @@ unsigned OptCmp7 (CodeSeg* S) /* Check for a compare against an immediate value */ if ((E->Info & OF_CMP) != 0 && (RegVal = GetCmpRegVal (E)) >= 0 && - CE_KnownImm (E)) { + CE_IsConstImm (E)) { /* We are able to evaluate the compare at compile time. Check if * one or more branches are ahead. @@ -926,13 +881,79 @@ NextEntry: } - /* Free register info */ - CS_FreeRegInfo (S); - /* Return the number of changes made */ return Changes; } +unsigned OptCmp9 (CodeSeg* S) +/* Search for the sequence + * + * sbc xx + * bvs/bvc L + * eor #$80 + * L: asl a + * bcc/bcs somewhere + * + * If A is not used later (which should be the case), we can branch on the N + * flag instead of the carry flag and remove the asl. + */ +{ + unsigned Changes = 0; + unsigned I; + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[5]; + + /* Get next entry */ + L[0] = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (L[0]->OPC == OP65_SBC && + CS_GetEntries (S, L+1, I+1, 4) && + (L[1]->OPC == OP65_BVC || + L[1]->OPC == OP65_BVS) && + L[1]->JumpTo != 0 && + L[1]->JumpTo->Owner == L[3] && + L[2]->OPC == OP65_EOR && + CE_IsKnownImm (L[2], 0x80) && + L[3]->OPC == OP65_ASL && + L[3]->AM == AM65_ACC && + (L[4]->OPC == OP65_BCC || + L[4]->OPC == OP65_BCS || + L[4]->OPC == OP65_JCC || + L[4]->OPC == OP65_JCS) && + !CE_HasLabel (L[4]) && + !RegAUsed (S, I+4)) { + + /* Replace the branch condition */ + switch (GetBranchCond (L[4]->OPC)) { + case BC_CC: CE_ReplaceOPC (L[4], OP65_JPL); break; + case BC_CS: CE_ReplaceOPC (L[4], OP65_JMI); break; + default: Internal ("Unknown branch condition in OptCmp9"); + } + + /* Delete the asl insn */ + CS_DelEntry (S, I+3); + + /* Next sequence is somewhat ahead (if any) */ + I += 3; + + /* Remember, we had changes */ + ++Changes; + } + + /* Next entry */ + ++I; + } + + /* Return the number of changes made */ + return Changes; +} + +