/* */
/* */
/* */
-/* (C) 2001-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
-/* D-70794 Filderstadt */
-/* 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 */
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
-};
-
/*****************************************************************************/
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
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 */
-unsigned OptCmp2 (CodeSeg* S)
+unsigned OptCmp3 (CodeSeg* S)
/* Search for
*
* lda/and/ora/eor ...
!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) {
+ CE_IsKnownImm (L[1], 0)) {
+
+ 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 */
-unsigned OptCmp3 (CodeSeg* S)
+unsigned OptCmp4 (CodeSeg* S)
/* Search for
*
* lda x
-unsigned OptCmp4 (CodeSeg* S)
+unsigned OptCmp5 (CodeSeg* S)
/* Optimize compares of local variables:
*
* ldy #o
/* 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_IsCallTo (L[1], "ldaxysp") &&
-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
-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.
*/
-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.
*/
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)) {
/* 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.
}
- /* 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;
+}
+
+