-static void ParseLongArg (StrBuf* T, unsigned Arg)
+static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused)))
/* Parse the %l format specifier */
{
ExprDesc Expr;
AddCodeLine ("dey");
AddCodeLine ("lda (sp),y");
} else {
- if (offs) {
- ldyconst (offs+1);
- AddCodeLine ("jsr ldaxysp");
- } else {
- AddCodeLine ("jsr ldax0sp");
- }
+ ldyconst (offs+1);
+ AddCodeLine ("jsr ldaxysp");
}
}
break;
case CF_LONG:
- if (offs) {
- ldyconst (offs+3);
- AddCodeLine ("jsr ldeaxysp");
- } else {
- AddCodeLine ("jsr ldeax0sp");
- }
+ ldyconst (offs+3);
+ AddCodeLine ("jsr ldeaxysp");
break;
default:
AddCodeLine ("iny");
AddCodeLine ("ora (ptr1),y");
} else {
- if (offs == 0) {
- AddCodeLine ("jsr ldaxi");
- } else {
- ldyconst (offs+1);
- AddCodeLine ("jsr ldaxidx");
- }
+ ldyconst (offs+1);
+ AddCodeLine ("jsr ldaxidx");
}
break;
case CF_LONG:
- if (offs == 0) {
- AddCodeLine ("jsr ldeaxi");
- } else {
- ldyconst (offs+3);
- AddCodeLine ("jsr ldeaxidx");
- }
+ ldyconst (offs+3);
+ AddCodeLine ("jsr ldeaxidx");
if (flags & CF_TEST) {
AddCodeLine ("jsr tsteax");
}
if (Flags & CF_CONST) {
g_getimmed (Flags, Val, 0);
}
- if (Offs) {
- ldyconst (Offs);
- AddCodeLine ("jsr steaxysp");
- } else {
- AddCodeLine ("jsr steax0sp");
- }
+ ldyconst (Offs);
+ AddCodeLine ("jsr steaxysp");
break;
default:
-/*****************************************************************************/
-/* Compares of ax with a variable with fixed address */
-/*****************************************************************************/
-
-
-
-void g_cmplocal (unsigned flags, int offs)
-/* Compare a local variable to ax */
-{
- Internal ("g_cmplocal not implemented");
-}
-
-
-
-void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
-/* Compare a static variable to ax */
-{
- Internal ("g_cmpstatic not implemented");
-}
-
-
-
/*****************************************************************************/
/* Special op= functions */
/*****************************************************************************/
if (flags & CF_CONST) {
g_getimmed (flags, val, 0);
}
- if (offs == 0) {
- AddCodeLine ("jsr laddeq0sp");
- } else {
- ldyconst (offs);
- AddCodeLine ("jsr laddeqysp");
- }
+ ldyconst (offs);
+ AddCodeLine ("jsr laddeqysp");
break;
default:
AddCodeLine ("ldy #<(%s)", lbuf);
AddCodeLine ("sty ptr1");
AddCodeLine ("ldy #>(%s+1)", lbuf);
- if (val == 1) {
- AddCodeLine ("jsr lsubeq1");
- } else {
- AddCodeLine ("lda #$%02X", (unsigned char)val);
- AddCodeLine ("jsr lsubeqa");
- }
+ AddCodeLine ("lda #$%02X", (unsigned char)val);
+ AddCodeLine ("jsr lsubeqa");
} else {
g_getstatic (flags, label, offs);
g_dec (flags, val);
if (flags & CF_CONST) {
g_getimmed (flags, val, 0);
}
- if (offs == 0) {
- AddCodeLine ("jsr subeq0sp");
- } else {
- ldyconst (offs);
- AddCodeLine ("jsr subeqysp");
- }
+ ldyconst (offs);
+ AddCodeLine ("jsr subeqysp");
break;
case CF_LONG:
if (flags & CF_CONST) {
g_getimmed (flags, val, 0);
}
- if (offs == 0) {
- AddCodeLine ("jsr lsubeq0sp");
- } else {
- ldyconst (offs);
- AddCodeLine ("jsr lsubeqysp");
- }
+ ldyconst (offs);
+ AddCodeLine ("jsr lsubeqysp");
break;
default:
-void g_addaddr_local (unsigned flags, int offs)
+void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
/* Add the address of a local variable to ax */
{
unsigned L = 0;
void g_push (unsigned flags, unsigned long val)
/* Push the primary register or a constant value onto the stack */
{
- unsigned char hi;
-
if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
/* We have a constant 8 or 16 bit value */
if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
/* Handle as 8 bit value */
- if (CodeSizeFactor >= 165 || val > 2) {
- ldaconst (val);
- AddCodeLine ("jsr pusha");
- } else {
- AddCodeLine ("jsr pushc%d", (int) val);
- }
+ ldaconst (val);
+ AddCodeLine ("jsr pusha");
} else {
/* Handle as 16 bit value */
- hi = (unsigned char) (val >> 8);
- if (val <= 7) {
- AddCodeLine ("jsr push%u", (unsigned) val);
- } else if (hi == 0 || hi == 0xFF) {
- /* Use special function */
- ldaconst (val);
- AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
- } else {
- /* Long way ... */
- g_getimmed (flags, val, 0);
- AddCodeLine ("jsr pushax");
- }
+ g_getimmed (flags, val, 0);
+ AddCodeLine ("jsr pushax");
}
} else {
-void g_truejump (unsigned flags, unsigned label)
+void g_truejump (unsigned flags attribute ((unused)), unsigned label)
/* Jump to label if zero flag clear */
{
AddCodeLine ("jne %s", LocalLabelName (label));
-void g_falsejump (unsigned flags, unsigned label)
+void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
/* Jump to label if zero flag set */
{
AddCodeLine ("jeq %s", LocalLabelName (label));
#include "coptadd.h"
#include "coptcmp.h"
#include "coptind.h"
+#include "coptneg.h"
#include "coptstop.h"
#include "coptsub.h"
#include "copttest.h"
-/*****************************************************************************/
-/* nega optimizations */
-/*****************************************************************************/
-
-
-
-static unsigned OptNegA1 (CodeSeg* S)
-/* Check for
- *
- * ldx #$00
- * lda ..
- * jsr bnega
- *
- * Remove the ldx if the lda does not use it.
- */
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* L[2];
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check for a ldx */
- if (E->OPC == OP65_LDX &&
- E->AM == AM65_IMM &&
- (E->Flags & CEF_NUMARG) != 0 &&
- E->Num == 0 &&
- CS_GetEntries (S, L, I+1, 2) &&
- L[0]->OPC == OP65_LDA &&
- (L[0]->Use & REG_X) == 0 &&
- !CE_HasLabel (L[0]) &&
- CE_IsCall (L[1], "bnega") &&
- !CE_HasLabel (L[1])) {
-
- /* Remove the ldx instruction */
- CS_DelEntry (S, I);
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-static unsigned OptNegA2 (CodeSeg* S)
-/* Check for
- *
- * lda ..
- * jsr bnega
- * jeq/jne ..
- *
- * Adjust the conditional branch and remove the call to the subroutine.
- */
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* L[2];
-
- /* Get next entry */
- CodeEntry* E = 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) &&
- CE_IsCall (L[0], "bnega") &&
- !CE_HasLabel (L[0]) &&
- (L[1]->Info & OF_ZBRA) != 0 &&
- !CE_HasLabel (L[1])) {
-
- /* Invert the branch */
- CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
-
- /* Delete the subroutine call */
- CS_DelEntry (S, I+1);
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-/*****************************************************************************/
-/* negax optimizations */
-/*****************************************************************************/
-
-
-
-static unsigned OptNegAX1 (CodeSeg* S)
-/* On a call to bnegax, if X is zero, the result depends only on the value in
- * A, so change the call to a call to bnega. This will get further optimized
- * later if possible.
- */
-{
- 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)) {
-
- /* Get next entry */
- 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")) {
-
- /* We're cheating somewhat here ... */
- E->Arg[5] = '\0';
- E->Use &= ~REG_X;
-
- /* We had changes */
- ++Changes;
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Free register info */
- CS_FreeRegInfo (S);
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-static unsigned OptNegAX2 (CodeSeg* S)
-/* Search for the sequence:
- *
- * lda (xx),y
- * tax
- * dey
- * lda (xx),y
- * jsr bnegax
- * jne/jeq ...
- *
- * and replace it by
- *
- * lda (xx),y
- * dey
- * ora (xx),y
- * jeq/jne ...
- */
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* L[5];
-
- /* Get next entry */
- CodeEntry* E = 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);
-
- /* Invert the branch */
- CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->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 */
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-static unsigned OptNegAX3 (CodeSeg* S)
-/* Search for the sequence:
- *
- * lda xx
- * ldx yy
- * jsr bnegax
- * jne/jeq ...
- *
- * and replace it by
- *
- * lda xx
- * ora xx+1
- * jeq/jne ...
- */
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* L[3];
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check for the sequence */
- if (E->OPC == OP65_LDA &&
- CS_GetEntries (S, L, I+1, 3) &&
- L[0]->OPC == OP65_LDX &&
- !CE_HasLabel (L[0]) &&
- CE_IsCall (L[1], "bnegax") &&
- !CE_HasLabel (L[1]) &&
- (L[2]->Info & OF_ZBRA) != 0 &&
- !CE_HasLabel (L[2])) {
-
- /* ldx --> ora */
- CE_ReplaceOPC (L[0], OP65_ORA);
-
- /* Invert the branch */
- CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
-
- /* Delete the subroutine call */
- CS_DelEntry (S, I+2);
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-static unsigned OptNegAX4 (CodeSeg* S)
-/* Search for the sequence:
- *
- * jsr xxx
- * jsr bnega(x)
- * jeq/jne ...
- *
- * and replace it by:
- *
- * jsr xxx
- * <boolean test>
- * jne/jeq ...
- */
-{
- unsigned Changes = 0;
-
- /* Walk over the entries */
- unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* L[2];
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check for the sequence */
- if (E->OPC == OP65_JSR &&
- CS_GetEntries (S, L, I+1, 2) &&
- L[0]->OPC == OP65_JSR &&
- strncmp (L[0]->Arg,"bnega",5) == 0 &&
- !CE_HasLabel (L[0]) &&
- (L[1]->Info & OF_ZBRA) != 0 &&
- !CE_HasLabel (L[1])) {
-
- CodeEntry* X;
-
- /* Check if we're calling bnega or bnegax */
- int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
-
- /* Insert apropriate test code */
- if (ByteSized) {
- /* Test bytes */
- X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
- CS_InsertEntry (S, X, I+2);
- } else {
- /* Test words */
- X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
- CS_InsertEntry (S, X, I+2);
- X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
- CS_InsertEntry (S, X, I+3);
- }
-
- /* Delete the subroutine call */
- CS_DelEntry (S, I+1);
-
- /* Invert the branch */
- CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
-
- /* Remember, we had changes */
- ++Changes;
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
/*****************************************************************************/
/* Optimize stores through pointers */
/*****************************************************************************/
-static unsigned OptSize (CodeSeg* S)
+static unsigned OptSize1 (CodeSeg* S)
+/* Do size optimization by calling special subroutines that preload registers.
+ * This routine does not work standalone, it needs a following register load
+ * removal pass.
+ */
+{
+#if 0
+ static const char* Func = {
+ "stax0sp", /* staxysp, y = 0 */
+ "addeq0sp",
+ "ldax0sp", /* ldaxysp, y = 1 */
+ "ldeax0sp", /* ldeaxysp, y = 3 */
+ "push0", /* pushax, a = 0, x = 0 */
+ "pusha0", /* pushax, x = 0 */
+ "pushaFF", /* pushax, x = ff */
+ "pusha0sp", /* pushaysp, y = 0 */
+ "tosadda0", /* tosaddax, x = 0 */
+ "tosanda0", /* tosandax, x = 0 */
+ "tosdiva0", /* tosdivax, x = 0 */
+ "toseqa0", /* toseqax, x = 0 */
+ "tosgea0", /* tosgeax, x = 0 */
+ "tosgta0", /* tosgtax, x = 0 */
+ "tosadd0ax", /* tosaddeax, sreg = 0 */
+ "laddeqa", /* laddeq, sreg = 0, x = 0 */
+ "laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */
+ "laddeq0sp", /* laddeqysp, y = 0 */
+ "tosand0ax", /* tosandeax, sreg = 0 */
+ "ldaxi", /* ldaxidx, y = 1 */
+ "ldeaxi", /* ldeaxidx, y = 3 */
+ "ldeax0sp", /* ldeaxysp, y = 3 */
+ "tosdiv0ax", /* tosdiveax, sreg = 0 */
+ "toslea0", /* tosleax, x = 0 */
+ "tosmod0ax", /* tosmodeax, sreg = 0 */
+ "tosmul0ax", /* tosmuleax, sreg = 0 */
+ "tosumul0ax", /* tosumuleax, sreg = 0 */
+ "tosor0ax", /* tosoreax, sreg = 0 */
+ "push0ax", /* pusheax, sreg = 0 */
+ "tosrsub0ax", /* tosrsubeax, sreg = 0 */
+ "tosshl0ax", /* tosshleax, sreg = 0 */
+ "tosasl0ax", /* tosasleax, sreg = 0 */
+ "tosshr0ax", /* tosshreax, sreg = 0 */
+ "tosasr0ax", /* tosasreax, sreg = 0 */
+ "tossub0ax", /* tossubeax, sreg = 0 */
+ "lsubeqa", /* lsubeq, sreg = 0, x = 0 */
+ "lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */
+ "lsubeq0sp", /* lsubeqysp, y = 0 */
+ "toslta0", /* tosltax, x = 0 */
+ "tosudiv0ax", /* tosudiveax, sreg = 0 */
+ "tosumod0ax", /* tosumodeax, sreg = 0 */
+ "tosxor0ax", /* tosxoreax, sreg = 0 */
+ "tosmoda0", /* tosmodax, x = 0 */
+ "tosmula0", /* tosmulax, x = 0 */
+ "tosumula0", /* tosumulax, x = 0 */
+ "tosnea0", /* tosneax, x = 0 */
+ "tosora0", /* tosorax, x = 0 */
+ "push1", /* pushax, x = 0, a = 1 */
+ "push2", /* pushax, x = 0, a = 2 */
+ "push3", /* pushax, x = 0, a = 3 */
+ "push4", /* pushax, x = 0, a = 4 */
+ "push5", /* pushax, x = 0, a = 5 */
+ "push6", /* pushax, x = 0, a = 6 */
+ "push7", /* pushax, x = 0, a = 7 */
+ "pushc0", /* pusha, a = 0 */
+ "pushc1", /* pusha, a = 1 */
+ "pushc2", /* pusha, a = 2 */
+ "tosrsuba0", /* tosrsubax, x = 0 */
+ "tosshla0", /* tosshlax, x = 0 */
+ "tosasla0", /* tosaslax, x = 0 */
+ "tosshra0", /* tosshrax, x = 0 */
+ "tosasra0", /* tosasrax, x = 0 */
+ "steax0sp", /* steaxsp, y = 0 */
+ "tossuba0", /* tossubax, x = 0 */
+ "subeq0sp", /* subeqysp, y = 0 */
+ "tosudiva0", /* tosudivax, x = 0 */
+ "tosugea0", /* tosugeax, x = 0 */
+ "tosugta0", /* tosugtax, x = 0 */
+ "tosulea0", /* tosuleax, x = 0 */
+ "tosulta0", /* tosultax, x = 0 */
+ "tosumoda0", /* tosumodax, x = 0 */
+ "tosxora0", /* tosxorax, x = 0 */
+ };
+#endif
+
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Generate register info for the following step */
+ CS_GenRegInfo (S);
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptSize2 (CodeSeg* S)
/* Do size optimization by using shorter code sequences, even if this
* introduces relations between instructions. This step must be one of the
* last steps, because it makes further work much more difficult.
X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
}
}
- }
+ }
break;
case OP65_LDX:
static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 0, 0, 0, 0, 0 };
static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 0, 0, 0, 0, 0 };
static OptFunc DOptShift1 = { OptShift1, "OptShift1", 0, 0, 0, 0, 0 };
-static OptFunc DOptSize = { OptSize, "OptSize", 0, 0, 0, 0, 0 };
+static OptFunc DOptSize1 = { OptSize1, "OptSize1", 0, 0, 0, 0, 0 };
+static OptFunc DOptSize2 = { OptSize2, "OptSize2", 0, 0, 0, 0, 0 };
static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 0, 0, 0, 0, 0 };
static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0 };
static OptFunc DOptSub1 = { OptSub1, "OptSub1", 0, 0, 0, 0, 0 };
&DOptNegAX2,
&DOptNegAX3,
&DOptNegAX4,
- &DOptPtrStore1,
- &DOptPtrStore2,
&DOptPtrLoad1,
&DOptPtrLoad2,
&DOptPtrLoad3,
&DOptPtrLoad4,
&DOptPtrLoad5,
&DOptPtrLoad6,
+ &DOptPtrStore1,
+ &DOptPtrStore2,
&DOptRTS,
&DOptRTSJumps,
&DOptShift1,
- &DOptSize,
- &DOptSub1,
- &DOptSub2,
+ &DOptSize1,
+ &DOptSize2,
&DOptStackOps,
&DOptStoreLoad,
+ &DOptSub1,
+ &DOptSub2,
&DOptTest1,
&DOptTransfers,
&DOptUnusedLoads,
* if this does hinder further optimizations (no problem since we're
* done soon).
*/
- RunOptFunc (S, &DOptSize, 1);
+ RunOptFunc (S, &DOptSize2, 1);
/* Run the jump target optimization again, since the size optimization
* above may have opened new oportunities.
-static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
+static int IsImmCmp16 (CodeEntry** L)
/* Check if the instructions at L are an immidiate compare of a/x:
*
*
/*****************************************************************************/
/* Optimizations for compares */
/*****************************************************************************/
-
+
unsigned OptCmp1 (CodeSeg* S)
CS_GetEntries (S, L, I+1, 5) &&
L[0]->OPC == OP65_LDX &&
!CE_HasLabel (L[0]) &&
- IsImmCmp16 (S, L+1)) {
+ IsImmCmp16 (L+1)) {
if (L[1]->Num == 0 && L[3]->Num == 0) {
/* The value is zero, we may use the simple code version. */
CodeEntry* L[9];
/* Check for the sequence */
- if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
+ if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) {
if (L[5]->Num == 0 && L[7]->Num == 0) {
--- /dev/null
+/*****************************************************************************/
+/* */
+/* coptneg.c */
+/* */
+/* Optimize negation 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. */
+/* */
+/*****************************************************************************/
+
+
+
+/* cc65 */
+#include "codeent.h"
+#include "codeinfo.h"
+#include "coptneg.h"
+
+
+
+/*****************************************************************************/
+/* nega optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegA1 (CodeSeg* S)
+/* Check for
+ *
+ * ldx #$00
+ * lda ..
+ * jsr bnega
+ *
+ * Remove the ldx if the lda does not use it.
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check for a ldx */
+ if (E->OPC == OP65_LDX &&
+ E->AM == AM65_IMM &&
+ (E->Flags & CEF_NUMARG) != 0 &&
+ E->Num == 0 &&
+ CS_GetEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OP65_LDA &&
+ (L[0]->Use & REG_X) == 0 &&
+ !CE_HasLabel (L[0]) &&
+ CE_IsCall (L[1], "bnega") &&
+ !CE_HasLabel (L[1])) {
+
+ /* Remove the ldx instruction */
+ CS_DelEntry (S, I);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptNegA2 (CodeSeg* S)
+/* Check for
+ *
+ * lda ..
+ * jsr bnega
+ * jeq/jne ..
+ *
+ * Adjust the conditional branch and remove the call to the subroutine.
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = 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) &&
+ CE_IsCall (L[0], "bnega") &&
+ !CE_HasLabel (L[0]) &&
+ (L[1]->Info & OF_ZBRA) != 0 &&
+ !CE_HasLabel (L[1])) {
+
+ /* Invert the branch */
+ CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+
+ /* Delete the subroutine call */
+ CS_DelEntry (S, I+1);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* negax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegAX1 (CodeSeg* S)
+/* On a call to bnegax, if X is zero, the result depends only on the value in
+ * A, so change the call to a call to bnega. This will get further optimized
+ * later if possible.
+ */
+{
+ 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)) {
+
+ /* Get next entry */
+ 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")) {
+
+ /* We're cheating somewhat here ... */
+ E->Arg[5] = '\0';
+ E->Use &= ~REG_X;
+
+ /* We had changes */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptNegAX2 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * lda (xx),y
+ * tax
+ * dey
+ * lda (xx),y
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda (xx),y
+ * dey
+ * ora (xx),y
+ * jeq/jne ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[5];
+
+ /* Get next entry */
+ CodeEntry* E = 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);
+
+ /* Invert the branch */
+ CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->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 */
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptNegAX3 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * lda xx
+ * ldx yy
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda xx
+ * ora xx+1
+ * jeq/jne ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[3];
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OP65_LDA &&
+ CS_GetEntries (S, L, I+1, 3) &&
+ L[0]->OPC == OP65_LDX &&
+ !CE_HasLabel (L[0]) &&
+ CE_IsCall (L[1], "bnegax") &&
+ !CE_HasLabel (L[1]) &&
+ (L[2]->Info & OF_ZBRA) != 0 &&
+ !CE_HasLabel (L[2])) {
+
+ /* ldx --> ora */
+ CE_ReplaceOPC (L[0], OP65_ORA);
+
+ /* Invert the branch */
+ CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
+
+ /* Delete the subroutine call */
+ CS_DelEntry (S, I+2);
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptNegAX4 (CodeSeg* S)
+/* Search for the sequence:
+ *
+ * jsr xxx
+ * jsr bnega(x)
+ * jeq/jne ...
+ *
+ * and replace it by:
+ *
+ * jsr xxx
+ * <boolean test>
+ * jne/jeq ...
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[2];
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check for the sequence */
+ if (E->OPC == OP65_JSR &&
+ CS_GetEntries (S, L, I+1, 2) &&
+ L[0]->OPC == OP65_JSR &&
+ strncmp (L[0]->Arg,"bnega",5) == 0 &&
+ !CE_HasLabel (L[0]) &&
+ (L[1]->Info & OF_ZBRA) != 0 &&
+ !CE_HasLabel (L[1])) {
+
+ CodeEntry* X;
+
+ /* Check if we're calling bnega or bnegax */
+ int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
+
+ /* Insert apropriate test code */
+ if (ByteSized) {
+ /* Test bytes */
+ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
+ CS_InsertEntry (S, X, I+2);
+ } else {
+ /* Test words */
+ X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
+ CS_InsertEntry (S, X, I+2);
+ X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
+ CS_InsertEntry (S, X, I+3);
+ }
+
+ /* Delete the subroutine call */
+ CS_DelEntry (S, I+1);
+
+ /* Invert the branch */
+ CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
+
+ /* Remember, we had changes */
+ ++Changes;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* coptneg.h */
+/* */
+/* Optimize negation 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 COPTNEG_H
+#define COPTNEG_H
+
+
+
+/* cc65 */
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/* nega optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegA1 (CodeSeg* S);
+/* Check for
+ *
+ * ldx #$00
+ * lda ..
+ * jsr bnega
+ *
+ * Remove the ldx if the lda does not use it.
+ */
+
+unsigned OptNegA2 (CodeSeg* S);
+/* Check for
+ *
+ * lda ..
+ * jsr bnega
+ * jeq/jne ..
+ *
+ * Adjust the conditional branch and remove the call to the subroutine.
+ */
+
+
+
+/*****************************************************************************/
+/* negax optimizations */
+/*****************************************************************************/
+
+
+
+unsigned OptNegAX1 (CodeSeg* S);
+/* On a call to bnegax, if X is zero, the result depends only on the value in
+ * A, so change the call to a call to bnega. This will get further optimized
+ * later if possible.
+ */
+
+unsigned OptNegAX2 (CodeSeg* S);
+/* Search for the sequence:
+ *
+ * lda (xx),y
+ * tax
+ * dey
+ * lda (xx),y
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda (xx),y
+ * dey
+ * ora (xx),y
+ * jeq/jne ...
+ */
+
+unsigned OptNegAX3 (CodeSeg* S);
+/* Search for the sequence:
+ *
+ * lda xx
+ * ldx yy
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda xx
+ * ora xx+1
+ * jeq/jne ...
+ */
+
+unsigned OptNegAX4 (CodeSeg* S);
+/* Search for the sequence:
+ *
+ * jsr xxx
+ * jsr bnega(x)
+ * jeq/jne ...
+ *
+ * and replace it by:
+ *
+ * jsr xxx
+ * <boolean test>
+ * jne/jeq ...
+ */
+
+
+
+/* End of coptneg.h */
+
+#endif
+
+
+
{
Expr->Flags = E_MCONST;
Expr->Type = type_int;
- Expr->ConstVal = 1;
+ Expr->ConstVal = Value;
}
g_space (- (int) sizeofarg (CF_PTR));
pop (CF_PTR);
}
-
+
/* Skip T_PTR */
++lval->Type;
-static void OptAddSource (const char* Opt, const char* Arg)
+static void OptAddSource (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Add source lines as comments in generated assembler file */
{
AddSource = 1;
-static void OptAnsi (const char* Opt, const char* Arg)
+static void OptAnsi (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Compile in strict ANSI mode */
{
ANSI = 1;
-static void OptBssName (const char* Opt, const char* Arg)
+static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --bss-name option */
{
/* Check for a valid name */
-static void OptCheckStack (const char* Opt, const char* Arg)
+static void OptCheckStack (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Handle the --check-stack option */
{
CheckStack = 1;
-static void OptCodeName (const char* Opt, const char* Arg)
+static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --code-name option */
{
/* Check for a valid name */
-static void OptCreateDep (const char* Opt, const char* Arg)
+static void OptCreateDep (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Handle the --create-dep option */
{
CreateDep = 1;
} else if (strcmp (Arg, "65C02") == 0) {
CPU = CPU_65C02;
} else {
- AbEnd ("Invalid CPU: `%s'", Arg);
+ AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
}
}
-static void OptDataName (const char* Opt, const char* Arg)
+static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --data-name option */
{
/* Check for a valid name */
-static void OptDebug (const char* Opt, const char* Arg)
+static void OptDebug (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Compiler debug mode */
{
Debug = 1;
-static void OptDebugInfo (const char* Opt, const char* Arg)
+static void OptDebugInfo (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Add debug info to the object file */
{
DebugInfo = 1;
-static void OptDebugOpt (const char* Opt, const char* Arg)
+static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg)
/* Debug optimization steps */
{
char Buf [128];
-static void OptDisableOpt (const char* Opt, const char* Arg)
+static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg)
/* Disable an optimization step */
{
DisableOpt (Arg);
-static void OptEnableOpt (const char* Opt, const char* Arg)
+static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
/* Enable an optimization step */
{
EnableOpt (Arg);
-static void OptHelp (const char* Opt, const char* Arg)
+static void OptHelp (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Print usage information and exit */
{
Usage ();
-static void OptIncludeDir (const char* Opt, const char* Arg)
+static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
/* Add an include search path */
{
AddIncludePath (Arg, INC_SYS | INC_USER);
-static void OptListOptSteps (const char* Opt, const char* Arg)
+static void OptListOptSteps (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* List all optimizer steps */
{
/* List the optimizer steps */
-static void OptRodataName (const char* Opt, const char* Arg)
+static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --rodata-name option */
{
/* Check for a valid name */
-static void OptSignedChars (const char* Opt, const char* Arg)
+static void OptSignedChars (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Make default characters signed */
{
SignedChars = 1;
-static void OptStaticLocals (const char* Opt, const char* Arg)
+static void OptStaticLocals (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Place local variables in static storage */
{
StaticLocals = 1;
-static void OptTarget (const char* Opt, const char* Arg)
+static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
/* Set the target system */
{
SetSys (Arg);
-static void OptVerbose (const char* Opt, const char* Arg)
+static void OptVerbose (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Increase verbosity */
{
++Verbosity;
-static void OptVersion (const char* Opt, const char* Arg)
+static void OptVersion (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
/* Print the assembler version */
{
fprintf (stderr,
# Default for the compiler lib search path as compiler define
CDEFS=-DCC65_INC=\"/usr/lib/cc65/include/\"
-CFLAGS = -O2 -g -Wall -W -Wno-unused-parameter -I$(COMMON) $(CDEFS)
+CFLAGS = -O2 -g -Wall -W -I$(COMMON) $(CDEFS)
CC=gcc
EBIND=emxbind
LDFLAGS=
coptadd.o \
coptcmp.o \
coptind.o \
+ coptneg.o \
coptstop.o \
coptsub.o \
copttest.o \
coptadd.obj \
coptcmp.obj \
coptind.obj \
+ coptneg.obj \
coptstop.obj \
coptsub.obj \
copttest.obj \
FILE coptadd.obj
FILE coptcmp.obj
FILE coptind.obj
+FILE coptneg.obj
FILE coptstop.obj
FILE coptsub.obj
FILE copttest.obj
-static void StdFunc_strlen (ExprDesc* lval)
+static void StdFunc_strlen (ExprDesc* lval attribute ((unused)))
/* Handle the strlen function */
{
ExprDesc pval;