diff --git a/src/cc65.vcxproj b/src/cc65.vcxproj
index 556c616b0..6f3f8e4e4 100644
--- a/src/cc65.vcxproj
+++ b/src/cc65.vcxproj
@@ -64,12 +64,12 @@
+
-
@@ -79,6 +79,7 @@
+
@@ -144,12 +145,12 @@
+
-
@@ -159,6 +160,7 @@
+
diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c
index 208ada134..6c2a1fddd 100644
--- a/src/cc65/codeopt.c
+++ b/src/cc65/codeopt.c
@@ -52,12 +52,12 @@
#include "codeinfo.h"
#include "codeopt.h"
#include "coptadd.h"
+#include "coptbool.h"
#include "coptc02.h"
#include "coptcmp.h"
#include "coptind.h"
#include "coptjmp.h"
#include "coptmisc.h"
-#include "coptneg.h"
#include "coptptrload.h"
#include "coptptrstore.h"
#include "coptpush.h"
@@ -67,6 +67,7 @@
#include "coptstore.h"
#include "coptsub.h"
#include "copttest.h"
+#include "coptunary.h"
#include "error.h"
#include "global.h"
#include "output.h"
@@ -115,6 +116,7 @@ static OptFunc DOptBNegAX1 = { OptBNegAX1, "OptBNegAX1", 100, 0,
static OptFunc DOptBNegAX2 = { OptBNegAX2, "OptBNegAX2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBNegAX3 = { OptBNegAX3, "OptBNegAX3", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBNegAX4 = { OptBNegAX4, "OptBNegAX4", 100, 0, 0, 0, 0, 0 };
+static OptFunc DOptBoolCmp = { OptBoolCmp, "OptBoolCmp", 100, 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 DOptBranchDist2 = { OptBranchDist2, "OptBranchDist2", 0, 0, 0, 0, 0, 0 };
@@ -123,7 +125,6 @@ static OptFunc DOptCmp2 = { OptCmp2, "OptCmp2", 85, 0,
static OptFunc DOptCmp3 = { OptCmp3, "OptCmp3", 75, 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", 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 DOptCmp9 = { OptCmp9, "OptCmp9", 85, 0, 0, 0, 0, 0 };
@@ -221,6 +222,7 @@ static OptFunc* OptFuncs[] = {
&DOptBNegAX2,
&DOptBNegAX3,
&DOptBNegAX4,
+ &DOptBoolCmp,
&DOptBoolTrans,
&DOptBranchDist,
&DOptBranchDist2,
@@ -229,7 +231,6 @@ static OptFunc* OptFuncs[] = {
&DOptCmp3,
&DOptCmp4,
&DOptCmp5,
- &DOptCmp6,
&DOptCmp7,
&DOptCmp8,
&DOptCmp9,
@@ -684,6 +685,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
C += RunOptFunc (S, &DOptJumpCascades, 1);
C += RunOptFunc (S, &DOptDeadJumps, 1);
C += RunOptFunc (S, &DOptDeadCode, 1);
+ C += RunOptFunc (S, &DOptBoolCmp, 1);
C += RunOptFunc (S, &DOptBoolTrans, 1);
C += RunOptFunc (S, &DOptJumpTarget1, 1);
C += RunOptFunc (S, &DOptJumpTarget2, 1);
@@ -696,7 +698,6 @@ static unsigned RunOptGroup3 (CodeSeg* S)
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, &DOptCmp9, 1);
C += RunOptFunc (S, &DOptTest1, 1);
diff --git a/src/cc65/coptneg.c b/src/cc65/coptbool.c
similarity index 66%
rename from src/cc65/coptneg.c
rename to src/cc65/coptbool.c
index 27171c68d..ee88cac0d 100644
--- a/src/cc65/coptneg.c
+++ b/src/cc65/coptbool.c
@@ -1,8 +1,8 @@
/*****************************************************************************/
/* */
-/* coptneg.c */
+/* coptbool.c */
/* */
-/* Optimize negation sequences */
+/* Optimize boolean sequences */
/* */
/* */
/* */
@@ -36,7 +36,257 @@
/* cc65 */
#include "codeent.h"
#include "codeinfo.h"
-#include "coptneg.h"
+#include "error.h"
+#include "coptbool.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Table used to invert a condition, indexed by condition */
+static const unsigned char CmpInvertTab[] = {
+ CMP_NE, CMP_EQ,
+ CMP_LE, CMP_LT, CMP_GE, CMP_GT,
+ CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
+};
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static void ReplaceBranchCond (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
+** codes are evaluated directly.
+** I is the index of the conditional branch, the sequence is already checked
+** to be correct.
+*/
+{
+ CodeEntry* N;
+ CodeLabel* L;
+
+ /* Get the entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Replace the conditional branch */
+ switch (Cond) {
+
+ case CMP_EQ:
+ CE_ReplaceOPC (E, OP65_JEQ);
+ break;
+
+ case CMP_NE:
+ CE_ReplaceOPC (E, OP65_JNE);
+ break;
+
+ case CMP_GT:
+ /* Replace by
+ ** beq @L
+ ** jpl Target
+ ** @L: ...
+ */
+ if ((N = CS_GetNextEntry (S, I)) == 0) {
+ /* No such entry */
+ Internal ("Invalid program flow");
+ }
+ L = CS_GenLabel (S, N);
+ N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
+ CS_InsertEntry (S, N, I);
+ CE_ReplaceOPC (E, OP65_JPL);
+ break;
+
+ case CMP_GE:
+ CE_ReplaceOPC (E, OP65_JPL);
+ break;
+
+ case CMP_LT:
+ CE_ReplaceOPC (E, OP65_JMI);
+ break;
+
+ case CMP_LE:
+ /* Replace by
+ ** jmi Target
+ ** jeq Target
+ */
+ CE_ReplaceOPC (E, OP65_JMI);
+ L = E->JumpTo;
+ N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
+ CS_InsertEntry (S, N, I+1);
+ break;
+
+ case CMP_UGT:
+ /* Replace by
+ ** beq @L
+ ** jcs Target
+ ** @L: ...
+ */
+ if ((N = CS_GetNextEntry (S, I)) == 0) {
+ /* No such entry */
+ Internal ("Invalid program flow");
+ }
+ L = CS_GenLabel (S, N);
+ N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
+ CS_InsertEntry (S, N, I);
+ CE_ReplaceOPC (E, OP65_JCS);
+ break;
+
+ case CMP_UGE:
+ CE_ReplaceOPC (E, OP65_JCS);
+ break;
+
+ case CMP_ULT:
+ CE_ReplaceOPC (E, OP65_JCC);
+ break;
+
+ case CMP_ULE:
+ /* Replace by
+ ** jcc Target
+ ** jeq Target
+ */
+ CE_ReplaceOPC (E, OP65_JCC);
+ L = E->JumpTo;
+ N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
+ CS_InsertEntry (S, N, I+1);
+ break;
+
+ default:
+ Internal ("Unknown jump condition: %d", Cond);
+
+ }
+
+}
+
+
+
+/*****************************************************************************/
+/* Optimize bool comparison and transformer subroutines */
+/*****************************************************************************/
+
+
+
+unsigned OptBoolCmp (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
+** that explicitly, but for the current code generator it is always true).
+*/
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* N;
+ cmp_t Cond;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OP65_JSR &&
+ (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
+ (N = CS_GetNextEntry (S, I)) != 0 &&
+ (N->Info & OF_ZBRA) != 0 &&
+ !CE_HasLabel (N)) {
+
+ /* The tos... functions will return a boolean value in a/x and
+ ** the Z flag says if this value is zero or not. We will call
+ ** a cheaper subroutine instead, one that does not return a
+ ** boolean value but only valid flags. Note: jeq jumps if
+ ** the condition is not met, jne jumps if the condition is met.
+ ** Invert the code if we jump on condition not met.
+ */
+ if (GetBranchCond (N->OPC) == BC_EQ) {
+ /* Jumps if condition false, invert condition */
+ Cond = CmpInvertTab [Cond];
+ }
+
+ /* Replace the subroutine call. */
+ E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
+ CS_InsertEntry (S, E, I+1);
+ CS_DelEntry (S, I);
+
+ /* Replace the conditional branch */
+ ReplaceBranchCond (S, I+1, Cond);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptBoolTrans (CodeSeg* S)
+/* Try to remove the call to boolean transformer routines where the call is
+** not really needed and change following branch condition accordingly.
+*/
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* N;
+ cmp_t Cond;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check for a boolean transformer */
+ if (E->OPC == OP65_JSR &&
+ (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
+ (N = CS_GetNextEntry (S, I)) != 0 &&
+ (N->Info & OF_ZBRA) != 0) {
+
+ /* Make the boolean transformer unnecessary by changing the
+ ** the conditional jump to evaluate the condition flags that
+ ** are set after the compare directly. Note: jeq jumps if
+ ** the condition is not met, jne jumps if the condition is met.
+ ** Invert the code if we jump on condition not met.
+ */
+ if (GetBranchCond (N->OPC) == BC_EQ) {
+ /* Jumps if condition false, invert condition */
+ Cond = CmpInvertTab [Cond];
+ }
+
+ /* Check if we can replace the code by something better */
+ ReplaceBranchCond (S, I+1, Cond);
+
+ /* Remove the call to the bool transformer */
+ CS_DelEntry (S, I);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
@@ -408,200 +658,3 @@ unsigned OptBNegAX4 (CodeSeg* S)
/* Return the number of changes made */
return Changes;
}
-
-
-
-/*****************************************************************************/
-/* negax optimizations */
-/*****************************************************************************/
-
-
-
-unsigned OptNegAX1 (CodeSeg* S)
-/* Search for a call to negax and replace it by
-**
-** eor #$FF
-** clc
-** adc #$01
-**
-** if X isn't used later.
-*/
-{
- unsigned Changes = 0;
- unsigned I;
-
- /* Walk over the entries */
- I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check if this is a call to negax, and if X isn't used later */
- if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) {
-
- CodeEntry* X;
-
- /* Add replacement code behind */
- X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
- CS_InsertEntry (S, X, I+1);
-
- X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
- CS_InsertEntry (S, X, I+2);
-
- X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
- CS_InsertEntry (S, X, I+3);
-
- /* Delete the call to negax */
- CS_DelEntry (S, I);
-
- /* Skip the generated code */
- I += 2;
-
- /* We had changes */
- ++Changes;
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-unsigned OptNegAX2 (CodeSeg* S)
-/* Search for a call to negax and replace it by
-**
-** ldx #$FF
-** eor #$FF
-** clc
-** adc #$01
-** bcc L1
-** inx
-** L1:
-**
-** if X is known and zero on entry.
-*/
-{
- unsigned Changes = 0;
- unsigned I;
-
- /* Walk over the entries */
- I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* P;
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check if this is a call to negax, and if X is known and zero */
- if (E->RI->In.RegX == 0 &&
- CE_IsCallTo (E, "negax") &&
- (P = CS_GetNextEntry (S, I)) != 0) {
-
- CodeEntry* X;
- CodeLabel* L;
-
- /* Add replacement code behind */
-
- /* ldx #$FF */
- X = NewCodeEntry (OP65_LDX, AM65_IMM, "$FF", 0, E->LI);
- CS_InsertEntry (S, X, I+1);
-
- /* eor #$FF */
- X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
- CS_InsertEntry (S, X, I+2);
-
- /* clc */
- X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
- CS_InsertEntry (S, X, I+3);
-
- /* adc #$01 */
- X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
- CS_InsertEntry (S, X, I+4);
-
- /* Get the label attached to the insn following the call */
- L = CS_GenLabel (S, P);
-
- /* bcc L */
- X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, E->LI);
- CS_InsertEntry (S, X, I+5);
-
- /* inx */
- X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
- CS_InsertEntry (S, X, I+6);
-
- /* Delete the call to negax */
- CS_DelEntry (S, I);
-
- /* Skip the generated code */
- I += 5;
-
- /* We had changes */
- ++Changes;
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-/*****************************************************************************/
-/* complax optimizations */
-/*****************************************************************************/
-
-
-
-unsigned OptComplAX1 (CodeSeg* S)
-/* Search for a call to complax and replace it by
-**
-** eor #$FF
-**
-** if X isn't used later.
-*/
-{
- unsigned Changes = 0;
- unsigned I;
-
- /* Walk over the entries */
- I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check if this is a call to negax, and if X isn't used later */
- if (CE_IsCallTo (E, "complax") && !RegXUsed (S, I+1)) {
-
- CodeEntry* X;
-
- /* Add replacement code behind */
- X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
- CS_InsertEntry (S, X, I+1);
-
- /* Delete the call to negax */
- CS_DelEntry (S, I);
-
- /* We had changes */
- ++Changes;
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
diff --git a/src/cc65/coptneg.h b/src/cc65/coptbool.h
similarity index 80%
rename from src/cc65/coptneg.h
rename to src/cc65/coptbool.h
index 844d8b886..195751a02 100644
--- a/src/cc65/coptneg.h
+++ b/src/cc65/coptbool.h
@@ -1,8 +1,8 @@
/*****************************************************************************/
/* */
-/* coptneg.h */
+/* coptbool.h */
/* */
-/* Optimize negation sequences */
+/* Optimize boolean sequences */
/* */
/* */
/* */
@@ -33,8 +33,8 @@
-#ifndef COPTNEG_H
-#define COPTNEG_H
+#ifndef COPTBOOL_H
+#define COPTBOOL_H
@@ -43,6 +43,26 @@
+/*****************************************************************************/
+/* Optimize bool comparison and transformer subroutines */
+/*****************************************************************************/
+
+
+
+unsigned OptBoolCmp (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
+** that explicitly, but for the current code generator it is always true).
+*/
+
+unsigned OptBoolTrans (CodeSeg* S);
+/* Try to remove the call to boolean transformer routines where the call is
+** not really needed and change following branch condition accordingly.
+*/
+
+
+
/*****************************************************************************/
/* bnega optimizations */
/*****************************************************************************/
@@ -132,54 +152,6 @@ unsigned OptBNegAX4 (CodeSeg* S);
-/*****************************************************************************/
-/* negax optimizations */
-/*****************************************************************************/
-
-
-
-unsigned OptNegAX1 (CodeSeg* S);
-/* Search for a call to negax and replace it by
-**
-** eor #$FF
-** clc
-** adc #$01
-**
-** if X isn't used later.
-*/
-
-unsigned OptNegAX2 (CodeSeg* S);
-/* Search for a call to negax and replace it by
-**
-** ldx #$FF
-** eor #$FF
-** clc
-** adc #$01
-** bcc L1
-** inx
-** L1:
-**
-** if X is known and zero on entry.
-*/
-
-
-
-/*****************************************************************************/
-/* complax optimizations */
-/*****************************************************************************/
-
-
-
-unsigned OptComplAX1 (CodeSeg* S);
-/* Search for a call to complax and replace it by
-**
-** eor #$FF
-**
-** if X isn't used later.
-*/
-
-
-
-/* End of coptneg.h */
+/* End of coptbool.h */
#endif
diff --git a/src/cc65/coptcmp.c b/src/cc65/coptcmp.c
index 92401a858..2970b363b 100644
--- a/src/cc65/coptcmp.c
+++ b/src/cc65/coptcmp.c
@@ -43,131 +43,12 @@
-/*****************************************************************************/
-/* Data */
-/*****************************************************************************/
-
-
-
-/* Table used to invert a condition, indexed by condition */
-static const unsigned char CmpInvertTab [] = {
- CMP_NE, CMP_EQ,
- CMP_LE, CMP_LT, CMP_GE, CMP_GT,
- CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
-};
-
-
-
/*****************************************************************************/
/* Helper functions */
/*****************************************************************************/
-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
-** codes are evaluated directly.
-** I is the index of the conditional branch, the sequence is already checked
-** to be correct.
-*/
-{
- CodeEntry* N;
- CodeLabel* L;
-
- /* Get the entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Replace the conditional branch */
- switch (Cond) {
-
- case CMP_EQ:
- CE_ReplaceOPC (E, OP65_JEQ);
- break;
-
- case CMP_NE:
- CE_ReplaceOPC (E, OP65_JNE);
- break;
-
- case CMP_GT:
- /* Replace by
- ** beq @L
- ** jpl Target
- ** @L: ...
- */
- if ((N = CS_GetNextEntry (S, I)) == 0) {
- /* No such entry */
- Internal ("Invalid program flow");
- }
- L = CS_GenLabel (S, N);
- N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
- CS_InsertEntry (S, N, I);
- CE_ReplaceOPC (E, OP65_JPL);
- break;
-
- case CMP_GE:
- CE_ReplaceOPC (E, OP65_JPL);
- break;
-
- case CMP_LT:
- CE_ReplaceOPC (E, OP65_JMI);
- break;
-
- case CMP_LE:
- /* Replace by
- ** jmi Target
- ** jeq Target
- */
- CE_ReplaceOPC (E, OP65_JMI);
- L = E->JumpTo;
- N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
- CS_InsertEntry (S, N, I+1);
- break;
-
- case CMP_UGT:
- /* Replace by
- ** beq @L
- ** jcs Target
- ** @L: ...
- */
- if ((N = CS_GetNextEntry (S, I)) == 0) {
- /* No such entry */
- Internal ("Invalid program flow");
- }
- L = CS_GenLabel (S, N);
- N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
- CS_InsertEntry (S, N, I);
- CE_ReplaceOPC (E, OP65_JCS);
- break;
-
- case CMP_UGE:
- CE_ReplaceOPC (E, OP65_JCS);
- break;
-
- case CMP_ULT:
- CE_ReplaceOPC (E, OP65_JCC);
- break;
-
- case CMP_ULE:
- /* Replace by
- ** jcc Target
- ** jeq Target
- */
- CE_ReplaceOPC (E, OP65_JCC);
- L = E->JumpTo;
- N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
- CS_InsertEntry (S, N, I+1);
- break;
-
- default:
- Internal ("Unknown jump condition: %d", Cond);
-
- }
-
-}
-
-
-
static int IsImmCmp16 (CodeEntry** L)
/* Check if the instructions at L are an immediate compare of a/x:
**
@@ -205,68 +86,6 @@ static int GetCmpRegVal (const CodeEntry* E)
-/*****************************************************************************/
-/* Remove calls to the bool transformer subroutines */
-/*****************************************************************************/
-
-
-
-unsigned OptBoolTrans (CodeSeg* S)
-/* Try to remove the call to boolean transformer routines where the call is
-** not really needed.
-*/
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* N;
- cmp_t Cond;
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check for a boolean transformer */
- if (E->OPC == OP65_JSR &&
- (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
- (N = CS_GetNextEntry (S, I)) != 0 &&
- (N->Info & OF_ZBRA) != 0) {
-
- /* Make the boolean transformer unnecessary by changing the
- ** the conditional jump to evaluate the condition flags that
- ** are set after the compare directly. Note: jeq jumps if
- ** the condition is not met, jne jumps if the condition is met.
- ** Invert the code if we jump on condition not met.
- */
- if (GetBranchCond (N->OPC) == BC_EQ) {
- /* Jumps if condition false, invert condition */
- Cond = CmpInvertTab [Cond];
- }
-
- /* Check if we can replace the code by something better */
- ReplaceCmp (S, I+1, Cond);
-
- /* Remove the call to the bool transformer */
- CS_DelEntry (S, I);
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
/*****************************************************************************/
/* Optimizations for compares */
/*****************************************************************************/
@@ -684,68 +503,6 @@ 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
-** that explicitly, but for the current code generator it is always true).
-*/
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* N;
- cmp_t Cond;
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check for the sequence */
- if (E->OPC == OP65_JSR &&
- (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
- (N = CS_GetNextEntry (S, I)) != 0 &&
- (N->Info & OF_ZBRA) != 0 &&
- !CE_HasLabel (N)) {
-
- /* The tos... functions will return a boolean value in a/x and
- ** the Z flag says if this value is zero or not. We will call
- ** a cheaper subroutine instead, one that does not return a
- ** boolean value but only valid flags. Note: jeq jumps if
- ** the condition is not met, jne jumps if the condition is met.
- ** Invert the code if we jump on condition not met.
- */
- if (GetBranchCond (N->OPC) == BC_EQ) {
- /* Jumps if condition false, invert condition */
- Cond = CmpInvertTab [Cond];
- }
-
- /* Replace the subroutine call. */
- E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
- CS_InsertEntry (S, E, I+1);
- CS_DelEntry (S, I);
-
- /* Replace the conditional branch */
- ReplaceCmp (S, I+1, Cond);
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
unsigned OptCmp7 (CodeSeg* S)
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
** used later.
diff --git a/src/cc65/coptcmp.h b/src/cc65/coptcmp.h
index 0cdcf2d3d..dd188f7fc 100644
--- a/src/cc65/coptcmp.h
+++ b/src/cc65/coptcmp.h
@@ -43,19 +43,6 @@
-/*****************************************************************************/
-/* Remove calls to the bool transformer subroutines */
-/*****************************************************************************/
-
-
-
-unsigned OptBoolTrans (CodeSeg* S);
-/* Try to remove the call to boolean transformer routines where the call is
-** not really needed.
-*/
-
-
-
/*****************************************************************************/
/* Optimizations for compares */
/*****************************************************************************/
@@ -136,13 +123,6 @@ unsigned OptCmp5 (CodeSeg* S);
** jne/jeq L2
*/
-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
-** that explicitly, but for the current code generator it is always true).
-*/
-
unsigned OptCmp7 (CodeSeg* S);
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
** used later.
diff --git a/src/cc65/coptunary.c b/src/cc65/coptunary.c
new file mode 100644
index 000000000..4d92f9d4a
--- /dev/null
+++ b/src/cc65/coptunary.c
@@ -0,0 +1,236 @@
+/*****************************************************************************/
+/* */
+/* coptunary.c */
+/* */
+/* Optimize bitwise unary sequences */
+/* */
+/* */
+/* */
+/* (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 */
+/* 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. */
+/* */
+/*****************************************************************************/
+
+
+
+/* cc65 */
+#include "codeent.h"
+#include "codeinfo.h"
+#include "coptbool.h"
+
+
+
+/*****************************************************************************/
+/* negax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegAX1 (CodeSeg* S)
+/* Search for a call to negax and replace it by
+**
+** eor #$FF
+** clc
+** adc #$01
+**
+** if X isn't used later.
+*/
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this is a call to negax, and if X isn't used later */
+ if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) {
+
+ CodeEntry* X;
+
+ /* Add replacement code behind */
+ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+ CS_InsertEntry (S, X, I+1);
+
+ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
+ CS_InsertEntry (S, X, I+2);
+
+ X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
+ CS_InsertEntry (S, X, I+3);
+
+ /* Delete the call to negax */
+ CS_DelEntry (S, I);
+
+ /* Skip the generated code */
+ I += 2;
+
+ /* We had changes */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptNegAX2 (CodeSeg* S)
+/* Search for a call to negax and replace it by
+**
+** ldx #$FF
+** eor #$FF
+** clc
+** adc #$01
+** bcc L1
+** inx
+** L1:
+**
+** if X is known and zero on entry.
+*/
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* P;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this is a call to negax, and if X is known and zero */
+ if (E->RI->In.RegX == 0 &&
+ CE_IsCallTo (E, "negax") &&
+ (P = CS_GetNextEntry (S, I)) != 0) {
+
+ CodeEntry* X;
+ CodeLabel* L;
+
+ /* Add replacement code behind */
+
+ /* ldx #$FF */
+ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$FF", 0, E->LI);
+ CS_InsertEntry (S, X, I+1);
+
+ /* eor #$FF */
+ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+ CS_InsertEntry (S, X, I+2);
+
+ /* clc */
+ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
+ CS_InsertEntry (S, X, I+3);
+
+ /* adc #$01 */
+ X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
+ CS_InsertEntry (S, X, I+4);
+
+ /* Get the label attached to the insn following the call */
+ L = CS_GenLabel (S, P);
+
+ /* bcc L */
+ X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, E->LI);
+ CS_InsertEntry (S, X, I+5);
+
+ /* inx */
+ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
+ CS_InsertEntry (S, X, I+6);
+
+ /* Delete the call to negax */
+ CS_DelEntry (S, I);
+
+ /* Skip the generated code */
+ I += 5;
+
+ /* We had changes */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* complax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptComplAX1 (CodeSeg* S)
+/* Search for a call to complax and replace it by
+**
+** eor #$FF
+**
+** if X isn't used later.
+*/
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this is a call to negax, and if X isn't used later */
+ if (CE_IsCallTo (E, "complax") && !RegXUsed (S, I+1)) {
+
+ CodeEntry* X;
+
+ /* Add replacement code behind */
+ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
+ CS_InsertEntry (S, X, I+1);
+
+ /* Delete the call to negax */
+ CS_DelEntry (S, I);
+
+ /* We had changes */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
diff --git a/src/cc65/coptunary.h b/src/cc65/coptunary.h
new file mode 100644
index 000000000..a7fd6d7b4
--- /dev/null
+++ b/src/cc65/coptunary.h
@@ -0,0 +1,96 @@
+/*****************************************************************************/
+/* */
+/* coptunary.h */
+/* */
+/* Optimize bitwise unary sequences */
+/* */
+/* */
+/* */
+/* (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 */
+/* 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 COPTUNARY_H
+#define COPTUNARY_H
+
+
+
+/* cc65 */
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/* negax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegAX1 (CodeSeg* S);
+/* Search for a call to negax and replace it by
+**
+** eor #$FF
+** clc
+** adc #$01
+**
+** if X isn't used later.
+*/
+
+unsigned OptNegAX2 (CodeSeg* S);
+/* Search for a call to negax and replace it by
+**
+** ldx #$FF
+** eor #$FF
+** clc
+** adc #$01
+** bcc L1
+** inx
+** L1:
+**
+** if X is known and zero on entry.
+*/
+
+
+
+/*****************************************************************************/
+/* complax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptComplAX1 (CodeSeg* S);
+/* Search for a call to complax and replace it by
+**
+** eor #$FF
+**
+** if X isn't used later.
+*/
+
+
+
+/* End of coptunary.h */
+
+#endif