diff --git a/src/cc65/asmcode.c b/src/cc65/asmcode.c index 227adbe2b..079111b87 100644 --- a/src/cc65/asmcode.c +++ b/src/cc65/asmcode.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 2000-2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -33,16 +33,11 @@ -/* common */ -#include "check.h" - /* b6502 */ #include "codeseg.h" #include "dataseg.h" /* cc65 */ -#include "codegen.h" -#include "global.h" #include "asmcode.h" diff --git a/src/cc65/asmcode.h b/src/cc65/asmcode.h index 1dee13815..a7845191d 100644 --- a/src/cc65/asmcode.h +++ b/src/cc65/asmcode.h @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 2000-2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ diff --git a/src/cc65/asmline.c b/src/cc65/asmline.c deleted file mode 100644 index 207d99b53..000000000 --- a/src/cc65/asmline.c +++ /dev/null @@ -1,180 +0,0 @@ -/*****************************************************************************/ -/* */ -/* asmline.h */ -/* */ -/* Internal assembler line structure */ -/* */ -/* */ -/* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ -/* */ -/* */ -/* 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. */ -/* */ -/*****************************************************************************/ - - - -#include -#include - -/* common */ -#include "xmalloc.h" -#include "xsprintf.h" - -/* cc65 */ -#include "error.h" -#include "asmline.h" - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Number used to index lines */ -static unsigned long LineIndex = 0; - -/* The line list */ -Line* FirstLine = 0; /* Pointer to first line */ -Line* LastLine = 0; /* Pointer to last line */ - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -static Line* NewLine (const char* Format, va_list ap) -/* Interal routine to create a new line from the given text */ -{ - char Buf [8192]; - unsigned Len; - Line* L; - - - /* Make a string from the given format and arguments */ - xvsprintf (Buf, sizeof (Buf), Format, ap); - - /* Get the length of the line */ - Len = strlen (Buf); - - /* Allocate memory */ - L = (Line*) xmalloc (sizeof (Line) + Len); - - /* Partially initialize the struct (the remaining fields are initialized - * by the caller). - */ - L->Flags = 0; - L->Size = 0; - L->Len = Len; - memcpy (L->Line, Buf, Len+1); - - /* Return the new line */ - return L; -} - - - -Line* NewCodeLine (const char* Format, va_list ap) -/* Create a new code line and return it */ -{ - /* Create a new line struct */ - Line* L = NewLine (Format, ap); - - /* Initialize struct fields */ - L->Index = LineIndex++; - - /* Insert the line into the list */ - if (FirstLine == 0) { - /* The list is empty */ - L->Next = L->Prev = 0; - FirstLine = LastLine = L; - } else { - /* There are entries in the list, add the new one at the end */ - LastLine->Next = L; - L->Prev = LastLine; - L->Next = 0; - LastLine = L; - } - - /* Return the new line */ - return L; -} - - - -Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap) -/* Create a new line, insert it after L and return it. */ -{ - /* Create a new line struct */ - Line* L = NewLine (Format, ap); - - /* Initialize struct fields. We use the same index for the inserted line - * as for its predecessor, since we cannot create new numbers on the - * fly and the index is only used to determine sort order. - */ - L->Index = LineBefore->Index; - - /* Insert the line after its predecessor */ - L->Next = LineBefore->Next; - LineBefore->Next = L; - L->Prev = LineBefore; - if (L->Next) { - L->Next->Prev = L; - } else { - /* This is the last line */ - LastLine = L; - } - - /* Return the new line */ - return L; -} - - - -void FreeCodeLine (Line* L) -/* Remove a line from the list and free it */ -{ - /* Unlink the line */ - if (L->Prev == 0) { - /* No line before this one */ - FirstLine = L->Next; - } else { - L->Prev->Next = L->Next; - } - if (L->Next == 0) { - /* No line after this one */ - LastLine = L->Prev; - } else { - L->Next->Prev = L->Prev; - } - - /* Free the struct */ - xfree (L); -} - - - diff --git a/src/cc65/asmline.h b/src/cc65/asmline.h deleted file mode 100644 index d47274b82..000000000 --- a/src/cc65/asmline.h +++ /dev/null @@ -1,93 +0,0 @@ -/*****************************************************************************/ -/* */ -/* asmline.h */ -/* */ -/* Internal assembler line structure */ -/* */ -/* */ -/* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ -/* */ -/* */ -/* 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 ASMLINE_H -#define ASMLINE_H - - - -#include - -/* common */ -#include "attrib.h" - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Structure that contains one line */ -typedef struct Line Line; -struct Line { - Line* Next; /* Next line on double linked list */ - Line* Prev; /* Revious line in list */ - unsigned Flags; /* Flags for this line */ - unsigned long Index; /* Index of this line */ - unsigned Size; /* Size of this code */ - unsigned Len; /* Length of the line */ - char Line [1]; /* The line itself */ -}; - -/* The line list */ -extern Line* FirstLine; /* Pointer to first line */ -extern Line* LastLine; /* Pointer to last line */ - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -Line* NewCodeLine (const char* Format, va_list ap) attribute((format(printf,1,0))); -/* Create a new code line and return it */ - -Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap) attribute((format(printf,2,0))); -/* Create a new line, insert it after L and return it. */ - -void FreeCodeLine (Line* L); -/* Remove a line from the list and free it */ - - - -/* End of asmline.h */ -#endif - - - diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index aafefa532..8252d6162 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -43,6 +43,10 @@ #include "xmalloc.h" #include "xsprintf.h" +/* b6502 */ +#include "codeseg.h" +#include "dataseg.h" + /* cc65 */ #include "asmcode.h" #include "asmlabel.h" @@ -64,10 +68,6 @@ /* Compiler relative stack pointer */ int oursp = 0; -/* Segments */ -DataSeg* DS = 0; -CodeSeg* CS = 0; - /* Current segment */ segment_t CurSeg = SEG_INV; @@ -79,22 +79,6 @@ segment_t CurSeg = SEG_INV; -static void AddCodeLine (const char* Format, ...) -{ - va_list ap; - char Buf [1024]; - va_start (ap, Format); - xvsprintf (Buf, sizeof (Buf), Format, ap); - va_end (ap); - if (CurSeg == SEG_CODE) { - AddCodeSegLine (CS, "%s", Buf); - } else { - AddDataSegLine (DS, "%s", Buf); - } -} - - - static void typeerror (unsigned type) /* Print an error message about an invalid operand type */ { @@ -108,7 +92,6 @@ static void CheckLocalOffs (unsigned Offs) { if (Offs >= 256) { /* Too many local vars */ - AddCodeLine (";*** Too many locals"); Error ("Too many local variables"); } } @@ -153,7 +136,7 @@ static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs) /*****************************************************************************/ -/* Pre- and postamble */ +/* Pre- and postamble */ /*****************************************************************************/ @@ -161,34 +144,37 @@ static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs) void g_preamble (void) /* Generate the assembler code preamble */ { - /* ### */ - CS = NewCodeSeg ("CODE"); - DS = NewDataSeg (); - - AddCodeLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH); + /* Generate the global segments and push them */ + PushCodeSeg (NewCodeSeg ("")); + PushDataSeg (NewDataSeg ("")); + + /* Identify the compiler version */ + AddDataSegLine (DS, "; File generated by cc65 v %u.%u.%u", + VER_MAJOR, VER_MINOR, VER_PATCH); /* Insert some object file options */ - AddCodeLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH); + AddDataSegLine (DS, ".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", + VER_MAJOR, VER_MINOR, VER_PATCH); /* If we're producing code for some other CPU, switch the command set */ if (CPU == CPU_65C02) { - AddCodeLine (".pc02"); + AddDataSegLine (DS, ".pc02"); } /* Allow auto import for runtime library routines */ - AddCodeLine (".autoimport\ton"); + AddDataSegLine (DS, ".autoimport\ton"); /* Switch the assembler into case sensitive mode */ - AddCodeLine (".case\t\ton"); + AddDataSegLine (DS, ".case\t\ton"); /* Tell the assembler if we want to generate debug info */ - AddCodeLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); + AddDataSegLine (DS, ".debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); /* Import the stack pointer for direct auto variable access */ - AddCodeLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1"); + AddDataSegLine (DS, ".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1"); /* Define long branch macros */ - AddCodeLine (".macpack\tlongbranch"); + AddDataSegLine (DS, ".macpack\tlongbranch"); } @@ -205,7 +191,7 @@ static void UseSeg (int NewSeg) if (CurSeg != NewSeg) { CurSeg = (segment_t) NewSeg; if (CurSeg != SEG_CODE) { - AddCodeLine (".segment\t\"%s\"", SegmentNames [CurSeg]); + AddDataSegLine (DS, ".segment\t\"%s\"", SegmentNames [CurSeg]); } } } @@ -557,7 +543,7 @@ void g_leave (int flags, int val) } /* Output the jump */ - AddCodeLine (buf); + AddCodeSegLine (CS, buf); } } @@ -3910,7 +3896,7 @@ void g_defbytes (const void* Bytes, unsigned Count) } while (Chunk); /* Output the line */ - AddCodeLine (Buf); + AddCodeSegLine (CS, Buf); } } @@ -3920,7 +3906,7 @@ void g_zerobytes (unsigned n) /* Output n bytes of data initialized with zero */ { AddDataSegLine (DS, "\t.res\t%u,$00", n); -} +} diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 2b0274fe0..88b8d9ac8 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -38,12 +38,6 @@ -/* ##### */ -#include "dataseg.h" -#include "codeseg.h" - - - /*****************************************************************************/ /* data */ /*****************************************************************************/ @@ -86,10 +80,6 @@ /* Compiler relative stackpointer */ extern int oursp; -/* Segments */ -extern DataSeg* DS; -extern CodeSeg* CS; - /*****************************************************************************/ diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 4ec6c07d9..532f35c9c 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -55,7 +55,18 @@ /*****************************************************************************/ -/* Code */ +/* Data */ +/*****************************************************************************/ + + + +/* Pointer to current code segment */ +CodeSeg* CS = 0; + + + +/*****************************************************************************/ +/* Functions for parsing instructions */ /*****************************************************************************/ @@ -292,6 +303,12 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L) +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + CodeSeg* NewCodeSeg (const char* Name) /* Create a new code segment, initialize and return it */ { @@ -301,6 +318,7 @@ CodeSeg* NewCodeSeg (const char* Name) CodeSeg* S = xmalloc (sizeof (CodeSeg)); /* Initialize the fields */ + S->Next = 0; S->Name = xstrdup (Name); InitCollection (&S->Entries); InitCollection (&S->Labels); @@ -348,6 +366,33 @@ void FreeCodeSeg (CodeSeg* S) +void PushCodeSeg (CodeSeg* S) +/* Push the given code segment onto the stack */ +{ + S->Next = CS; + CS = S; +} + + + +CodeSeg* PopCodeSeg (void) +/* Remove the current code segment from the stack and return it */ +{ + /* Remember the current code segment */ + CodeSeg* S = CS; + + /* Cannot pop on empty stack */ + PRECONDITION (S != 0); + + /* Pop */ + CS = S->Next; + + /* Return the popped code segment */ + return S; +} + + + void AddCodeSegLine (CodeSeg* S, const char* Format, ...) /* Add a line to the given code segment */ { diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index 0279165d3..b47fcda9b 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -61,12 +61,16 @@ /* Code segment structure */ typedef struct CodeSeg CodeSeg; struct CodeSeg { + CodeSeg* Next; /* Pointer to next CodeSeg */ char* Name; /* Segment name */ Collection Entries; /* List of code entries */ Collection Labels; /* Labels for next insn */ CodeLabel* LabelHash [CS_LABEL_HASH_SIZE]; /* Label hash table */ }; +/* Pointer to current code segment */ +extern CodeSeg* CS; + /*****************************************************************************/ @@ -81,6 +85,12 @@ CodeSeg* NewCodeSeg (const char* Name); void FreeCodeSeg (CodeSeg* S); /* Free a code segment including all code entries */ +void PushCodeSeg (CodeSeg* S); +/* Push the given code segment onto the stack */ + +CodeSeg* PopCodeSeg (void); +/* Remove the current code segment from the stack and return it */ + void AddCodeSegLine (CodeSeg* S, const char* Format, ...) attribute ((format(printf,2,3))); /* Add a line to the given code segment */ @@ -109,7 +119,7 @@ void MergeCodeLabels (CodeSeg* S); unsigned GetCodeSegEntries (const CodeSeg* S); /* Return the number of entries for the given code segment */ - + /* End of codeseg.h */ diff --git a/src/cc65/dataseg.c b/src/cc65/dataseg.c index 8940c6b8a..72f782853 100644 --- a/src/cc65/dataseg.c +++ b/src/cc65/dataseg.c @@ -34,6 +34,7 @@ /* common */ +#include "check.h" #include "xmalloc.h" #include "xsprintf.h" @@ -42,19 +43,32 @@ +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Pointer to current data segment */ +DataSeg* DS = 0; + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ -DataSeg* NewDataSeg (void) +DataSeg* NewDataSeg (const char* Name) /* Create a new data segment, initialize and return it */ { /* Allocate memory */ DataSeg* S = xmalloc (sizeof (DataSeg)); /* Initialize the fields */ + S->Next = 0; + S->Name = xstrdup (Name); InitCollection (&S->Lines); /* Return the new struct */ @@ -67,6 +81,9 @@ void FreeDataSeg (DataSeg* S) /* Free a data segment including all line entries */ { unsigned I, Count; + + /* Free the name */ + xfree (S->Name); /* Free the lines */ Count = CollCount (&S->Lines); @@ -83,6 +100,34 @@ void FreeDataSeg (DataSeg* S) +void PushDataSeg (DataSeg* S) +/* Push the given data segment onto the stack */ +{ + /* Push */ + S->Next = DS; + DS = S; +} + + + +DataSeg* PopDataSeg (void) +/* Remove the current data segment from the stack and return it */ +{ + /* Remember the current data segment */ + DataSeg* S = DS; + + /* Cannot pop on empty stack */ + PRECONDITION (S != 0); + + /* Pop */ + DS = S->Next; + + /* Return the popped data segment */ + return S; +} + + + void AppendDataSeg (DataSeg* Target, const DataSeg* Source) /* Append the data from Source to Target */ { diff --git a/src/cc65/dataseg.h b/src/cc65/dataseg.h index 328962f82..e03c37211 100644 --- a/src/cc65/dataseg.h +++ b/src/cc65/dataseg.h @@ -54,9 +54,14 @@ typedef struct DataSeg DataSeg; struct DataSeg { + DataSeg* Next; /* Pointer to next DataSeg */ + char* Name; /* Segment name */ Collection Lines; /* List of code lines */ }; +/* Pointer to current data segment */ +extern DataSeg* DS; + /*****************************************************************************/ @@ -65,12 +70,18 @@ struct DataSeg { -DataSeg* NewDataSeg (void); +DataSeg* NewDataSeg (const char* Name); /* Create a new data segment, initialize and return it */ void FreeDataSeg (DataSeg* S); /* Free a data segment including all line entries */ +void PushDataSeg (DataSeg* S); +/* Push the given data segment onto the stack */ + +DataSeg* PopDataSeg (void); +/* Remove the current data segment from the stack and return it */ + void AppendDataSeg (DataSeg* Target, const DataSeg* Source); /* Append the data from Source to Target. */ diff --git a/src/cc65/optimize.c b/src/cc65/optimize.c deleted file mode 100644 index 2c6a588e7..000000000 --- a/src/cc65/optimize.c +++ /dev/null @@ -1,4767 +0,0 @@ -/*****************************************************************************/ -/* */ -/* optimize.c */ -/* */ -/* An optimizer for the cc65 C compiler */ -/* */ -/* */ -/* */ -/* (C) 1998 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ -/* */ -/* */ -/* 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. */ -/* */ -/*****************************************************************************/ - - - -#include -#include -#include - -/* common */ -#include "attrib.h" -#include "chartype.h" -#include "check.h" -#include "print.h" -#include "xmalloc.h" -#include "xsprintf.h" - -/* cc65 */ -#include "asmlabel.h" -#include "asmline.h" -#include "cpu.h" -#include "error.h" -#include "global.h" -#include "optimize.h" - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Bitset of flags that switch the different optimizer passes */ -unsigned long OptDisable = 0; - - - -/* Bitmapped flags for the Flags field in the Line struct */ -#define OF_CODE 0x0001 /* This line is in a code segment */ - -/* Pointer to first code line */ -static Line* FirstCode; - -/* Label list */ -static Line** Labels = 0; /* Pointers to label lines */ -static unsigned LabelCount = 0; /* Count of local labels found */ - -/* A collection of lines */ -typedef struct LineColl_ LineColl; -struct LineColl_ { - unsigned Count; /* Count of lines in the collection */ - unsigned Max; /* Maximum count of lines */ - Line* Lines[1]; /* Lines, dynamically allocated */ -}; - - - -/* Calculate the element count of a table */ -#define COUNT(T) (sizeof (T) / sizeof (T [0])) - -/* Macro to increment and decrement register contents if they're valid */ -#define INC(reg,val) if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF -#define DEC(reg,val) if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF - -/* Defines for the conditions in a compare */ -#define CMP_EQ 0 -#define CMP_NE 1 -#define CMP_GT 2 -#define CMP_GE 3 -#define CMP_LT 4 -#define CMP_LE 5 -#define CMP_UGT 6 -#define CMP_UGE 7 -#define CMP_ULT 8 -#define CMP_ULE 9 - -/* Defines for registers */ -#define REG_NONE 0x00 -#define REG_A 0x01 -#define REG_X 0x02 -#define REG_Y 0x04 -#define REG_AX (REG_A | REG_X) -#define REG_ALL (REG_A | REG_X | REG_Y) - -/* Description of the commands */ -static const struct { - const char* Insn; /* Instruction */ - unsigned char FullMatch; /* Match full instuction? */ - unsigned char Use; /* Registers used */ - unsigned char Load; /* Registers loaded */ -} CmdDesc [] = { - { "\tadc\t", 0, REG_A, REG_NONE }, - { "\tand\t", 0, REG_A, REG_NONE }, - { "\tasl\ta", 1, REG_A, REG_NONE }, - { "\tasl\t", 0, REG_NONE, REG_NONE }, - { "\tclc", 1, REG_NONE, REG_NONE }, - { "\tcld", 1, REG_NONE, REG_NONE }, - { "\tcli", 1, REG_NONE, REG_NONE }, - { "\tcmp\t", 0, REG_A, REG_NONE }, - { "\tcpx\t", 0, REG_X, REG_NONE }, - { "\tcpy\t", 0, REG_Y, REG_NONE }, - { "\tdea", 1, REG_A, REG_NONE }, - { "\tdec\ta", 1, REG_A, REG_NONE }, - { "\tdec\t", 0, REG_NONE, REG_NONE }, - { "\tdex", 1, REG_X, REG_NONE }, - { "\tdey", 1, REG_Y, REG_NONE }, - { "\teor\t", 0, REG_A, REG_NONE }, - { "\tina", 1, REG_A, REG_NONE }, - { "\tinc\ta", 1, REG_A, REG_NONE }, - { "\tinc\t", 0, REG_NONE, REG_NONE }, - { "\tinx", 1, REG_X, REG_NONE }, - { "\tiny", 1, REG_Y, REG_NONE }, - { "\tjsr\tbool", 0, REG_NONE, REG_AX }, - { "\tjsr\tdecaxy", 1, REG_ALL, REG_AX }, - { "\tjsr\tdecax", 0, REG_AX, REG_AX }, - { "\tjsr\tdecsp2", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp3", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp4", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp5", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp6", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp7", 1, REG_NONE, REG_A }, - { "\tjsr\tdecsp8", 1, REG_NONE, REG_A }, - { "\tjsr\tldax0sp", 1, REG_Y, REG_AX }, - { "\tjsr\tldaxysp", 1, REG_Y, REG_AX }, - { "\tjsr\tpusha", 1, REG_A, REG_Y }, - { "\tjsr\tpusha0", 1, REG_A, REG_X | REG_Y }, - { "\tjsr\tpushax", 1, REG_AX, REG_Y }, - { "\tjsr\tpushw0sp", 1, REG_NONE, REG_ALL }, - { "\tjsr\tpushwysp", 1, REG_Y, REG_ALL }, - { "\tjsr\ttosicmp", 1, REG_AX, REG_ALL }, - { "\tlda\t", 0, REG_NONE, REG_A }, - { "\tldax\t", 0, REG_NONE, REG_AX }, - { "\tldx\t", 0, REG_NONE, REG_X }, - { "\tldy\t", 0, REG_NONE, REG_Y }, - { "\tlsr\ta", 1, REG_A, REG_NONE }, - { "\tlsr\t", 0, REG_NONE, REG_NONE }, - { "\tnop", 1, REG_NONE, REG_NONE }, - { "\tora\t", 0, REG_A, REG_NONE }, - { "\tpha", 1, REG_A, REG_NONE }, - { "\tphp", 1, REG_NONE, REG_NONE }, - { "\tpla", 1, REG_NONE, REG_A }, - { "\tplp", 1, REG_NONE, REG_NONE }, - { "\trol\ta", 1, REG_A, REG_A }, - { "\trol\t", 0, REG_NONE, REG_NONE }, - { "\tror\ta", 1, REG_A, REG_A }, - { "\tror\t", 0, REG_NONE, REG_NONE }, - { "\tsbc\t", 0, REG_A, REG_NONE }, - { "\tsec", 1, REG_NONE, REG_NONE }, - { "\tsed", 1, REG_NONE, REG_NONE }, - { "\tsei", 1, REG_NONE, REG_NONE }, - { "\tsta\t", 0, REG_A, REG_NONE }, - { "\tstx\t", 0, REG_X, REG_NONE }, - { "\tsty\t", 0, REG_Y, REG_NONE }, - { "\tstz\t", 0, REG_NONE, REG_NONE }, - { "\ttax", 1, REG_A, REG_X }, - { "\ttay", 1, REG_A, REG_Y }, - { "\ttrb\t", 0, REG_A, REG_NONE }, - { "\ttsb\t", 0, REG_A, REG_NONE }, - { "\ttsx", 1, REG_NONE, REG_X }, - { "\ttxa", 1, REG_X, REG_A }, - { "\ttya", 1, REG_Y, REG_A }, -}; - - - -/* 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, - CMP_LE, CMP_LT, CMP_GE, CMP_GT, - 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 -}; - - - -/* Lists of branches */ -static const char* ShortBranches [] = { - "\tbeq\t", - "\tbne\t", - "\tbpl\t", - "\tbmi\t", - "\tbcc\t", - "\tbcs\t", - "\tbvc\t", - "\tbvs\t", - 0 -}; -static const char* LongBranches [] = { - "\tjeq\t", - "\tjne\t", - "\tjpl\t", - "\tjmi\t", - "\tjcc\t", - "\tjcs\t", - "\tjvc\t", - "\tjvs\t", - 0 -}; - - - -/*****************************************************************************/ -/* Forwards */ -/*****************************************************************************/ - - - -static unsigned EstimateSize (Line* L); -/* Estimate the size of an instruction */ - -static int IsLocalLabel (const Line* L); -/* Return true if the line is a local label line */ - -static unsigned GetLabelNum (const char* L); -/* Return the label number of a label line */ - -static unsigned RVUInt1 (Line* L, LineColl* LC, unsigned Used, unsigned Unused); -/* Subfunction for RegValUsed. Will be called recursively in case of branches. */ - -static Line* NewLineAfter (Line* LineBefore, const char* Format, ...) attribute ((format(printf,2,3))); -/* Create a new line, insert it after L and return it. The new line is marked - * as code line. - */ - -static Line* ReplaceLine (Line* L, const char* Format, ...) - attribute ((format(printf,2,3))); -/* Replace one line by another */ - - - -/*****************************************************************************/ -/* List stuff */ -/*****************************************************************************/ - - - -static Line* NewLineAfter (Line* LineBefore, const char* Format, ...) -/* Create a new line, insert it after L and return it. The new line is marked - * as code line. - */ -{ - Line* L; - - /* Format the new line and add it */ - va_list ap; - va_start (ap, Format); - L = NewCodeLineAfter (LineBefore, Format, ap); - va_end (ap); - - /* Make the line a code line */ - L->Flags = OF_CODE; - - /* Estimate the code size */ - L->Size = EstimateSize (L); - - /* Return the new line */ - return L; -} - - - -static Line* NewLabelAfter (Line* L, unsigned Label) -/* Add a new line with a definition of a local label after the line L */ -{ - char Buf [32]; - - /* Create the label */ - sprintf (Buf, "L%04X:", Label); - - /* Create a new line */ - L = NewLineAfter (L, Buf); - - /* Insert this label into the label list */ - Labels [Label] = L; - - /* Return the new line */ - return L; -} - - - -static void FreeLine (Line* L) -/* Remove a line from the list and free it */ -{ - /* If this is a label line, remove it from the label list */ - if (IsLocalLabel (L)) { - Labels [GetLabelNum (L->Line)] = 0; - } - - /* Unlink the line */ - FreeCodeLine (L); -} - - - -static Line* ReplaceLine (Line* L, const char* Format, ...) -/* Replace one line by another */ -{ - unsigned Len; - char S [256]; - - /* Format the new line */ - va_list ap; - va_start (ap, Format); - xvsprintf (S, sizeof (S), Format, ap); - va_end (ap); - - /* Get the length of the new line */ - Len = strlen (S); - - /* We can copy the line if the old line has space enough */ - if (Len <= L->Len) { - - /* Just copy the new line, but don't update the length */ - memcpy (L->Line, S, Len); - L->Line [Len] = '\0'; - - } else { - - /* We must allocate new space */ - Line* NewLine = xmalloc (sizeof (Line) + Len); - - /* Set the values in the new struct */ - NewLine->Flags = L->Flags; - NewLine->Index = L->Index; - NewLine->Size = L->Size; /* Hmm ... */ - NewLine->Len = Len; - memcpy (NewLine->Line, S, Len + 1); - - /* Replace the old struct in the list */ - NewLine->Next = L->Next; - if (NewLine->Next) { - NewLine->Next->Prev = NewLine; - } else { - /* Last line */ - LastLine = NewLine; - } - NewLine->Prev = L->Prev; - if (NewLine->Prev) { - NewLine->Prev->Next = NewLine; - } else { - /* First line */ - FirstLine = NewLine; - } - - /* Free the old struct */ - xfree (L); - L = NewLine; - } - - /* Estimate the new size */ - if (L->Flags & OF_CODE) { - L->Size = EstimateSize (L); - } - - /* Return the line */ - return L; -} - - - -static Line* PrevCodeLine (Line* L) -/* Return the previous line containing code */ -{ - L = L->Prev; - while (L) { - if (L->Flags & OF_CODE && L->Line [0] != '+') { - break; - } - L = L->Prev; - } - return L; -} - - - -static Line* NextCodeSegLine (Line* L) -/* Return the next line in the code segment */ -{ - L = L->Next; - while (L) { - if (L->Flags & OF_CODE) { - break; - } - L = L->Next; - } - return L; -} - - - -static Line* NextCodeLine (Line* L) -/* Return the next line containing code */ -{ - L = L->Next; - while (L) { - if ((L->Flags & OF_CODE) != 0 && L->Line [0] != '+') { - break; - } - L = L->Next; - } - return L; -} - - - -static Line* NextInstruction (Line* L) -/* Return the next line containing code, ignoring labels. */ -{ - do { - L = NextCodeLine (L); - } while (L && (L->Line[0] == '+' || IsLocalLabel(L))); - return L; -} - - - -static void FreeLines (Line* Start, Line* End) -/* Delete all lines from Start to End, both inclusive */ -{ - Line* L; - do { - L = Start; - Start = NextCodeSegLine (Start); - FreeLine (L); - } while (L != End); -} - - - -/*****************************************************************************/ -/* Line Collections */ -/*****************************************************************************/ - - - -static LineColl* NewLineColl (unsigned Size) -/* Create a new line collection and return it */ -{ - /* Allocate memory */ - LineColl* LC = xmalloc (sizeof (LineColl) + sizeof (Line) * (Size-1)); - - /* Initialize members */ - LC->Count = 0; - LC->Max = Size; - - /* Return the new collection */ - return LC; -} - - - -static void FreeLineColl (LineColl* LC) -/* Delete a line collection */ -{ - xfree (LC); -} - - - -static int LCAddLine (LineColl* LC, Line* L) -/* Add a line. Return 0 if no space available, return 1 otherwise */ -{ - /* Check if there is enough space available */ - if (LC->Count >= LC->Max) { - /* No room available */ - return 0; - } - - /* Add the line */ - LC->Lines [LC->Count++] = L; - - /* Done */ - return 1; -} - - - -static int LCHasLine (LineColl* LC, Line* L) -/* Check if the given line is in the collection */ -{ - unsigned I; - for (I = 0; I < LC->Count; ++I) { - if (LC->Lines[I] == L) { - return 1; - } - } - return 0; -} - - - -/*****************************************************************************/ -/* Test a line for several things */ -/*****************************************************************************/ - - - -static int IsLocalLabel (const Line* L) -/* Return true if the line is a local label line */ -{ - return (L->Line [0] == 'L' && IsXDigit (L->Line [1])); -} - - - -static int IsExtLabel (const Line* L) -/* Return true if the line is an external label line */ -{ - return (L->Line [0] == '_'); -} - - - -static int IsLabel (const Line* L) -/* Return true if the line is a label line */ -{ - return (L->Line [0] == 'L' && IsXDigit (L->Line [1])) || - (L->Line [0] == '_');; -} - - - -static int IsHintLine (const Line* L) -/* Return true if the line contains an optimizer hint */ -{ - return L->Line [0] == '+'; -} - - - -static int IsSegHint (const Line* L) -/* Return true if the given line contains a segment hint */ -{ - return (L->Line [0] == '+' && strncmp (L->Line + 1, "seg:", 4) == 0); -} - - - -static int IsHint (const Line* L, const char* Hint) -/* Check if the line contains a given hint */ -{ - return (L->Line [0] == '+' && strcmp (L->Line + 1, Hint) == 0); -} - - - -static int IsCondJump (const Line* L) -/* Return true if the line contains a conditional jump */ -{ - return (L->Line [0] == '\t' && - (strncmp (L->Line + 1, "beq\t", 4) == 0 || - strncmp (L->Line + 1, "bne\t", 4) == 0 || - strncmp (L->Line + 1, "jeq\t", 4) == 0 || - strncmp (L->Line + 1, "jne\t", 4) == 0)); -} - - - -static int IsXAddrMode (const Line* L) -/* Return true if the given line does use the X register */ -{ - unsigned Len = strlen (L->Line); - return (strcmp (L->Line + Len - 3, ",x)") == 0 || - strcmp (L->Line + Len - 2, ",x") == 0); -} - - - -static int NoXAddrMode (const Line* L) -/* Return true if the given line does use the X register */ -{ - return !IsXAddrMode (L); -} - - - -static int IsYAddrMode (const Line* L) -/* Return true if the given line does use the Y register */ -{ - unsigned Len = strlen (L->Line); - return (strcmp (L->Line + Len - 2, ",y") == 0); -} - - - -static int Is16BitStore (const Line* L1, const Line* L2) -/* Check if L1 and L2 are a store of ax into a 16 bit location */ -{ - unsigned Len1 = strlen (L1->Line); - return (strncmp (L1->Line, "\tsta\t", 5) == 0 && - strncmp (L2->Line, "\tstx\t", 5) == 0 && - strncmp (L1->Line+5, L2->Line+5, Len1-5) == 0 && - strcmp (L2->Line+Len1, "+1") == 0); -} - - - -static Line* FindHint (Line* L, const char* Hint) -/* Search for a line with the given hint */ -{ - while (L) { - if (IsHint (L, Hint)) { - break; - } - L = L->Next; - } - return L; -} - - - -static unsigned GetHexNum (const char* S) -/* Get a hex number from a string */ -{ - unsigned I = 0; - unsigned Val = 0; - while (IsXDigit (S [I])) { - int C = (unsigned char) (S [I++]); - if (C >= 'A') { - C -= 'A' - 10; - } else { - C -= '0'; - } - Val = (Val << 4) + C; - } - return Val; -} - - - -static unsigned GetLabelNum (const char* L) -/* Return the label number of a label line */ -{ - CHECK (*L == 'L'); - return GetHexNum (L+1); -} - - - -static Line* GetTargetLine (const char* L) -/* Get the line with the target label of a jump. L must be a pointer to the - * string containing the label number. - */ -{ - Line* Target; - - /* Get the label number of the target */ - unsigned Label = GetLabelNum (L); - CHECK (Label < LabelCount); - - /* Get the line with this label */ - Target = Labels [Label]; - CHECK (Target != 0 && (Target->Flags & OF_CODE) != 0); - - /* And return it */ - return Target; -} - - - -static unsigned GetJumpDistance (Line* L, Line* Target) -/* Get the distance between both lines */ -{ - unsigned Distance = 0; - - if (L != Target) { - if (Target->Index > L->Index) { - /* This is a forward jump. */ - do { - L = NextCodeLine (L); - Distance += L->Size; - } while (L != Target); - } else { - /* This is a backward jump */ - do { - L = PrevCodeLine (L); - Distance += L->Size; - } while (L != Target); - } - } - - /* Return the calculated distance */ - return Distance; -} - - - -static int LineMatch (const Line* L, const char* Start) -/* Check if the start of the line matches Start */ -{ - return strncmp (L->Line, Start, strlen (Start)) == 0; -} - - - -static int LineFullMatch (const Line* L, const char* Start) -/* Check if the matches Start */ -{ - return strcmp (L->Line, Start) == 0; -} - - - -static int LineMatchX (const Line* L, const char** Start) -/* Check the start of the line against a list of patterns. Return the - * number of the pattern that matched, or -1 in case of no match. - */ -{ - unsigned I = 0; - while (*Start) { - if (LineMatch (L, *Start)) { - /* Found */ - return I; - } - ++Start; - ++I; - } - /* Not found */ - return -1; -} - - - -static int LineFullMatchX (const Line* L, const char** Start) -/* Check the the line against a list of patterns. Return the - * number of the pattern that matched, or -1 in case of no match. - */ -{ - unsigned I = 0; - while (*Start) { - if (LineFullMatch (L, *Start)) { - /* Found */ - return I; - } - ++Start; - ++I; - } - /* Not found */ - return -1; -} - - - -static int IsLoadAX (Line* L1, Line* L2) -/* Check if the both lines load a static variable into ax. That is, both lines - * look like - * lda x+0 - * ldx x+0+1 - */ -{ - return LineMatch (L1, "\tlda\t") && - LineMatch (L2, "\tldx\t") && - strncmp (L1->Line+5, L2->Line+5, strlen (L1->Line+5)) == 0 && - strcmp (L2->Line+strlen(L1->Line), "+1") == 0; -} - - - -/*****************************************************************************/ -/* Initial optimizer setup */ -/*****************************************************************************/ - - - -static void FindCodeStart (void) -/* Find and remember the first line of actual code */ -{ - Line* L = FindHint (FirstLine, "end_of_preamble"); - FirstCode = L? L->Next : 0; -} - - - -static unsigned EstimateDataSize (Line* L, unsigned Chunk) -/* Estimate the size of a .byte, .word or .dword command */ -{ - unsigned Size = Chunk; - char* S = L->Line; - while ((S = strchr (S, ',')) != 0) { - Size += Chunk; - ++S; - } - return Size; -} - - - -static unsigned EstimateSize (Line* L) -/* Estimate the size of an instruction */ -{ - static const char* OneByteCmds [] = { - "\tdea", - "\tdex", - "\tdey", - "\tina", - "\tinx", - "\tiny" - "\ttax", - "\ttay", - "\ttsx", - "\ttxa", - "\ttya", - 0 - }; - char OpStart; - - if (L->Line [0] != '\t') { - return 0; - } - if (LineMatch (L, "\tldax\t")) { - /* Immidiate load of both, A and X */ - return 4; - } - if (LineMatch (L, "\tld")) { - OpStart = L->Line [5]; - return (OpStart == '#' || OpStart == '(')? 2 : 3; - } - if (LineMatch (L, "\tst")) { - OpStart = L->Line [5]; - return (OpStart == '(')? 2 : 3; - } - if (LineMatch (L, "\t.byte\t")) { - return EstimateDataSize (L, 1); - } - if (LineMatch (L, "\t.word\t")) { - return EstimateDataSize (L, 2); - } - if (LineMatch (L, "\t.dword\t")) { - return EstimateDataSize (L, 4); - } - if (LineMatchX (L, ShortBranches) >= 0) { - return 2; - } - if (LineMatchX (L, LongBranches) >= 0) { - return 5; - } - if (LineMatchX (L, OneByteCmds) >= 0) { - return 1; - } - return 3; -} - - - -static void MarkCodeLines (void) -/* Mark all lines that are inside a code segment */ -{ - int InCode = 1; - Line* L = FirstCode; - while (L) { - if (IsSegHint (L)) { - InCode = IsHint (L, "seg:code"); - } else if (InCode && L->Line[0] != '\0') { - L->Flags |= OF_CODE; - L->Size = EstimateSize (L); - } - L = L->Next; - } -} - - - -static void CreateLabelList (void) -/* Create a list with pointers to local labels */ -{ - unsigned I; - Line* L; - - - /* Get the next label number. This is also the current label count. - * Make some room for more labels when optimizing code. - */ - LabelCount = GetLocalLabel () + 100; - - /* Allocate memory for the array and clear it */ - Labels = xmalloc (LabelCount * sizeof (Line*)); - for (I = 0; I < LabelCount; ++I) { - Labels [I] = 0; - } - - /* Walk through the code and insert all label lines */ - L = FirstLine; - while (L) { - if (IsLocalLabel (L)) { - unsigned LabelNum = GetLabelNum (L->Line); - CHECK (LabelNum < LabelCount); - Labels [LabelNum] = L; - } - L = L->Next; - } -} - - - -static unsigned AllocLabel (void) -/* Get a new label. The current code does not realloc the label list, so there - * must be room enough in the current list. - */ -{ - unsigned I; - - /* Search for a free slot, start at 1, since 0 is "no label" */ - for (I = 1; I < LabelCount; ++I) { - if (Labels[I] == 0) { - /* Found a free slot */ - return I; - } - } - - /* No label space available */ - Internal ("Out of label space in the optimizer"); - - /* Not reached */ - return 0; -} - - - -/*****************************************************************************/ -/* Helper functions */ -/*****************************************************************************/ - - - -static int GetNextCodeLines (Line* L, Line** Lines, unsigned Count) -/* Get a number of code lines ignoring hints and other stuff. The function - * returns 1 if we got the lines and 0 if we are at the end of the code - * segment or if we hit a label. - */ -{ - while (Count--) { - - /* Get the next valid line */ - do { - L = NextCodeLine (L); - } while (L && IsHintLine (L)); - - /* Did we get one? */ - if (L == 0 || IsLabel (L)) { - /* Error */ - return 0; - } - - /* Remember the line */ - *Lines++ = L; - } - - /* Success */ - return 1; -} - - - -static int FindCond (const char* Suffix) -/* Map a condition suffix to a code. Return the code or -1 on failure */ -{ - int I; - - /* Linear search */ - for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) { - if (strncmp (Suffix, CmpSuffixTab [I], strlen (CmpSuffixTab[I])) == 0) { - /* Found */ - return I; - } - } - - /* Not found */ - return -1; -} - - - -static int CheckAndGetIntCmp (const Line* JSR, const Line* JMP) -/* Helper function to check for a compare subroutine call followed by a - * conditional branch. Will return the condition found, or -1 if no - * or invalid condition. - */ -{ - char Cond[5]; - const char* Tail; - int C; - - /* Extract the condition from the function name. */ - if ((Cond [0] = JSR->Line [8]) == 'u') { - Cond [1] = JSR->Line [9]; - Cond [2] = JSR->Line [10]; - Cond [3] = '\0'; - Tail = JSR->Line + 11; - } else { - Cond [1] = JSR->Line [9]; - Cond [2] = '\0'; - Tail = JSR->Line + 10; - } - - /* Check if this is indeed an integer function */ - if (strcmp (Tail, "ax") != 0) { - /* No! */ - return -1; - } - - /* Get the condition code */ - C = FindCond (Cond); - if (C < 0) { - /* OOPS! */ - return -1; - } - - /* Invert the code if we jump on condition not met. */ - if (JMP->Line [2] == 'e' && JMP->Line [3] == 'q') { - /* Jumps if condition false, invert condition */ - C = CmpInvertTab [C]; - } - - /* Return the condition code */ - return C; -} - - - -static int TosCmpFunc (Line* L) -/* Check if this is a call to one of the TOS compare functions (tosgtax). - * Return the condition code or -1 if not found. - */ -{ - if (LineMatch (L, "\tjsr\ttos") && - strcmp (L->Line+strlen(L->Line)-2, "ax") == 0) { - - /* Ok, found. Get the condition. */ - return FindCond (L->Line+8); - - } else { - - /* Not found */ - return -1; - } -} - - - -static int IsUnsignedCmp (int Code) -/* Check if this is an unsigned compare */ -{ - CHECK (Code >= 0); - return CmpSignedTab [Code] == 0; -} - - - -static void InvertZJump (Line* L) -/* Invert a jeq/jne jump */ -{ - if (L->Line [2] == 'n' && L->Line [3] == 'e') { - /* This was a bne/jne */ - L->Line [2] = 'e'; - L->Line [3] = 'q'; - } else { - /* This was (hopefully) a beq/jeq */ - L->Line [2] = 'n'; - L->Line [3] = 'e'; - } -} - - - -static int FindCmd (Line* L) -{ - int I; - - /* Search for the known patterns */ - for (I = 0; I < COUNT(CmdDesc); ++I) { - if (CmdDesc[I].FullMatch) { - if (LineFullMatch (L, CmdDesc[I].Insn)) { - /* found */ - return I; - } - } else { - if (LineMatch (L, CmdDesc[I].Insn)) { - /* found */ - return I; - } - } - } - /* Not found */ - return -1; -} - - - -static unsigned RVUInt2 (Line* L, - LineColl* LC, /* To remember visited lines */ - unsigned Used, /* Definitely used registers */ - unsigned Unused) /* Definitely unused registers */ -/* Subfunction for RegValUsed. Will be called recursively in case of branches. */ -{ - int I; - - /* Check the following instructions. We classifiy them into primary - * loads (register value not used), neutral (check next instruction), - * and unknown (assume register was used). - */ - while (1) { - - unsigned R; - - /* Get the next line and follow jumps */ - do { - - /* Handle jumps to local labels (continue there) */ - if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) { - /* Get the target of the jump */ - L = GetTargetLine (L->Line+5); - } - - /* Get the next line, skip local labels */ - do { - L = NextCodeSegLine (L); - } while (L && (IsLocalLabel (L) || L->Line[0] == '\0')); - - /* Bail out if we're done */ - if (L == 0 || IsExtLabel (L)) { - /* End of function reached */ - goto ExitPoint; - } - - /* Check if we had this line already. If so, bail out, if not, - * add it to the list of known lines. - */ - if (LCHasLine (LC, L) || !LCAddLine (LC, L)) { - goto ExitPoint; - } - - } while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")); - - /* Special handling of code hints */ - if (IsHintLine (L)) { - - if (IsHint (L, "a:-") && (Used & REG_A) == 0) { - Unused |= REG_A; - } else if (IsHint (L, "x:-") && (Used & REG_X) == 0) { - Unused |= REG_X; - } else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) { - Unused |= REG_Y; - } - - /* Special handling for branches */ - } else if (LineMatchX (L, ShortBranches) >= 0 || - LineMatchX (L, LongBranches) >= 0) { - const char* Target = L->Line+5; - if (Target[0] == 'L') { - /* Jump to local label. Check the register usage starting at - * the branch target and at the code following the branch. - * All registers that are unused in both execution flows are - * returned as unused. - */ - unsigned U1, U2; - U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused); - U1 = RVUInt1 (L, LC, Used, Unused); - return U1 | U2; /* Used in any of the branches */ - } - } else { - - /* Search for the instruction in this line */ - I = FindCmd (L); - - /* If we don't find it, assume all other registers are used */ - if (I < 0) { - break; - } - - /* Evaluate the use flags, check for addressing modes */ - R = CmdDesc[I].Use; - if (IsXAddrMode (L)) { - R |= REG_X; - } else if (IsYAddrMode (L)) { - R |= REG_Y; - } - if (R) { - /* Remove registers that were already new loaded */ - R &= ~Unused; - - /* Remember the remaining registers */ - Used |= R; - } - - /* Evaluate the load flags */ - R = CmdDesc[I].Load; - if (R) { - /* Remove registers that were already used */ - R &= ~Used; - - /* Remember the remaining registers */ - Unused |= R; - } - - } - - /* If we know about all registers, bail out */ - if ((Used | Unused) == REG_ALL) { - break; - } - } - -ExitPoint: - /* Return to the caller the complement of all unused registers */ - return ~Unused & REG_ALL; -} - - - -static unsigned RVUInt1 (Line* L, - LineColl* LC, /* To remember visited lines */ - unsigned Used, /* Definitely used registers */ - unsigned Unused) /* Definitely unused registers */ -/* Subfunction for RegValUsed. Will be called recursively in case of branches. */ -{ - /* Remember the current count of the line collection */ - unsigned Count = LC->Count; - - /* Call the worker routine */ - unsigned R = RVUInt2 (L, LC, Used, Unused); - - /* Restore the old count */ - LC->Count = Count; - - /* Return the result */ - return R; -} - - - -static unsigned RegValUsed (Line* Start) -/* Check the next instructions after the one in L for register usage. If - * a register is used as an index, or in a store or other instruction, it - * is assumed to be used. If a register is loaded with a value, before it - * was used by one of the actions described above, it is assumed unused. - * If the end of the lookahead is reached, all registers that are uncertain - * are marked as used. - * The result of the search is returned. - */ -{ - unsigned R; - - /* Create a new line collection and enter the start line */ - LineColl* LC = NewLineColl (256); - LCAddLine (LC, Start); - - /* Call the recursive subfunction */ - R = RVUInt1 (Start, LC, REG_NONE, REG_NONE); - - /* Delete the line collection */ - FreeLineColl (LC); - - /* Return the registers used */ - return R; -} - - - -static int RegAUsed (Line* Start) -/* Check if the value in A is used. */ -{ - return (RegValUsed (Start) & REG_A) != 0; -} - - - -static int RegXUsed (Line* Start) -/* Check if the value in X is used. */ -{ - return (RegValUsed (Start) & REG_X) != 0; -} - - - -static int RegYUsed (Line* Start) -/* Check if the value in Y is used. */ -{ - return (RegValUsed (Start) & REG_Y) != 0; -} - - - -/*****************************************************************************/ -/* Real optimizer routines */ -/*****************************************************************************/ - - - -static void OptCompares1 (void) -/* Try to optimize the integer compare subroutines. */ -{ - Line* L2[10]; /* Line lookahead */ - int Cond; /* Condition to evaluate */ - unsigned Label; /* Local label number */ - unsigned Offs; /* Stack offset */ - Line* DelStart; /* First line to delete */ - - Line* L = FirstCode; - while (L) { - - /* Search for compares of local byte sized variables. This looks - * like: - * - * ldy #$xx - * ldx #$00 - * lda (sp),y - * jsr pushax - * ldy #$yy - * ldx #$00 - * lda (sp),y - * jsr tosugtax - * - * Replace it by a direct compare: - * - * ldy #$xx - * lda (sp),y - * ldy #$yy - * cmp (sp),y - * jsr boolugt - */ - if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 7) && - LineFullMatch (L2[0], "\tldx\t#$00") && - LineFullMatch (L2[1], "\tlda\t(sp),y") && - LineFullMatch (L2[2], "\tjsr\tpushax") && - LineMatch (L2[3], "\tldy\t#$") && - LineFullMatch (L2[4], "\tldx\t#$00") && - LineFullMatch (L2[5], "\tlda\t(sp),y") && - (Cond = TosCmpFunc (L2[6])) >= 0) { - - /* Get the stack offset and correct it, since we will remove - * the pushax. - */ - Offs = GetHexNum (L2[3]->Line+7) - 2; - - /* Replace it */ - L = NewLineAfter (L, "\tlda\t(sp),y"); - L = NewLineAfter (L, "\tldy\t#$%02X", Offs); - L = NewLineAfter (L, "\tcmp\t(sp),y"); - L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]); - - /* Remove the old cruft */ - FreeLines (L2[0], L2[6]); - } - - /* Compares of byte sized global variables */ - else if (LineFullMatch (L, "\tldx\t#$00") && - GetNextCodeLines (L, L2, 5) && - LineMatch (L2[0], "\tlda\t") && - LineFullMatch (L2[1], "\tjsr\tpushax") && - LineFullMatch (L2[2], "\tldx\t#$00") && - LineMatch (L2[3], "\tlda\t") && - (Cond = TosCmpFunc (L2[4])) >= 0) { - - /* Replace it */ - if (IsXAddrMode (L2[0])) { - /* The load is X indirect, so we may not remove the load - * of the X register. - */ - L = L2[0]; - DelStart = L2[1]; - } else { - L = ReplaceLine (L, L2[0]->Line); - DelStart = L2[0]; - } - L = NewLineAfter (L, "\tcmp\t%s", L2[3]->Line+5); - L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]); - - /* Remove the old cruft */ - FreeLines (DelStart, L2[4]); - - } - - /* Byte sized local to global */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 6) && - LineFullMatch (L2[0], "\tldx\t#$00") && - LineFullMatch (L2[1], "\tlda\t(sp),y") && - LineFullMatch (L2[2], "\tjsr\tpushax") && - LineFullMatch (L2[3], "\tldx\t#$00") && - LineMatch (L2[4], "\tlda\t") && - (Cond = TosCmpFunc (L2[5])) >= 0) { - - /* Replace it */ - L = NewLineAfter (L, L2[1]->Line); - L = NewLineAfter (L, "\tcmp\t%s", L2[4]->Line+5); - L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]); - - /* Remove the old cruft */ - FreeLines (L2[0], L2[5]); - - } - - /* Byte sized global to local */ - else if (LineFullMatch (L, "\tldx\t#$00") && - GetNextCodeLines (L, L2, 6) && - LineMatch (L2[0], "\tlda\t") && - LineFullMatch (L2[1], "\tjsr\tpushax") && - LineMatch (L2[2], "\tldy\t#$") && - LineFullMatch (L2[3], "\tldx\t#$00") && - LineFullMatch (L2[4], "\tlda\t(sp),y") && - (Cond = TosCmpFunc (L2[5])) >= 0) { - - /* Get the stack offset and correct it, since we will remove - * the pushax. - */ - Offs = GetHexNum (L2[2]->Line+7) - 2; - - /* Replace it */ - if (IsXAddrMode (L2[0])) { - /* The load is X indirect, so we may not remove the load - * of the X register. - */ - L = L2[0]; - DelStart = L2[1]; - } else { - L = ReplaceLine (L, L2[0]->Line); - DelStart = L2[0]; - } - L = NewLineAfter (L, "\tldy\t#$%02X", Offs); - L = NewLineAfter (L, "\tcmp\t(sp),y"); - L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]); - - /* Remove the old cruft */ - FreeLines (DelStart, L2[5]); - - } - - /* Search for unsigned compares against global variables. This looks - * like: - * - * jsr pushax - * lda _b+0 - * ldx _b+0+1 - * jsr tosugtax - * - * Replace that by a direct compare: - * - * cpx _b+0+1 - * bne L - * cmp _b+0 - * L: - * jsr boolugt - */ - else if (LineFullMatch (L, "\tjsr\tpushax") && - GetNextCodeLines (L, L2, 3) && - IsLoadAX (L2[0], L2[1]) && - (Cond = TosCmpFunc (L2[2])) >= 0 && - IsUnsignedCmp (Cond)) { - - /* Get a free label number */ - Label = AllocLabel (); - - /* Replace the code */ - L = ReplaceLine (L, "\tcpx\t%s", L2[1]->Line+5); - L = NewLineAfter (L, "\tbne\tL%04X", Label); - L = NewLineAfter (L, "\tcmp\t%s", L2[0]->Line+5); - L = NewLabelAfter(L, Label); - L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]); - - /* Remove the old code */ - FreeLines (L2[0], L2[2]); - - } - - L = NextCodeLine (L); - } -} - - - -static void OptDeadJumps (void) -/* Remove jumps to the following instruction */ -{ - static const char* Jumps [] = { - "\tbeq\tL", - "\tbne\tL", - "\tjeq\tL", - "\tjne\tL", - "\tjmp\tL", - 0 - }; - - Line* L = FirstCode; - while (L) { - - /* Get a pointer to the next instruction line */ - Line* NextLine = NextInstruction (L); - - /* Is this line a jump? */ - int I = LineMatchX (L, Jumps); - if (I >= 0) { - /* Yes. Get the target label, skip labels */ - Line* Target = NextInstruction (GetTargetLine (L->Line+5)); - - /* If the target label is the next line, remove the jump */ - if (Target == NextLine) { - FreeLine (L); - } - } - - /* Go to the next line */ - L = NextLine; - } -} - - - -static void OptLoads (void) -/* Remove unnecessary loads of values */ -{ - unsigned Changes; - - do { - - Line* L2 [10]; - Line* L = FirstCode; - Changes = 0; - while (L) { - - /* Check for - * - * ldy #$.. - * lda (sp),y - * tax - * dey - * lda (sp),y - * jsr pushax - * - * and replace it by - * - * ldy #$.. - * jsr pushwysp - * - * or even - * - * jsr pushw0sp - * - * This change will cost 3 cycles (one additional jump inside the - * subroutine), but it saves a lot of code (6 bytes per occurrence), - * so we will accept the overhead. It may even be possible to rewrite - * the library routine to get rid of the additional overhead. - */ - if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 5) && - LineFullMatch (L2 [0], "\tlda\t(sp),y") && - LineFullMatch (L2 [1], "\ttax") && - LineFullMatch (L2 [2], "\tdey") && - LineFullMatch (L2 [3], "\tlda\t(sp),y") && - LineFullMatch (L2 [4], "\tjsr\tpushax")) { - - /* Found - replace it */ - if (LineFullMatch (L, "\tldy\t#$01")) { - /* Word at offset zero */ - FreeLine (L); - L = ReplaceLine (L2 [4], "\tjsr\tpushw0sp"); - } else { - ReplaceLine (L2 [4], "\tjsr\tpushwysp"); - } - - /* Delete the remaining lines */ - FreeLines (L2 [0], L2 [3]); - - /* We have changes */ - ++Changes; - - /* Check for - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * ldy #$yy - * jsr ldauidx - * - * and replace it by - * - * ldy #$xx - * ldx #$yy - * jsr ldauiysp - * - * or even - * - * jsr ldaui0sp - * - * This change will cost 2 cycles, but it saves a lot of code (6 bytes - * per occurrence), so we will accept the overhead. It may even be - * possible to rewrite the library routine to get rid of the additional - * overhead. - */ - } else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 6) && - LineFullMatch (L2 [0], "\tlda\t(sp),y") && - LineFullMatch (L2 [1], "\ttax") && - LineFullMatch (L2 [2], "\tdey") && - LineFullMatch (L2 [3], "\tlda\t(sp),y") && - LineMatch (L2 [4], "\tldy\t#$") && - LineFullMatch (L2 [5], "\tjsr\tldauidx")) { - - /* Found - replace it */ - L2 [4]->Line [3] = 'x'; /* Change to ldx */ - if (LineFullMatch (L, "\tldy\t#$01")) { - /* Word at offset zero */ - FreeLine (L); - L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp"); - } else { - ReplaceLine (L2 [5], "\tjsr\tldauiysp"); - } - - /* Delete the remaining lines */ - FreeLines (L2 [0], L2 [3]); - - /* We have changes */ - ++Changes; - - /* Search for: - * - * lda (sp),y - * jsr pusha - * - * And replace by - * - * jsr pushaysp - */ - } else if (LineFullMatch (L, "\tlda\t(sp),y") && - GetNextCodeLines (L, L2, 1) && - LineFullMatch (L2 [0], "\tjsr\tpusha")) { - - /* Found, replace it */ - L = ReplaceLine (L, "\tjsr\tpushaysp"); - FreeLine (L2 [0]); - - /* We have changes */ - ++Changes; - - /* Search for: - * - * ldx xx - * lda yy - * sta zzz - * stx zzz+1 - * - * and replace it by: - * - * lda xx - * sta zzz+1 - * lda yy - * sta zzz - * - * provided that that the X register is not used later. While this is - * no direct optimization, it helps with other optimizations. - */ - } else if (LineMatch (L, "\tldx\t") && - GetNextCodeLines (L, L2, 3) && - LineMatch (L2 [0], "\tlda\t") && - Is16BitStore (L2[1], L2[2]) && - !RegXUsed (L2[2])) { - - /* Found - replace it */ - L->Line[3] = 'a'; - NewLineAfter (L, "\tsta\t%s", L2[2]->Line+5); - FreeLine (L2[2]); - L = L2[1]; - - /* We have changes */ - ++Changes; - - /* Search for: - * - * ldx xx - * lda yy - * ldy #$zz - * jsr staxysp - * - * and replace it by: - * - * lda xx - * ldy #$zz+1 - * sta (sp),y - * dey - * lda yy - * sta (sp),y - * - * provided that that the X register is not used later. This code - * sequence is two bytes longer, but a lot faster and it does not - * use the X register, so other loads may get removed later. - */ - } else if (LineMatch (L, "\tldx\t") && - GetNextCodeLines (L, L2, 3) && - LineMatch (L2 [0], "\tlda\t") && - LineMatch (L2 [1], "\tldy\t#$") && - LineFullMatch (L2 [2], "\tjsr\tstaxysp") && - !RegXUsed (L2[2])) { - - /* Found - replace it */ - L->Line[3] = 'a'; - L = NewLineAfter (L, "\tldy\t#$%02X", GetHexNum (L2[1]->Line+7)+1); - L = NewLineAfter (L, "\tsta\t(sp),y"); - L = NewLineAfter (L, "\tdey"); - L = NewLineAfter (L2[0], "\tsta\t(sp),y"); - - /* Remove the remaining lines */ - FreeLines (L2[1], L2[2]); - - /* We have changes */ - ++Changes; - - /* Search for: - * - * ldx xx - * lda yy - * jsr stax0sp - * - * and replace it by: - * - * lda xx - * ldy #$01 - * sta (sp),y - * dey - * lda yy - * sta (sp),y - * - * provided that that the X register is not used later. This code - * sequence is four bytes longer, but a lot faster and it does not - * use the X register, so other loads may get removed later. - */ - } else if (LineMatch (L, "\tldx\t") && - GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tlda\t") && - LineFullMatch (L2 [1], "\tjsr\tstax0sp") && - !RegXUsed (L2[1])) { - - /* Found - replace it */ - L->Line[3] = 'a'; - L = NewLineAfter (L, "\tldy\t#$01"); - L = NewLineAfter (L, "\tsta\t(sp),y"); - L = NewLineAfter (L, "\tdey"); - L = NewLineAfter (L2[0], "\tsta\t(sp),y"); - - /* Remove the remaining line */ - FreeLine (L2[1]); - - /* We have changes */ - ++Changes; - - /* Search for - * - * adc xx - * bcc *+3 - * inx - * - * Remove the handling of the high byte if the X register - * is not used any more - */ - } else if (LineMatch (L, "\tadc\t") && - GetNextCodeLines (L, L2, 3) && - LineFullMatch (L2[0], "\tbcc\t*+3") && - LineFullMatch (L2[1], "\tinx") && - L2[1]->Next && - IsHint (L2[1]->Next, "x:!") && - !RegXUsed (L2[1])) { - - /* Delete the lines */ - FreeLines (L2[0], L2[1]->Next); - - /* We have changes */ - ++Changes; - - /* Search for - * - * sbc xx - * bcs *+3 - * dex - * - * Remove the handling of the high byte if the X register - * is not used any more - */ - } else if (LineMatch (L, "\tsbc\t") && - GetNextCodeLines (L, L2, 3) && - LineFullMatch (L2[0], "\tbcs\t*+3") && - LineFullMatch (L2[1], "\tdex") && - L2[1]->Next && - IsHint (L2[1]->Next, "x:!") && - !RegXUsed (L2[1])) { - - /* Delete the lines */ - FreeLines (L2[0], L2[1]->Next); - - /* We have changes */ - ++Changes; - - /* Search for - * - * lda xx - * bpl *+3 - * dex - * - * Remove the handling of the high byte if the X register - * is not used any more - */ - } else if (LineMatch (L, "\tlda\t") && - GetNextCodeLines (L, L2, 3) && - LineFullMatch (L2[0], "\tbpl\t*+3") && - LineFullMatch (L2[1], "\tdex") && - L2[1]->Next && - IsHint (L2[1]->Next, "x:!") && - !RegXUsed (L2[1])) { - - /* Delete the lines */ - FreeLines (L2[0], L2[1]->Next); - - /* We have changes */ - ++Changes; - - } - - /* All other patterns start with this one: */ - if (!LineFullMatch (L, "\tldx\t#$00")) { - /* Next line */ - goto NextLine; - } - - /* Search for: - * - * ldx #$00 - * jsr pushax - * - * and replace it by: - * - * jsr pusha0 - * - */ - if (GetNextCodeLines (L, L2, 1) && - LineFullMatch (L2 [0], "\tjsr\tpushax")) { - - /* Replace the subroutine call */ - L = ReplaceLine (L, "\tjsr\tpusha0"); - - /* Remove the unnecessary line */ - FreeLine (L2[0]); - - /* We have changes */ - ++Changes; - } - - /* Search for: - * - * ldx #$00 - * lda ... - * jsr pushax - * - * and replace it by: - * - * lda ... - * jsr pusha0 - * - */ - else if (GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tlda\t") && - LineFullMatch (L2 [1], "\tjsr\tpushax")) { - - /* Be sure, X is not used in the load */ - if (NoXAddrMode (L2 [0])) { - - /* Replace the subroutine call */ - L2 [1] = ReplaceLine (L2 [1], "\tjsr\tpusha0"); - - /* Remove the unnecessary load */ - FreeLine (L); - - /* L must be valid */ - L = L2 [0]; - - /* We have changes */ - ++Changes; - } - - } - - /* Search for: - * - * ldx #$00 - * lda ... - * cmp #$.. - * - * and replace it by: - * - * lda ... - * cmp #$.. - */ - else if (GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tlda\t") && - LineMatch (L2 [1], "\tcmp\t#$")) { - - /* Be sure, X is not used in the load */ - if (NoXAddrMode (L2 [0])) { - - /* Remove the unnecessary load */ - FreeLine (L); - - /* L must be valid */ - L = L2 [0]; - - /* We have changes */ - ++Changes; - } - } - - /* Search for: - * - * ldx #$00 - * lda ... - * jsr bnega - * - * and replace it by: - * - * lda ... - * jsr bnega - */ - else if (GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tlda\t") && - LineFullMatch (L2 [1], "\tjsr\tbnega")) { - - /* Be sure, X is not used in the load */ - if (NoXAddrMode (L2 [0])) { - - /* Remove the unnecessary load */ - FreeLine (L); - - /* L must be valid */ - L = L2 [0]; - - /* We have changes */ - ++Changes; - } - } - - NextLine: - /* Go to the next line */ - L = NextCodeLine (L); - } - - } while (Changes); -} - - - -static void OptRegLoads (void) -/* Remove unnecessary loads of registers */ -{ - unsigned Deletions; - Line* L; - Line* Lx; - - /* Repeat this until there is nothing more to delete */ - do { - Deletions = 0; - L = FirstCode; - while (L) { - - int Delete = 0; - - /* Search for a load of X and check if the value is used later */ - if (LineMatch (L, "\tldx\t") && - !RegXUsed (L) && - !IsCondJump (NextInstruction (L))) { - - /* Remember to delete this line */ - Delete = 1; - } - - /* Search for a load of A and check if the value is used later */ - else if (LineMatch (L, "\tlda\t") && - !RegAUsed (L) && - !IsCondJump (NextInstruction (L))) { - - /* Remember to delete this line */ - Delete = 1; - } - - /* Search for a load of Y and check if the value is used later */ - else if (LineMatch (L, "\tldy\t") && - !RegYUsed (L) && - !IsCondJump (NextInstruction (L))) { - - /* Remember to delete this line */ - Delete = 1; - } - - /* Go to the next line, delete the current if requested */ - Lx = L; - L = NextCodeLine (L); - if (Delete) { - FreeLine (Lx); - ++Deletions; - } - } - } while (Deletions > 0); -} - - - -static int OptPtrOps1 (Line** Start) -/* Optimize several pointer and array constructs - subfunction 1 */ -{ - Line* L2[15]; - Line** L3; - unsigned NeedLoad; - unsigned LinesToRemove; - unsigned Inc; - unsigned Done; - unsigned Offs; - - /* Use a local variable for the working line */ - Line* L = *Start; - - /* Search for (23B/XXT) - * - * lda _b+0 - * ldx _b+0+1 - * sta regsave - * stx regsave+1 - * jsr incax1 - * sta _b+0 - * stx _b+0+1 - * lda regsave - * ldx regsave+1 - * - * and replace it by something like (24B/26T) - * - * lda _b+0 - * sta regsave - * clc - * adc #$01 - * sta _b+0 - * lda _b+0+1 - * sta regsave+1 - * adc #$00 - * sta _b+0+1 - * tax - * lda regsave - */ - if (!LineMatch (L, "\tlda\t") || - !GetNextCodeLines (L, L2, 4) || - !IsLoadAX (L, L2 [0]) || - !LineFullMatch (L2[1], "\tsta\tregsave") || - !LineFullMatch (L2[2], "\tstx\tregsave+1")) { - - /* Not found */ - return 0; - } - - /* */ - if (LineMatch (L2[3], "\tjsr\tincax")) { - /* Get next code lines */ - if (GetNextCodeLines (L2[3], &L2[4], 4) == 0) { - /* Cannot get lines */ - return 0; - } - Inc = GetHexNum (L2[3]->Line+10); - L3 = &L2[4]; - LinesToRemove = 8; - } else { - /* Get next code lines */ - if (GetNextCodeLines (L2[3], &L2[4], 7) == 0) { - /* Cannot get lines */ - return 0; - } - if (LineFullMatch (L2[3], "\tclc") && - LineMatch (L2[4], "\tadc\t#$") && - LineFullMatch (L2[5], "\tbcc\t*+3") && - LineFullMatch (L2[6], "\tinx")) { - /* Inlined increment */ - Inc = GetHexNum (L2[4]->Line+7); - L3 = &L2[7]; - LinesToRemove = 11; - } else { - /* Not found */ - return 0; - } - } - - /* Check for the remainder */ - if (!LineMatch (L3[0], "\tsta\t") || - strcmp (L3[0]->Line+5, L->Line+5) != 0 || - !LineMatch (L3[1], "\tstx\t") || - strcmp (L3[1]->Line+5, L2[0]->Line+5) != 0 || - !LineFullMatch (L3[2], "\tlda\tregsave") || - !LineFullMatch (L3[3], "\tldx\tregsave+1")) { - - /* Not found */ - return 0; - } - - /* Check if AX is actually used following the code above. If not, - * we don't need to load A/X from regsave. Since X will never be - * used without A, check just for A. - */ - NeedLoad = RegAUsed (L3[3]); - - /* Special code for register variables */ - Done = 0; - if (LineMatch (L, "\tlda\tregbank+") && - GetNextCodeLines (L3[3], &L3[4], 1) && - Inc == 1) { - - /* Remember the offset into the register bank */ - char Reg[20]; - strcpy (Reg, L->Line+5); - - /* Check for several special sequences */ - if (LineFullMatch (L3[4], "\tjsr\tldaui")) { - /* Load char indirect */ - L = ReplaceLine (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(%s,x)", Reg); - L = NewLineAfter (L, "\tinc\t%s", Reg); - L = NewLineAfter (L, "\tbne\t*+4"); - L = NewLineAfter (L, "\tinc\t%s+1", Reg); - Done = 1; - ++LinesToRemove; - } else if (LineFullMatch (L3[4], "\tsta\tptr1") && - GetNextCodeLines (L3[4], &L3[5], 3) && - LineFullMatch (L3[5], "\tstx\tptr1+1") && - LineFullMatch (L3[6], "\tldx\t#$00") && - LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) { - - /* Load char indirect, inlined */ - L = ReplaceLine (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(%s,x)", Reg); - L = NewLineAfter (L, "\tinc\t%s", Reg); - L = NewLineAfter (L, "\tbne\t*+4"); - L = NewLineAfter (L, "\tinc\t%s+1", Reg); - Done = 1; - LinesToRemove += 4; - - } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) { - if (GetNextCodeLines (L3[4], &L3[5], 2) && - LineMatch (L3[5], "\tlda\t") && - LineFullMatch (L3[6], "\tjsr\tstaspp")) { - - /* Store to pointer */ - L = ReplaceLine (L, L3[5]->Line); - L = NewLineAfter (L, "\tldy\t#$00"); - L = NewLineAfter (L, "\tsta\t(%s),y", Reg); - L = NewLineAfter (L, "\tinc\t%s", Reg); - L = NewLineAfter (L, "\tbne\t*+4"); - L = NewLineAfter (L, "\tinc\t%s+1", Reg); - - Done = 1; - LinesToRemove += 3; - - } else if (GetNextCodeLines (L3[4], &L3[5], 3) && - LineMatch (L3[5], "\tldy\t#$") && - LineFullMatch (L3[6], "\tlda\t(sp),y") && - LineFullMatch (L3[7], "\tjsr\tstaspp")) { - - /* Beware: We have to correct the stack offset, since we will - * remove the pushax instruction! - */ - Offs = GetHexNum (L3[5]->Line+7) - 2; - - /* Store to pointer */ - L = ReplaceLine (L, "\tldy\t#$%02X", Offs); - L = NewLineAfter (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(sp),y"); - L = NewLineAfter (L, "\tsta\t(%s,x)", Reg); - L = NewLineAfter (L, "\tinc\t%s", Reg); - L = NewLineAfter (L, "\tbne\t*+4"); - L = NewLineAfter (L, "\tinc\t%s+1", Reg); - - Done = 1; - LinesToRemove += 4; - } - } - } - - if (Done == 0) { - - /* No register variable - insert the first part of the code */ - if (NeedLoad) { - L = NewLineAfter (L, "\tsta\tptr1"); - } - L = NewLineAfter (L, "\tclc"); - L = NewLineAfter (L, "\tadc\t#$%02X", Inc); - L = NewLineAfter (L, "\tsta\t%s", L3[0]->Line+5); - L = NewLineAfter (L, "\tlda\t%s", L3[1]->Line+5); - if (NeedLoad) { - L = NewLineAfter (L, "\tsta\tptr1+1"); - } - L = NewLineAfter (L, "\tadc\t#$00"); - L = NewLineAfter (L, "\tsta\t%s", L3[1]->Line+5); - - /* Check if we must really load the old value into a/x or if the - * code may be replaced by something else. - */ - if (GetNextCodeLines (L3[3], &L3[4], 1)) { - if (LineFullMatch (L3[4], "\tjsr\tldaui")) { - /* Load char indirect */ - L = NewLineAfter (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(ptr1,x)"); - NeedLoad = 0; - ++LinesToRemove; - } else if (LineFullMatch (L3[4], "\tsta\tptr1") && - GetNextCodeLines (L3[4], &L3[5], 3) && - LineFullMatch (L3[5], "\tstx\tptr1+1") && - LineFullMatch (L3[6], "\tldx\t#$00") && - LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) { - - /* Load char indirect, inlined */ - L = NewLineAfter (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(ptr1,x)"); - NeedLoad = 0; - LinesToRemove += 4; - - } else if (LineFullMatch (L3[4], "\tjsr\tldaxi")) { - /* Load word indirect */ - L = NewLineAfter (L, "\tldy\t#$01"); - L = NewLineAfter (L, "\tlda\t(ptr1),y"); - L = NewLineAfter (L, "\ttax"); - L = NewLineAfter (L, "\tdey"); - L = NewLineAfter (L, "\tlda\t(ptr1),y"); - NeedLoad = 0; - ++LinesToRemove; - - } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) { - if (GetNextCodeLines (L3[4], &L3[5], 2) && - LineMatch (L3[5], "\tlda\t") && - LineFullMatch (L3[6], "\tjsr\tstaspp")) { - - /* Store to pointer */ - L = NewLineAfter (L, L3[5]->Line); - L = NewLineAfter (L, "\tldy\t#$00"); - L = NewLineAfter (L, "\tsta\t(ptr1),y"); - - NeedLoad = 0; - LinesToRemove += 3; - } else if (GetNextCodeLines (L3[4], &L3[5], 3) && - LineMatch (L3[5], "\tldy\t#$") && - LineFullMatch (L3[6], "\tlda\t(sp),y") && - LineFullMatch (L3[7], "\tjsr\tstaspp")) { - - /* Beware: We have to correct the stack offset, since we will - * remove the pushax instruction! - */ - sprintf (L3[5]->Line+7, "%02X", GetHexNum (L3[5]->Line+7)-2); - - /* Store to pointer */ - L = NewLineAfter (L, L3[5]->Line); - L = NewLineAfter (L, L3[6]->Line); - L = NewLineAfter (L, "\tldy\t#$00"); - L = NewLineAfter (L, "\tsta\t(ptr1),y"); - - NeedLoad = 0; - LinesToRemove += 4; - } - - } - } - - /* If we need to load a/x, add the code */ - if (NeedLoad) { - L = NewLineAfter (L, "\tlda\tptr1"); - L = NewLineAfter (L, "\tldx\tptr1+1"); - } - } - - /* Remove the code that is no longer needed */ - FreeLines (L2[0], L2[LinesToRemove-1]); - - /* Return the new line and success */ - *Start = NextCodeLine (L); - return 1; -} - - - -static int OptPtrOps2 (Line** Start) -/* Optimize several pointer and array constructs - subfunction 2 */ -{ - Line* L2[25]; - Line** L3; - unsigned NeedLoad; - unsigned LinesToRemove; - unsigned Inc; - unsigned Offs; - - - /* Use a local variable for the working line */ - Line* L = *Start; - - /* Same as subfunction 1 but for local variables. */ - if (LineMatch (L, "\tldy\t#$") == 0) { - return 0; - } - - /* Get the stack offset. The offset points to the high byte, correct that. */ - Offs = GetHexNum (L->Line+7) - 1; - - /* Check for the actual sequences */ - if (GetNextCodeLines (L, L2, 7) && - LineFullMatch (L2[0], "\tjsr\tldaxysp") && - LineFullMatch (L2[1], "\tsta\tregsave") && - LineFullMatch (L2[2], "\tstx\tregsave+1") && - LineMatch (L2[3], "\tjsr\tincax")) { - - /* Non inlined version */ - Inc = GetHexNum (L2[3]->Line+10); - - /* Check for stack offset zero */ - if (LineFullMatch (L2[4], "\tjsr\tstax0sp") && - LineFullMatch (L2[5], "\tlda\tregsave") && - LineFullMatch (L2[6], "\tldx\tregsave+1")) { - - LinesToRemove = 7; - - } else if (GetNextCodeLines (L2[6], &L2[7], 1) && - LineMatch (L2[4], "\tldy\t#$") && - GetHexNum (L2[4]->Line+7) == Offs && - LineFullMatch (L2[5], "\tjsr\tstaxysp") && - LineFullMatch (L2[6], "\tlda\tregsave") && - LineFullMatch (L2[7], "\tldx\tregsave+1")) { - - LinesToRemove = 8; - - } else { - /* Not found */ - return 0; - } - - } else if (GetNextCodeLines (L, L2, 13) && - LineFullMatch (L2[0], "\tlda\t(sp),y") && - LineFullMatch (L2[1], "\ttax") && - LineFullMatch (L2[2], "\tdey") && - LineFullMatch (L2[3], "\tlda\t(sp),y") && - LineFullMatch (L2[4], "\tsta\tregsave") && - LineFullMatch (L2[5], "\tstx\tregsave+1") && - LineFullMatch (L2[6], "\tclc") && - LineMatch (L2[7], "\tadc\t#$") && - LineFullMatch (L2[8], "\tbcc\t*+3") && - LineFullMatch (L2[9], "\tinx")) { - - /* Inlined version */ - Inc = GetHexNum (L2[7]->Line+7); - - /* Check for stack offset zero */ - if (LineFullMatch (L2[10], "\tjsr\tstax0sp") && - LineFullMatch (L2[11], "\tlda\tregsave") && - LineFullMatch (L2[12], "\tldx\tregsave+1")) { - - LinesToRemove = 13; - - } else if (GetNextCodeLines (L2[12], &L2[13], 1) && - LineMatch (L2[10], "\tldy\t#$") && - GetHexNum (L2[10]->Line+7) == Offs && - LineFullMatch (L2[11], "\tjsr\tstaxysp") && - LineFullMatch (L2[12], "\tlda\tregsave") && - LineFullMatch (L2[13], "\tldx\tregsave+1")) { - - LinesToRemove = 14; - - } else { - /* Not found */ - return 0; - } - } else { - /* Not found */ - return 0; - } - - /* Get a pointer to the last line of the preceding sequence */ - L3 = &L2[LinesToRemove-1]; - - /* Check if AX is actually used following the code above. If not, - * we don't need to load A/X from regsave. Since X will never by - * used without A, check just for A. - */ - NeedLoad = RegAUsed (L3[0]); - - /* Replace the ldy instruction, offset must point to the low byte */ - sprintf (L->Line+7, "%02X", Offs); - - /* Insert the first part of the code */ - L = NewLineAfter (L, "\tlda\t(sp),y"); - if (NeedLoad) { - L = NewLineAfter (L, "\tsta\tptr1"); - } - L = NewLineAfter (L, "\tclc"); - L = NewLineAfter (L, "\tadc\t#$%02X", Inc); - L = NewLineAfter (L, "\tsta\t(sp),y"); - L = NewLineAfter (L, "\tiny"); - L = NewLineAfter (L, "\tlda\t(sp),y"); - if (NeedLoad) { - L = NewLineAfter (L, "\tsta\tptr1+1"); - } - L = NewLineAfter (L, "\tadc\t#$00"); - L = NewLineAfter (L, "\tsta\t(sp),y"); - - /* Check if we must really load the old value into a/x or if the - * code may be replaced by something else. - */ - if (GetNextCodeLines (L3[0], &L3[1], 1)) { - if (LineFullMatch (L3[1], "\tjsr\tldaui")) { - /* Load char indirect */ - L = NewLineAfter (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(ptr1,x)"); - NeedLoad = 0; - ++LinesToRemove; - } else if (LineFullMatch (L3[1], "\tsta\tptr1") && - GetNextCodeLines (L3[1], &L3[2], 3) && - LineFullMatch (L3[2], "\tstx\tptr1+1") && - LineFullMatch (L3[3], "\tldx\t#$00") && - LineFullMatch (L3[4], "\tlda\t(ptr1,x)")) { - - /* Load char indirect, inlined */ - L = NewLineAfter (L, "\tldx\t#$00"); - L = NewLineAfter (L, "\tlda\t(ptr1,x)"); - NeedLoad = 0; - LinesToRemove += 4; - - } else if (LineFullMatch (L3[1], "\tjsr\tldaxi")) { - /* Load word indirect */ - L = NewLineAfter (L, "\tldy\t#$01"); - L = NewLineAfter (L, "\tlda\t(ptr1),y"); - L = NewLineAfter (L, "\ttax"); - L = NewLineAfter (L, "\tdey"); - L = NewLineAfter (L, "\tlda\t(ptr1),y"); - NeedLoad = 0; - ++LinesToRemove; - - } else if (LineFullMatch (L3[1], "\tjsr\tpushax")) { - if (GetNextCodeLines (L3[1], &L3[2], 2) && - LineMatch (L3[2], "\tlda\t") && - LineFullMatch (L3[3], "\tjsr\tstaspp")) { - - /* Store to pointer */ - L = NewLineAfter (L, L3[2]->Line); - L = NewLineAfter (L, "\tldy\t#$00"); - L = NewLineAfter (L, "\tsta\t(ptr1),y"); - - NeedLoad = 0; - LinesToRemove += 3; - } else if (GetNextCodeLines (L3[1], &L3[2], 3) && - LineMatch (L3[2], "\tldy\t#$") && - LineFullMatch (L3[3], "\tlda\t(sp),y") && - LineFullMatch (L3[4], "\tjsr\tstaspp")) { - - /* Beware: We have to correct the stack offset, since we will - * remove the pushax instruction! - */ - sprintf (L3[2]->Line+7, "%02X", GetHexNum (L3[2]->Line+7)-2); - - /* Store to pointer */ - L = NewLineAfter (L, L3[2]->Line); - L = NewLineAfter (L, L3[3]->Line); - L = NewLineAfter (L, "\tldy\t#$00"); - L = NewLineAfter (L, "\tsta\t(ptr1),y"); - - NeedLoad = 0; - LinesToRemove += 4; - } - } - - } - - /* If we need to load a/x, add the code */ - if (NeedLoad) { - L = NewLineAfter (L, "\tlda\tptr1"); - L = NewLineAfter (L, "\tldx\tptr1+1"); - } - - /* Remove the code that is no longer needed */ - FreeLines (L2[0], L2[LinesToRemove-1]); - - /* Return the new line and success */ - *Start = NextCodeLine (L); - return 1; -} - - - -static void OptPtrOps (void) -/* Optimize several pointer and array constructs */ -{ - Line* L2 [10]; - - Line* L = FirstCode; - while (L) { - - if (OptPtrOps1 (&L)) { - continue; - } else if (OptPtrOps2 (&L)) { - continue; - } - - /* Search for the following sequence: - * - * lda regsave - * ldx regsave+1 - * jsr pushax - * lda #$.. - * jsr staspp - * - * and replace it by: - * - * lda #$.. - * ldy #$00 - * sta (regsave),y - * - */ - else if (LineFullMatch (L, "\tlda\tregsave") && /* Match on start */ - GetNextCodeLines (L, L2, 4) && /* Fetch next lines */ - LineFullMatch (L2 [0], "\tldx\tregsave+1") && /* Match line 2 ... */ - LineFullMatch (L2 [1], "\tjsr\tpushax") && - LineMatch (L2 [2], "\tlda\t#$") && - LineFullMatch (L2 [3], "\tjsr\tstaspp")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, L2 [2]->Line); /* lda #$.. */ - L2 [0] = ReplaceLine (L2 [0], "\tldy\t#$00"); - L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y"); - - /* Free the remaining lines */ - FreeLines (L2 [2], L2 [3]); - } - - /* Search for the following sequence: - * - * lda regsave - * ldx regsave+1 - * jsr ldaui - * - * and replace it by: - * - * ldx #$00 - * lda (regsave,x) - * - */ - else if (LineFullMatch (L, "\tlda\tregsave") && /* Match on start */ - GetNextCodeLines (L, L2, 2) && /* Fetch next lines */ - LineFullMatch (L2 [0], "\tldx\tregsave+1") && /* Match line 2 ... */ - LineFullMatch (L2 [1], "\tjsr\tldaui")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tldx\t#$00"); - L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)"); - - /* Free the remaining lines */ - FreeLine (L2 [1]); - } - - /* - * Search for the following sequence: - * - * lda regsave - * ldx regsave+1 - * jsr pushax - * ldx #$high - * lda #$low - * jsr staxspp - * - * and replace it by: - * - * ldy #$01 - * lda #$high - * sta (regsave),y - * tax - * dey - * lda #$low - * sta (regsave),y - * - */ - else if (LineFullMatch (L, "\tlda\tregsave") && - GetNextCodeLines (L, L2, 5) && - LineFullMatch (L2 [0], "\tldx\tregsave+1") && - LineFullMatch (L2 [1], "\tjsr\tpushax") && - LineMatch (L2 [2], "\tldx\t#$") && - LineMatch (L2 [3], "\tlda\t#$") && - LineFullMatch (L2 [4], "\tjsr\tstaxspp")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tldy\t#$01"); - L2 [0] = ReplaceLine (L2 [0], L2 [2]->Line); - L2 [0]->Line [3] = 'a'; - L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y"); - L2 [4] = ReplaceLine (L2 [4], L2 [3]->Line); - L2 [2] = ReplaceLine (L2 [2], "\ttax"); - L2 [3] = ReplaceLine (L2 [3], "\tdey"); - L = NewLineAfter (L2 [4], "\tsta\t(regsave),y"); - } - - /* - * Search for the following sequence: - * - * lda regsave - * ldx regsave+1 - * sta ptr1 - * stx ptr1+1 - * ldx #$00 - * lda (ptr1,x) - * - * and replace it by: - * - * ldx #$00 - * lda (regsave,x) - * - */ - else if (LineFullMatch (L, "\tlda\tregsave") && - GetNextCodeLines (L, L2, 5) && - LineFullMatch (L2 [0], "\tldx\tregsave+1") && - LineFullMatch (L2 [1], "\tsta\tptr1") && - LineFullMatch (L2 [2], "\tstx\tptr1+1") && - LineFullMatch (L2 [3], "\tldx\t#$00") && - LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tldx\t#$00"); - L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)"); - - /* Remove the remaining lines */ - FreeLines (L2 [1], L2 [4]); - } - - /* Search for the following sequence: - * - * jsr pushax - * lda ... - * jsr staspp - * - * and replace it by: - * - * sta ptr1 - * stx ptr1+1 - * lda ... - * ldy #$00 - * sta (ptr1),y - * - */ - else if (LineFullMatch (L, "\tjsr\tpushax") && - GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tlda\t") && - LineFullMatch (L2 [1], "\tjsr\tstaspp")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tsta\tptr1"); - L2 [1] = ReplaceLine (L2 [1], L2 [0]->Line); /* lda ... */ - L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1"); - L2 [2] = NewLineAfter (L2 [1], "\tldy\t#$00"); - L = NewLineAfter (L2 [2], "\tsta\t(ptr1),y"); - } - - /* Search for the following sequence: - * - * jsr pushax - * lda ... - * ldy #$nn - * jsr staspidx - * - * and replace it by: - * - * sta ptr1 - * stx ptr1+1 - * lda ... - * ldy #$nn - * sta (ptr1),y - * - */ - else if (LineFullMatch (L, "\tjsr\tpushax") && - GetNextCodeLines (L, L2, 3) && - LineMatch (L2 [0], "\tlda\t") && - LineMatch (L2 [1], "\tldy\t#$") && - LineFullMatch (L2 [2], "\tjsr\tstaspidx")) { - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tsta\tptr1"); - L = NewLineAfter (L, "\tstx\tptr1+1"); - L2 [2] = ReplaceLine (L2 [2], "\tsta\t(ptr1),y"); - } - - /* Search for the following sequence: - * - * jsr pushax - * ldy #$.. - * lda (sp),y - * jsr staspp - * - * and replace it by: - * - * sta ptr1 - * stx ptr1+1 - * ldy #$.. - * lda (sp),y - * ldy #$00 - * sta (ptr1),y - * - * Beware: Since we remove a call to a function that changes the stack - * pointer, we have to adjust the stack address for the lda. - * - */ - else if (LineFullMatch (L, "\tjsr\tpushax") && - GetNextCodeLines (L, L2, 3) && - LineMatch (L2 [0], "\tldy\t#$") && - LineFullMatch (L2 [1], "\tlda\t(sp),y") && - LineFullMatch (L2 [2], "\tjsr\tstaspp")) { - - /* Found the sequence, replace it. First create a new load - * instruction for the changed stack offset. - */ - char Buf [30]; - sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2); - L = ReplaceLine (L, "\tsta\tptr1"); - L2 [1] = ReplaceLine (L2 [1], Buf); /* ldy ... */ - L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1"); - L2 [2] = ReplaceLine (L2 [2], "\tlda\t(sp),y"); - L2 [3] = NewLineAfter (L2 [2], "\tldy\t#$00"); - L = NewLineAfter (L2 [3], "\tsta\t(ptr1),y"); - } - - /* Search for the following sequence: - * - * jsr pushax - * ldy #$nn - * lda (sp),y - * ldy #$mm - * jsr staspidx - * - * and replace it by: - * - * sta ptr1 - * stx ptr1+1 - * ldy #$nn - * lda (sp),y - * ldy #$mm - * sta (ptr1),y - * - * Beware: Since we remove a call to a function that changes the stack - * pointer, we have to adjust the stack address for the lda. - * - */ - else if (LineFullMatch (L, "\tjsr\tpushax") && - GetNextCodeLines (L, L2, 4) && - LineMatch (L2 [0], "\tldy\t#$") && - LineFullMatch (L2 [1], "\tlda\t(sp),y") && - LineMatch (L2 [2], "\tldy\t#$") && - LineFullMatch (L2 [3], "\tjsr\tstaspidx")) { - - /* Found the sequence, replace it. First create a new load - * instruction for the changed stack offset. - */ - char Buf [30]; - sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2); - L = ReplaceLine (L, "\tsta\tptr1"); - L = NewLineAfter (L, "\tstx\tptr1+1"); - L2 [0] = ReplaceLine (L2 [0], Buf); /* ldy ... */ - L2 [3] = ReplaceLine (L2 [3], "\tsta\t(ptr1),y"); - } - - /* Search for the following sequence: - * - * ldax _label+0 - * ldy #$.. - * clc - * adc (sp),y - * bcc *+3 - * inx - * sta ptr1 - * stx ptr1+1 - * ldx #$00 - * lda (ptr1,x) - * - * and replace it by: - * - * ldy #$.. - * lda (sp),y - * tay - * ldx #$00 - * lda _label+0,y - * - * The load of X may be omitted if X is not used below. - */ - else if (LineMatch (L, "\tldax\t_") && - GetNextCodeLines (L, L2, 9) && - LineMatch (L2 [0], "\tldy\t#$") && - LineFullMatch (L2 [1], "\tclc") && - LineFullMatch (L2 [2], "\tadc\t(sp),y") && - LineFullMatch (L2 [3], "\tbcc\t*+3") && - LineFullMatch (L2 [4], "\tinx") && - LineFullMatch (L2 [5], "\tsta\tptr1") && - LineFullMatch (L2 [6], "\tstx\tptr1+1") && - LineFullMatch (L2 [7], "\tldx\t#$00") && - LineFullMatch (L2 [8], "\tlda\t(ptr1,x)")) { - - /* Found the sequence, replace it */ - char Label [256]; - strcpy (Label, L->Line + 6); /* Remember the label */ - L = ReplaceLine (L, L2 [0]->Line); /* ldy .. */ - L = NewLineAfter (L, "\tlda\t(sp),y"); - L = NewLineAfter (L, "\ttay"); - if (RegXUsed (L2[8])) { - L = NewLineAfter (L, "\tldx\t#$00"); - } - L = NewLineAfter (L, "\tlda\t%s,y", Label); - - /* Remove the remaining stuff. There may be hints between the - * instructions, remove them too - */ - FreeLines (L2[0], L2 [8]); - - } - - /* Check for - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * ldy #$yy - * jsr ldauidx - * - * and replace it by - * - * ldy #$xx - * ldx #$yy - * jsr ldauiysp - * - * or even - * - * jsr ldaui0sp - * - * This change will cost 2 cycles, but it saves a lot of code (6 bytes - * per occurrence), so we will accept the overhead. It may even be - * possible to rewrite the library routine to get rid of the additional - * overhead. - */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 6) && - LineFullMatch (L2 [0], "\tlda\t(sp),y") && - LineFullMatch (L2 [1], "\ttax") && - LineFullMatch (L2 [2], "\tdey") && - LineFullMatch (L2 [3], "\tlda\t(sp),y") && - LineMatch (L2 [4], "\tldy\t#$") && - LineFullMatch (L2 [5], "\tjsr\tldauidx")) { - - /* Found - replace it */ - L2 [4]->Line [3] = 'x'; /* Change to ldx */ - if (LineFullMatch (L, "\tldy\t#$01")) { - /* Word at offset zero */ - FreeLine (L); - L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp"); - } else { - ReplaceLine (L2 [5], "\tjsr\tldauiysp"); - } - - /* Delete the remaining lines */ - FreeLines (L2 [0], L2 [3]); - } - - /* Check for - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * sta ptr1 - * stx ptr1+1 - * ldx #$00 - * lda (ptr1,x) - * - * and replace it by - * - * ldy #$xx - * jsr ldau0ysp - * - * or even - * - * jsr ldau00sp - * - * This change will has an overhead of 10 cycles, but it saves 11(!) - * bytes per invocation. Maybe we should apply only if FavourSize is - * true? - */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 8) && - LineFullMatch (L2 [0], "\tlda\t(sp),y") && - LineFullMatch (L2 [1], "\ttax") && - LineFullMatch (L2 [2], "\tdey") && - LineFullMatch (L2 [3], "\tlda\t(sp),y") && - LineFullMatch (L2 [4], "\tsta\tptr1") && - LineFullMatch (L2 [5], "\tstx\tptr1+1") && - LineFullMatch (L2 [6], "\tldx\t#$00") && - LineFullMatch (L2 [7], "\tlda\t(ptr1,x)")) { - - /* Found - replace it */ - if (LineFullMatch (L, "\tldy\t#$01")) { - /* Word at offset zero */ - FreeLine (L); - L = ReplaceLine (L2 [0], "\tjsr\tldau00sp"); - } else { - ReplaceLine (L2 [0], "\tjsr\tldau0ysp"); - } - - /* Delete the remaining lines */ - FreeLines (L2 [1], L2 [7]); - } - - /* Check for - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * sta yyy - * stx yyy+1 - * - * and replace it by - * - * ldy #$xx - * lda (sp),y - * sta yyy+1 - * dey - * lda (sp),y - * sta yyy - * - * Provided that X is not used later. - */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 6) && - LineFullMatch (L2 [0], "\tlda\t(sp),y") && - LineFullMatch (L2 [1], "\ttax") && - LineFullMatch (L2 [2], "\tdey") && - LineFullMatch (L2 [3], "\tlda\t(sp),y") && - Is16BitStore (L2[4], L2[5]) && - !RegXUsed (L2[5])) { - - /* Found - replace it */ - L2[1] = ReplaceLine (L2[1], L2[5]->Line); - L2[1]->Line[3] = 'a'; - - /* Delete the remaining lines */ - FreeLine (L2[5]); - - /* Start over at last line */ - L = L2[4]; - } - - /* Next Line */ - L = NextCodeLine (L); - } -} - - - -static void OptRegVars (void) -/* Optimize register variable uses */ -{ - Line* L2 [10]; - - Line* L = FirstCode; - while (L) { - - /* Search for the following sequence: - * - * lda regbank+n - * ldx regbank+n+1 - * jsr ldaui - * - * and replace it by: - * - * ldx #$00 - * lda (regbank+n,x) - * - */ - if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */ - GetNextCodeLines (L, L2, 2) && /* Fetch next lines */ - LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */ - LineFullMatch (L2 [1], "\tjsr\tldaui") && - L->Line [13] == L2 [0]->Line [13] && /* Offset equal */ - strcmp (L2 [0]->Line + 14, "+1") == 0) { - - char Buf [100]; - sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5); - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tldx\t#$00"); - L2 [0] = ReplaceLine (L2 [0], Buf); - - /* Free the remaining lines */ - FreeLine (L2 [1]); - } - - /* Search for the following sequence: - * - * lda regbank+n - * ldx regbank+n+1 - * sta ptr1 - * stx ptr1+1 - * ldx #$00 - * lda (ptr1,x) - * - * and replace it by: - * - * ldx #$00 - * lda (regbank+n,x) - * - */ - else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */ - GetNextCodeLines (L, L2, 5) && /* Fetch next lines */ - LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */ - L->Line [13] == L2 [0]->Line [13] && /* Offset equal */ - strcmp (L2 [0]->Line + 14, "+1") == 0 && - LineFullMatch (L2 [1], "\tsta\tptr1") && - LineFullMatch (L2 [2], "\tstx\tptr1+1") && - LineFullMatch (L2 [3], "\tldx\t#$00") && - LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) { - - char Buf [100]; - sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5); - - /* Found the sequence, replace it */ - L = ReplaceLine (L, "\tldx\t#$00"); - L2 [0] = ReplaceLine (L2 [0], Buf); - - /* Free the remaining lines */ - FreeLines (L2 [1], L2 [4]); - } - - /* Search for the following sequence: - * - * lda regbank+n - * ldx regbank+n+1 - * ldy #$.. - * jsr ldauidx - * - * and replace it by: - * - * ldy #$.. - * ldx #$00 - * lda (regbank+n),y - * - */ - else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */ - GetNextCodeLines (L, L2, 3) && /* Fetch next lines */ - LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */ - L->Line [13] == L2 [0]->Line [13] && /* Offset equal */ - strcmp (L2 [0]->Line + 14, "+1") == 0 && - LineMatch (L2 [1], "\tldy\t#$") && - LineFullMatch (L2 [2], "\tjsr\tldauidx")) { - - char Buf [100]; - sprintf (Buf, "\tlda\t(%s),y", L->Line + 5); - - /* Found the sequence, replace it */ - L = ReplaceLine (L, L2 [1]->Line); - L2 [0] = ReplaceLine (L2 [0], "\tldx\t#$00"); - L2 [1] = ReplaceLine (L2 [1], Buf); - - /* Free the remaining lines */ - FreeLine (L2 [2]); - } - - /* Search for the following sequence: - * - * lda regbank+n - * ldx regbank+n+1 - * sta ptr1 - * stx ptr1+1 - * lda ... - * ldy #$mm - * sta (ptr1),y - * - * and replace it by: - * - * lda ... - * ldy #$mm - * sta (regbank+n),y - * - * The source form is not generated by the parser but by the optimizer. - */ - else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */ - GetNextCodeLines (L, L2, 6) && /* Fetch next lines */ - LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */ - L->Line [13] == L2 [0]->Line [13] && /* Offset equal */ - strcmp (L2 [0]->Line + 14, "+1") == 0 && - LineFullMatch (L2 [1], "\tsta\tptr1") && - LineFullMatch (L2 [2], "\tstx\tptr1+1") && - LineMatch (L2 [3], "\tlda\t") && - LineMatch (L2 [4], "\tldy\t#$") && - LineMatch (L2 [5], "\tsta\t(ptr1),y")) { - - char Buf [100]; - sprintf (Buf, "\tsta\t(%s),y", L->Line + 5); - - /* Found the sequence, replace it */ - L2 [5] = ReplaceLine (L2 [5], Buf); - - /* Free the remaining lines */ - FreeLines (L, L2 [2]); - - /* Make the line pointer valid again */ - L = L2 [5]; - } - - /* Search for the following sequence: - * - * lda regbank+n - * ldx regbank+n+1 - * sta ptr1 - * stx ptr1+1 - * ldy #$mm - * lda (sp),y - * ldy #$ll - * sta (ptr1),y - * - * and replace it by: - * - * ldy #$mm - * lda (sp),y - * ldy #$ll - * sta (regbank+n),y - * - * The source form is not generated by the parser but by the optimizer. - */ - else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */ - GetNextCodeLines (L, L2, 7) && /* Fetch next lines */ - LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */ - L->Line [13] == L2 [0]->Line [13] && /* Offset equal */ - strcmp (L2 [0]->Line + 14, "+1") == 0 && - LineFullMatch (L2 [1], "\tsta\tptr1") && - LineFullMatch (L2 [2], "\tstx\tptr1+1") && - LineMatch (L2 [3], "\tldy\t#$") && - LineFullMatch (L2 [4], "\tlda\t(sp),y") && - LineMatch (L2 [5], "\tldy\t#$") && - LineMatch (L2 [6], "\tsta\t(ptr1),y")) { - - char Buf [100]; - sprintf (Buf, "\tsta\t(%s),y", L->Line + 5); - - /* Found the sequence, replace it */ - L2 [6] = ReplaceLine (L2 [6], Buf); - - /* Free the remaining lines */ - FreeLines (L, L2 [2]); - - /* Make the line pointer valid again */ - L = L2 [6]; - } - - /* Next Line */ - L = NextCodeLine (L); - } -} - - - -static void OptDoubleJumps (void) -/* Remove/rearrange jumps that jump to other jumps */ -{ - static const char* Jumps [] = { - "\tjeq\tL", - "\tjne\tL", - "\tbeq\tL", - "\tbne\tL", - "\tjmp\tL", - 0 - }; - - unsigned D; - - Line* L = FirstCode; - while (L) { - - int I; - - /* Is this a jump? */ - while ((I = LineMatchX (L, Jumps)) >= 0) { - - /* Yes. Get the target label */ - Line* Target = GetTargetLine (L->Line + 5); - - /* Target points to the label itself. Skip lines until we reach - * one that is not a label. - */ - Target = NextInstruction (Target); - - /* Be sure, this line is not the same as the one the jump is - * in (this happens if there is an empty loop). - */ - if (Target == L) { - break; - } - D = 0; - if (LineMatch (Target, "\tjmp\t")) { - - /* The target is itself a jump. If this is a short branch, get - * the final target and check if it is in reach. Bail out if - * not. - */ - if (L->Line[1] == 'b') { - Line* FinalTarget = GetTargetLine (Target->Line+5); - FinalTarget = NextInstruction (FinalTarget); - if ((D = GetJumpDistance (L, FinalTarget)) >= 123) { - break; - } - } - - /* Make sure the jump does indeed point to another label. - * It may happen that this is not the case for some endless - * loop (while(1) and similar). - */ - if (strcmp (L->Line+5, Target->Line+5) == 0) { - /* Same label, bail out */ - break; - } - - /* Use the label in the original jump instead */ - L = ReplaceLine (L, "%.5s%s", L->Line, Target->Line+5); - - } else if (I < 2 && LineMatch (Target, Jumps [I])) { - - /* Conditional jump. Use final label */ - strcpy (L->Line+5, Target->Line+5); - - } else { - break; - } - } - - /* Next line */ - L = NextCodeLine (L); - } -} - - - -static void OptJumpRTS (void) -/* Replace jumps to an RTS by an RTS */ -{ - Line* L = FirstCode; - while (L) { - /* Is this a jump to a numbered label? */ - if (LineMatch (L, "\tjmp\t") && L->Line [5] == 'L' && IsDigit (L->Line [6])) { - - /* Yes. Get the target label */ - Line* Target = GetTargetLine (L->Line+5); - - /* Target points to the label itself. Get the next line */ - Target = NextCodeLine (Target); - if (LineFullMatch (Target, "\trts")) { - /* Replace the jump by an RTS */ - L = ReplaceLine (L, "\trts"); - } - } - L = NextCodeLine (L); - } -} - - - -static void OptBoolTransforms (void) -/* Try to remove the boolean transformation subroutines where they aren't - * necessary. - */ -{ - Line* L2 [2]; - unsigned Label; - const char* BranchTarget; - - Line* L = FirstCode; - while (L) { - - /* Search for a boolean transformer followed by a conditional jump. */ - if (LineMatch (L, "\tjsr\tbool") && - GetNextCodeLines (L, L2, 1) && - IsCondJump (L2 [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. - */ - - /* Get the condition code */ - int Cond = FindCond (L->Line + 9); - if (Cond < 0) { - /* OOPS! */ - goto NextLine; - } - - /* Invert the code if we jump on condition not met. */ - if (L2[0]->Line [2] == 'e' && L2[0]->Line [3] == 'q') { - /* Jumps if condition false, invert condition */ - Cond = CmpInvertTab [Cond]; - } - - /* For easier reading, get a pointer to the jump target */ - BranchTarget = L2[0]->Line+5; - - /* Check if we can replace the jump (sometimes we would need two - * conditional jumps, we will not handle that for now since it - * has some complications - both jumps may be far jumps for - * example making the jumps more costly than the bool transformer - * subroutine). If we cannot replace the jump, bail out. - */ - switch (Cond) { - - case CMP_EQ: - L = ReplaceLine (L, "\tjeq\t%s", BranchTarget); - break; - - case CMP_NE: - L = ReplaceLine (L, "\tjne\t%s", BranchTarget); - break; - - case CMP_GT: - Label = AllocLabel (); - L = ReplaceLine (L, "\tbeq\tL%04X", Label); - L = NewLineAfter (L, "\tjpl\t%s", BranchTarget); - L = NewLabelAfter(L, Label); - break; - - case CMP_GE: - L = ReplaceLine (L, "\tjpl\t%s", BranchTarget); - break; - - case CMP_LT: - L = ReplaceLine (L, "\tjmi\t%s", BranchTarget); - break; - - case CMP_LE: - L = ReplaceLine (L, "\tjeq\t%s", BranchTarget); - L = NewLineAfter (L, "\tjmi\t%s", BranchTarget); - break; - - case CMP_UGT: - Label = AllocLabel (); - L = ReplaceLine (L, "\tbeq\tL%04X", Label); - L = NewLineAfter (L, "\tjcs\t%s", BranchTarget); - L = NewLabelAfter(L, Label); - break; - - case CMP_UGE: - L = ReplaceLine (L, "\tjcs\t%s", BranchTarget); - break; - - case CMP_ULT: - L = ReplaceLine (L, "\tjcc\t%s", BranchTarget); - break; - - case CMP_ULE: - L = ReplaceLine (L, "\tjeq\t%s", BranchTarget); - L = NewLineAfter (L, "\tjcc\t%s", BranchTarget); - break; - - default: - Internal ("Unknown jump condition: %u", Cond); - - } - - /* Remove the old stuff */ - FreeLine (L2[0]); - - } - -NextLine: - L = NextCodeLine (L); - } -} - - - -static void OptCompares2 (void) -/* Try to optimize the integer compare subroutines. */ -{ - Line* L2[10]; - unsigned Label; - const char* BranchTarget; - int C; - - Line* L = FirstCode; - while (L) { - - /* Search for - * - * lda x - * ldx x+1 - * cpx #$00 - * bne *+4 - * cmp #$00 - * jne/jeq ... - * - * and replace it by - * - * lda x - * ora x+1 - * jne/jeq ... - */ - if (LineMatch (L, "\tlda\t") && - GetNextCodeLines (L, L2, 5) && - IsLoadAX (L, L2[0]) && - LineFullMatch (L2[1], "\tcpx\t#$00") && - LineFullMatch (L2[2], "\tbne\t*+4") && - LineFullMatch (L2[3], "\tcmp\t#$00") && - IsCondJump (L2[4])) { - - /* Replace the load of X by an ora */ - L2[0]->Line[1] = 'o'; - L2[0]->Line[2] = 'r'; - L2[0]->Line[3] = 'a'; - - /* Remove unneeded stuff */ - FreeLines (L2[1], L2[3]); - - } - - /* Same for local variables: Replace - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * cpx #$00 - * bne *+4 cmp #$00 - * cmp #$00 - * jne/jeq ... - * - * by - * - * ldy #$xx - * lda (sp),y - * dey - * ora (sp),y - * jne/jeq ... - */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 8) && - LineFullMatch (L2[0], "\tlda\t(sp),y") && - LineFullMatch (L2[1], "\ttax") && - LineFullMatch (L2[2], "\tdey") && - LineFullMatch (L2[3], "\tlda\t(sp),y") && - LineFullMatch (L2[4], "\tcpx\t#$00") && - LineFullMatch (L2[5], "\tbne\t*+4") && - LineFullMatch (L2[6], "\tcmp\t#$00") && - IsCondJump (L2[7])) { - - /* Replace the second load by an ora */ - L2[3]->Line[1] = 'o'; - L2[3]->Line[2] = 'r'; - L2[3]->Line[3] = 'a'; - - /* Remove unneeded stuff */ - FreeLine (L2[1]); - FreeLines (L2[4], L2[6]); - - } - - /* Search for the call to a compare subroutine followed by a - * conditional jump. - */ - else if (LineMatch (L, "\tjsr\ttos") && - (L2[0] = NextCodeLine (L)) != 0 && - IsCondJump (L2[0])) { - - /* Extract the condition from the function name and branch */ - C = CheckAndGetIntCmp (L, L2[0]); - if (C < 0) { - /* Something is wrong */ - goto NextLine; - } - - /* Replace the subroutine call by a cheaper one */ - L = ReplaceLine (L, "\tjsr\ttosicmp"); - - /* For easier reading, get a pointer to the jump target */ - BranchTarget = L2[0]->Line+5; - - /* Check if we can replace the jump (sometimes we would need two - * conditional jumps, we will not handle that for now since it - * has some complications - both jumps may be far jumps for - * example making the jumps more costly than the bool transformer - * subroutine). If we cannot replace the jump, bail out. - */ - switch (C) { - - case CMP_EQ: - L = NewLineAfter (L, "\tjeq\t%s", BranchTarget); - break; - - case CMP_NE: - L = NewLineAfter (L, "\tjne\t%s", BranchTarget); - break; - - case CMP_GT: - Label = AllocLabel (); - L = NewLineAfter (L, "\tbeq\tL%04X", Label); - L = NewLineAfter (L, "\tjpl\t%s", BranchTarget); - L = NewLabelAfter(L, Label); - break; - - case CMP_GE: - L = NewLineAfter (L, "\tjpl\t%s", BranchTarget); - break; - - case CMP_LT: - L = NewLineAfter (L, "\tjmi\t%s", BranchTarget); - break; - - case CMP_LE: - L = NewLineAfter (L, "\tjeq\t%s", BranchTarget); - L = NewLineAfter (L, "\tjmi\t%s", BranchTarget); - break; - - case CMP_UGT: - Label = AllocLabel (); - L = NewLineAfter (L, "\tbeq\tL%04X", Label); - L = NewLineAfter (L, "\tjcs\t%s", BranchTarget); - L = NewLabelAfter(L, Label); - break; - - case CMP_UGE: - L = NewLineAfter (L, "\tjcs\t%s", BranchTarget); - break; - - case CMP_ULT: - L = NewLineAfter (L, "\tjcc\t%s", BranchTarget); - break; - - case CMP_ULE: - L = NewLineAfter (L, "\tjeq\t%s", BranchTarget); - L = NewLineAfter (L, "\tjcc\t%s", BranchTarget); - break; - - default: - Internal ("Unknown jump condition: %u", C); - - } - - /* Remove the old stuff */ - FreeLine (L2[0]); - } - -NextLine: - L = NextCodeLine (L); - } -} - - - -static void OptTests (void) -/* Remove unnecessary tests */ -{ - Line* L2 [2]; - - static const char* BitOps [] = { - "\tand\t", - "\tora\t", - "\teor\t", - 0 - }; - - /* Search for lda/tay/jne or lda/tay/jeq, remove the tay. - * Search for - * lda ... - * cmp #$00 - * jne/jeq - * Remove the cmp. - */ - Line* L = FirstCode; - while (L) { - - /* Search for lda/tay/jne or lda/tay/jeq, remove the tay. - * Search for - * lda/and/ora/eor - * cmp #$00 - * jne/jeq ... - * Remove the cmp. - */ - if ((LineMatch (L, "\tlda\t") || - LineMatch (L, "\tand\t") || - LineMatch (L, "\tora\t") || - LineMatch (L, "\teor\t")) && - GetNextCodeLines (L, L2, 2) && - (LineFullMatch (L2 [0], "\ttay") || - LineFullMatch (L2 [0], "\tcmp\t#$00")) && - IsCondJump (L2 [1])) { - - /* We can remove the tay */ - FreeLine (L2 [0]); - - } - - /* Search for - * - * and ... - * tax - * jeq/jne - * - * and remove the tax. - */ - else if (LineMatchX (L, BitOps) >= 0 && - GetNextCodeLines (L, L2, 2) && - LineFullMatch (L2[0], "\ttax") && - IsCondJump (L2[1])) { - - /* Remove the tax including a hint line of there is one */ - if (LineFullMatch (L2[0]->Prev, "+forcetest")) { - FreeLine (L2[0]->Prev); - } - FreeLine (L2[0]); - - /* If the line before L loads X, this is useless and may be removed */ - L2[0] = PrevCodeLine (L); - if (LineFullMatch (L2[0], "\tldx\t#$00")) { - FreeLine (L2[0]); - } - - } - - /* Search for the sequence - * - * stx xx - * stx tmp1 - * ora tmp1 - * - * and replace it by - * - * stx xx - * ora xx - */ - else if (LineMatch (L, "\tstx\t") && - GetNextCodeLines (L, L2, 2) && - LineFullMatch (L2[0], "\tstx\ttmp1") && - LineFullMatch (L2[1], "\tora\ttmp1")) { - - /* Found, replace it */ - L = NewLineAfter (L, "\tora\t%s", L->Line+5); - - /* Remove remaining stuff */ - FreeLines (L2[0], L2[1]); - - } - - - /* Next line */ - L = NextCodeLine (L); - } -} - - - -static void OptBitOps (void) -/* Optimize bit oeprations */ -{ - Line* L2 [2]; - - /* Walk over the code */ - Line* L = FirstCode; - while (L) { - - /* Search for - * - * lda xxx - * and #$yy ; adc/eor/ora - * sta xxx - * - * and replace it by - * - * lda #$yy - * and xxx - * sta xxx - * - * While this saves nothing here, it transforms the code to contain an - * explicit register load that may be removed by the basic block - * optimization later. As a special optimization for the 65C02, the - * "ora" and "and" ops may be replaced by "trb" and "tsb" resp. if the - * value in A is not used later. - */ - if (LineMatch (L, "\tlda\t") && - L->Line[5] != '#' && - GetNextCodeLines (L, L2, 2) && - LineMatch (L2[1], "\tsta\t") && - strcmp (L->Line+5, L2[1]->Line+5) == 0) { - - if (LineMatch (L2[0], "\tand\t#$")) { - - unsigned Val = GetHexNum (L2[0]->Line+7); - if (Val == 0x00) { - - /* AND with 0x00, remove the mem access */ - FreeLine (L); - FreeLine (L2[1]); - - /* Replace the AND by a load */ - L = ReplaceLine (L2[0], "\tlda\t#$%02X", Val); - - } else if (Val == 0xFF) { - - /* AND with 0xFF, just load the value from memory */ - FreeLines (L2[0], L2[1]); - - } else if (CPU == CPU_65C02 && - !IsXAddrMode (L) && - !IsYAddrMode (L) && - !RegAUsed (L2[1])) { - - /* Replace by trb */ - ReplaceLine (L, "\tlda\t#$%02X", (~Val) & 0xFF); - L = ReplaceLine (L2[0], "\ttrb\t%s", L2[1]->Line+5); - FreeLine (L2[1]); - - } else { - - /* Just reorder */ - ReplaceLine (L, "\tlda\t#$%02X", Val); - ReplaceLine (L2[0], "\tand\t%s", L2[1]->Line+5); - L = L2[1]; - - } - - } else if (LineMatch (L2[0], "\tora\t#$")) { - - unsigned Val = GetHexNum (L2[0]->Line+7); - if (Val == 0x00) { - - /* ORA with 0x00, just load the value from memory */ - FreeLines (L2[0], L2[1]); - - } else if (Val == 0xFF) { - - /* ORA with 0xFF, replace by a store of $FF */ - FreeLine (L); - L = ReplaceLine (L2[0], "\tlda\t#$FF"); - - } else if (CPU == CPU_65C02 && - !IsXAddrMode (L) && - !IsYAddrMode (L) && - !RegAUsed (L2[1])) { - - /* Replace by trb */ - ReplaceLine (L, "\tlda\t#$%02X", Val); - L = ReplaceLine (L2[0], "\ttsb\t%s", L2[1]->Line+5); - FreeLine (L2[1]); - - } else { - - /* Just reorder */ - ReplaceLine (L, "\tlda\t#$%02X", Val); - ReplaceLine (L2[0], "\tora\t%s", L2[1]->Line+5); - L = L2[1]; - - } - - } else if (LineMatch (L2[0], "\teor\t#$") || - LineMatch (L2[0], "\tadc\t#$")) { - - /* Just reorder */ - L = ReplaceLine (L, "\tlda\t%s", L2[0]->Line+5); - ReplaceLine (L2[0], "\t%.3s\t%s", L2[0]->Line+1, L2[1]->Line+5); - - } - } - - /* Next line */ - L = NextCodeLine (L); - } -} - - - -static void OptNeg (void) -/* Optimize the "bnegax/jeq" and "bnegax/jne" sequences */ -{ - Line* L2 [10]; - - Line* L = FirstCode; - while (L) { - - /* Search for the sequence: - * - * lda ... - * jsr bnega - * jeq/jne ... - * - * and replace it by: - * - * lda ... - * jne/jeq ... - */ - if (LineMatch (L, "\tlda\t") && /* Match on start */ - GetNextCodeLines (L, L2, 2) && /* Fetch next lines */ - LineFullMatch (L2 [0], "\tjsr\tbnega") && - IsCondJump (L2 [1])) { - - /* Found the sequence, replace it */ - FreeLine (L2 [0]); - InvertZJump (L2 [1]); - - } - - /* Search for the sequence: - * - * ldy #$xx - * lda (sp),y - * tax - * dey - * lda (sp),y - * jsr bnegax - * jne/jeq ... - * - * and replace it by - * - * ldy #$xx - * lda (sp),y - * dey - * ora (sp),y - * jeq/jne ... - */ - else if (LineMatch (L, "\tldy\t#$") && - GetNextCodeLines (L, L2, 6) && - LineFullMatch (L2[0], "\tlda\t(sp),y") && - LineFullMatch (L2[1], "\ttax") && - LineFullMatch (L2[2], "\tdey") && - LineFullMatch (L2[3], "\tlda\t(sp),y") && - LineFullMatch (L2[4], "\tjsr\tbnegax") && - IsCondJump (L2[5])) { - - L2[1] = ReplaceLine (L2[1], "\tdey"); - L2[2] = ReplaceLine (L2[2], "\tora\t(sp),y"); - FreeLines (L2[3], L2[4]); - InvertZJump (L2[5]); - - } - - /* Search for the sequence: - * - * lda xx - * ldx xx+1 - * jsr bnegax - * jne/jeq ... - * - * and replace it by - * - * lda xx - * ora xx+1 - * jeq/jne ... - */ - else if (LineMatch (L, "\tlda\t") && - GetNextCodeLines (L, L2, 3) && - IsLoadAX (L, L2[0]) && - LineFullMatch (L2[1], "\tjsr\tbnegax") && - IsCondJump (L2[2])) { - - /* Replace the load of X by ora */ - L2[0]->Line[1] = 'o'; - L2[0]->Line[2] = 'r'; - L2[0]->Line[3] = 'a'; - FreeLine (L2[1]); - InvertZJump (L2[2]); - - } - - /* Search for the sequence: - * - * jsr _xxx - * jsr bnega(x) - * jeq/jne ... - * - * and replace it by: - * - * jsr _xxx - * - * jne/jeq ... - */ - else if (LineMatch (L, "\tjsr\t_") && /* Match on start */ - GetNextCodeLines (L, L2, 2) && - LineMatch (L2 [0], "\tjsr\tbnega") && - IsCondJump (L2 [1])) { - - if (LineFullMatch (L2 [0], "\tjsr\tbnega")) { - /* Byte sized */ - L2 [0] = ReplaceLine (L2 [0], "\ttax"); /* Test a */ - } else { - /* Word sized */ - L2 [0] = ReplaceLine (L2 [0], "\tstx\ttmp1"); - NewLineAfter (L2 [0], "\tora\ttmp1"); - } - - /* Invert the jump */ - InvertZJump (L2 [1]); - - } - - /* Next line */ - L = NextCodeLine (L); - } -} - - - -static void OptTriples (void) -/* Replace code triples */ -{ - static const char* Pat1 [] = { - "\tjsr\tldaxysp", - "\tjsr\tldax0sp", - "\tjsr\tldaysp", - "\tjsr\tleaasp", - "\tjsr\tldaxi", - 0 - }; - static const char* Pat2 [] = { - "\tjsr\tpushax", - "\tjsr\tpushax", - "\tjsr\tpushax", - "\tjsr\tpushax", - "\tjsr\tpushax", - 0 - }; - static const char* Replace [] = { - "\tjsr\tpushwysp", - "\tjsr\tpushw0sp", - "\tjsr\tpushbysp", - "\tjsr\tpleaasp", - "\tjsr\tpushw", - }; - - Line* L = FirstCode; - while (L) { - int I = LineFullMatchX (L, Pat1); - if (I >= 0) { - /* We found the first match, get the next line */ - Line* L2 = NextCodeLine (L); - if (L2 && LineFullMatch (L2, Pat2 [I])) { - /* Found. Replace by the short call */ - FreeLine (L2); - L = ReplaceLine (L, Replace [I]); - } - } - /* Next line */ - L = NextCodeLine (L); - } -} - - - -static Line* OptOneBlock (Line* L) -/* Optimize the register contents inside one basic block */ -{ - static const char* Compares [] = { - "\tjsr\ttoseq00", "\tjsr\ttoseqa0", "\tjsr\ttoseqax", - "\tjsr\ttoseqeax", "\tjsr\ttosne00", "\tjsr\ttosnea0", - "\tjsr\ttosneax", "\tjsr\ttosneeax", "\tjsr\ttoslt00", - "\tjsr\ttoslta0", "\tjsr\ttosltax", "\tjsr\ttosult00", - "\tjsr\ttosulta0", "\tjsr\ttosultax", "\tjsr\ttoslteax", - "\tjsr\ttosulteax", "\tjsr\ttosle00", "\tjsr\ttoslea0", - "\tjsr\ttosleax", "\tjsr\ttosule00", "\tjsr\ttosulea0", - "\tjsr\ttosuleax", "\tjsr\ttosleeax", "\tjsr\ttosuleeax", - "\tjsr\ttosgt00", "\tjsr\ttosgta0", "\tjsr\ttosgtax", - "\tjsr\ttosugt00", "\tjsr\ttosugta0", "\tjsr\ttosugtax", - "\tjsr\ttosgteax", "\tjsr\ttosugteax", "\tjsr\ttosge00", - "\tjsr\ttosgea0", "\tjsr\ttosgeax", "\tjsr\ttosuge00", - "\tjsr\ttosugea0", "\tjsr\ttosugeax", "\tjsr\ttosgeeax", - "\tjsr\ttosugeeax", - 0 - }; - - static const char* MakeBool [] = { - "\tjsr\tbooleq", "\tjsr\tboolne", "\tjsr\tboollt", - "\tjsr\tboolle", "\tjsr\tboolgt", "\tjsr\tboolge", - "\tjsr\tboolult", "\tjsr\tboolule", "\tjsr\tboolugt", - "\tjsr\tbooluge", - 0 - }; - - int A = -1; /* Contents of A register */ - int X = -1; /* Contents of X register */ - int Y = -1; /* Contents of Y register */ - Line* L2; - unsigned NewVal; - int Delete; - - while (L && !IsLabel (L)) { - - /* Handle all instructions. All instructions not tested here have - * no effects on the register contents. - */ - Delete = 0; - if (L->Line [0] == '+') { - /* This is a hint */ - if (LineMatch (L, "+a:")) { - /* Information about a */ - switch (L->Line [3]) { - case '!': A = -1; break; - case '=': A = GetHexNum (L->Line + 4); break; - } - } else if (LineMatch (L, "+x:")) { - /* The code generator tells something about the x register */ - switch (L->Line [3]) { - case '!': X = -1; break; - case '=': X = GetHexNum (L->Line + 4); break; - } - } else if (LineMatch (L, "+y:")) { - /* Information about the y register */ - switch (L->Line [3]) { - case '!': Y = -1; break; - case '=': Y = GetHexNum (L->Line + 4); break; - } - } - } else if (LineMatch (L, "\tadc\t")) { - if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) { - L->Line[strlen(L->Line)-2] = '\0'; - } - A = -1; - } else if (LineMatch (L, "\tand\t")) { - A = -1; - } else if (LineFullMatch (L, "\tasl\ta")) { - if (A != -1) { - A = (A << 1) & 0xFF; - } - } else if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) { - L->Line[strlen(L->Line)-2] = '\0'; - } else if (CPU == CPU_65C02 && (LineFullMatch (L, "\tdea") || - LineFullMatch (L, "\tdec\ta"))) { - DEC (A, 1); - } else if (LineFullMatch (L, "\tdex")) { - DEC (X, 1); - } else if (LineFullMatch (L, "\tdey")) { - DEC (Y, 1); - } else if (LineMatch (L, "\teor")) { - A = -1; - } else if (CPU == CPU_65C02 && (LineFullMatch (L, "\tina") || - LineFullMatch (L, "\tinc\ta"))) { - INC (A, 1); - } else if (LineFullMatch (L, "\tinx")) { - INC (X, 1); - } else if (LineFullMatch (L, "\tiny")) { - INC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\taddeq0sp")) { - /* We know about this function */ - A = X = -1; - Y = 1; - } else if (LineFullMatch (L, "\tjsr\taddeqysp")) { - /* We know about this function */ - A = X = -1; - INC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\taxulong")) { - /* We know about this function and we're trying to replace it by - * inline code if we have already a register that contains zero. - */ - char C; - if (A == 0) { - C = 'a'; - } else if (X == 0) { - C = 'x'; - } else if (Y == 0) { - C = 'y'; - } else { - C = '\0'; - } - if (C == '\0') { - /* We cannot replace the code, but we know about the results */ - Y = 0; - } else { - L = ReplaceLine (L, "\tst%c\tsreg", C); - NewLineAfter (L, "\tst%c\tsreg+1", C); - } - } else if (LineFullMatch (L, "\tjsr\tbnega")) { - /* We know about this function */ - A = -1; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tbnegax")) { - /* We know about this function */ - A = -1; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tbnegeax")) { - /* We know about this function */ - A = -1; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tcomplax")) { - /* We know about this function */ - if (A != -1) { - A ^= 0xFF; - } - if (X != -1) { - X ^= 0xFF; - } - } else if (LineFullMatch (L, "\tjsr\tdecax1")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tdecax2")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tdecaxy")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tdeceaxy")) { - /* We know about this function */ - A = X = -1; - } else if (LineMatch (L, "\tjsr\tdecsp") && IsDigit (L->Line[10])) { - if (L->Line[10] == '1') { - /* Destroys Y, leaves all other regs alone */ - Y = -1; - } else { - /* Destroys A, leaves all other regs alone */ - A = -1; - } - } else if (LineFullMatch (L, "\tjsr\tincax1")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tincax2")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tinceaxy")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tladdeq")) { - /* We know about this function */ - A = X = -1; - Y = 3; - } else if (LineFullMatch (L, "\tjsr\tladdeqb")) { - /* We know about this function */ - A = X = -1; - Y = 3; - } else if (LineFullMatch (L, "\tjsr\tlbneg")) { - /* We know about this function */ - A = -1; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tldai")) { - /* We know about this function */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldaidx")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tldau00sp")) { - /* We know about this function */ - A = -1; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldau0ysp")) { - /* We know about this function */ - A = -1; - X = 0; - DEC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\tldaui")) { - /* We know about this function */ - A = -1; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldaui0sp")) { - A = -1; - Y = X; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tldauidx")) { - /* We know about this function */ - A = -1; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tldauiysp")) { - /* We know about this function */ - A = -1; - Y = X; - X = 0; - } else if (LineFullMatch (L, "\tjsr\tldax0sp")) { - /* We know about this function */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldaxi")) { - /* We know about this function */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldaxidx")) { - /* We know about this function */ - A = X = -1; - DEC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\tldaxysp")) { - /* We know about this function */ - A = X = -1; - DEC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\tldeaxi")) { - /* We know about this function */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tldeaxidx")) { - /* We know about this function */ - A = X = -1; - DEC (Y, 3); - } else if (LineFullMatch (L, "\tjsr\tlsubeq")) { - /* We know about this function */ - A = X = -1; - Y = 3; - } else if (LineFullMatch (L, "\tjsr\tlsubeqb")) { - /* We know about this function */ - A = X = -1; - Y = 3; - } else if (LineFullMatch (L, "\tjsr\tnegax")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tnegeax")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tpush0")) { - /* We know about this function */ - A = 0; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush0ax")) { - /* We know about this function */ - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush1")) { - /* We know about this function */ - A = 1; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush2")) { - /* We know about this function */ - A = 2; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush3")) { - /* We know about this function */ - A = 3; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush4")) { - /* We know about this function */ - A = 4; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush5")) { - /* We know about this function */ - A = 5; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush6")) { - /* We know about this function */ - A = 6; - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpush7")) { - /* We know about this function */ - A = 7; - X = 0; - Y = 0; - } else if (CPU != CPU_65C02 && LineFullMatch (L, "\tjsr\tpusha")) { - /* We know about this function */ - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpusha0")) { - /* We know about this function - * If X is already zero, we may call pushax instead and save two - * cycles. - */ - if (X == 0) { - L = ReplaceLine (L, "\tjsr\tpushax"); - } - X = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushax")) { - /* We know about this function */ - Y = 0; - } else if (CPU != CPU_65C02 && LineFullMatch (L, "\tjsr\tpushaysp")) { - /* We know about this function */ - A = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushc0")) { - /* We know about this function */ - A = 0; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushc1")) { - /* We know about this function */ - A = 1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushc2")) { - /* We know about this function */ - A = 2; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpusheax")) { - /* We know about this function */ - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushw")) { - /* We know about this function (calls pushax) */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushw0sp")) { - /* We know about this function(calls pushax) */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushwidx")) { - /* We know about this function (calls pushax) */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tpushwysp")) { - /* We know about this function (calls pushax) */ - A = X = -1; - Y = 0; - } else if (LineFullMatch (L, "\tjsr\tresteax")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tsaveeax")) { - /* We know about this function */ - /* Changes nothing */ - } else if (LineFullMatch (L, "\tjsr\tshrax1")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tshrax2")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tshrax3")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tshreax1")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tshreax2")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tshreax3")) { - /* We know about this function */ - A = X = -1; - } else if (LineFullMatch (L, "\tjsr\tstaspp")) { - /* We know about this function */ - Y = -1; - } else if (LineFullMatch (L, "\tjsr\tstaxspp")) { - /* We know about this function */ - Y = -1; - } else if (LineFullMatch (L, "\tjsr\tstax0sp")) { - /* We know about this function */ - Y = 1; - } else if (LineFullMatch (L, "\tjsr\tstaxysp")) { - /* We know about this function */ - INC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\tsubeq0sp")) { - /* We know about this function */ - A = X = -1; - Y = 1; - } else if (LineFullMatch (L, "\tjsr\tsubeqysp")) { - /* We know about this function */ - A = X = -1; - INC (Y, 1); - } else if (LineFullMatch (L, "\tjsr\tsubysp")) { - /* We know about this function */ - A = -1; - } else if (LineFullMatch (L, "\tjsr\ttosadda0")) { - /* We know about this function */ - A = X = -1; - Y = 1; - } else if (LineFullMatch (L, "\tjsr\ttosaddax")) { - /* We know about this function */ - A = X = -1; - Y = 1; - } else if (LineFullMatch (L, "\tjsr\ttosicmp")) { - /* We know about this function */ - A = X = -1; - Y = 0; - } else if (LineFullMatchX (L, Compares) >= 0) { - A = Y = -1; - X = 0; - } else if (LineFullMatchX (L, MakeBool) >= 0) { - A = -1; - X = 0; - } else if (LineMatch (L, "\tjsr\t")) { - /* Subroutine call, forget all register information */ - A = X = Y = -1; - } else if (LineMatch (L, "\tlda\t")) { - if (!RegAUsed (L) && !IsCondJump (NextInstruction (L))) { - /* The value loaded is not used later, remove it */ - Delete = 1; - } else if (LineMatch (L, "\tlda\t(")) { - if (IsXAddrMode (L)) { - /* lda (zp,x). */ - /* If X is zero and we have a 65C02 cpu, replace it by - * an indirect load. - */ - if (X == 0 && CPU == CPU_65C02) { - unsigned Len = strlen (L->Line); - L->Line [Len-3] = ')'; - L->Line [Len-2] = '\0'; - /* If Y and X are both zero, replace by load indirect - * y and save one cycle in some cases. - */ - } else if (X == 0 && Y == 0) { - char Buf [256]; - const char* S = L->Line + 6; - char* T = Buf + 6; - strcpy (Buf, "\tlda\t("); - while (*S != ',') { - *T++ = *S++; - } - *T++ = ')'; - *T++ = ','; - *T++ = 'y'; - *T = '\0'; - L = ReplaceLine (L, Buf); - } - } else if (IsYAddrMode (L)) { - /* lda (zp),y. If Y is zero and we have a 65C02 CPU, - * replace it by an indirect load. - */ - if (Y == 0 && CPU == CPU_65C02) { - unsigned Len = strlen (L->Line); - L->Line [Len-3] = ')'; - L->Line [Len-2] = '\0'; - } - } - /* In any case invalidate A */ - A = -1; - } else if (LineMatch (L, "\tlda\t#$")) { - /* Immidiate load into A */ - NewVal = GetHexNum (L->Line + 7); - if (NewVal == A) { - /* Load has no effect */ - Delete = 1; - } else if (NewVal == X) { - /* Requested value is already in X */ - L = ReplaceLine (L, "\ttxa"); - } else if (NewVal == Y) { - /* Requested value is already in Y */ - L = ReplaceLine (L, "\ttya"); - } else if (CPU == CPU_65C02 && A != -1) { - /* Try ina/dea operators of 65C02 */ - if (NewVal == ((A - 1) & 0xFF)) { - L = ReplaceLine (L, "\tdea"); - } else if (NewVal == ((A + 1) & 0xFF)) { - L = ReplaceLine (L, "\tina"); - } - } - /* Anyway, the new value is now in A */ - A = NewVal; - } else { - /* Memory load into A */ - A = -1; - } - } else if (LineMatch (L, "\tldax\t")) { - /* Memory load into A and X */ - A = X = -1; - } else if (LineMatch (L, "\tldx\t")) { - if (!RegXUsed (L) && !IsCondJump (NextInstruction (L))) { - /* The value loaded is not used later, remove it */ - Delete = 1; - } else if (LineMatch (L, "\tldx\t#$")) { - /* Immidiate load into X */ - NewVal = GetHexNum (L->Line + 7); - if (NewVal == X) { - /* Load has no effect */ - Delete = 1; - } else if (NewVal == A) { - /* Requested value is already in A */ - L = ReplaceLine (L, "\ttax"); - } else if (X != -1 && NewVal == ((X + 1) & 0xFF)) { - /* Requested value is one more than current contents */ - L = ReplaceLine (L, "\tinx"); - } else if (X != -1 && NewVal == ((X - 1) & 0xFF)) { - /* Requested value is one less than current contents */ - L = ReplaceLine (L, "\tdex"); - } - /* Anyway, the new value is now in X */ - X = NewVal; - } else { - /* Memory load into X */ - X = -1; - } - } else if (LineMatch (L, "\tldy\t")) { - if (!RegYUsed (L) && !IsCondJump (NextInstruction (L))) { - /* The value loaded is not used later, remove it */ - Delete = 1; - } else if (LineMatch (L, "\tldy\t#$")) { - /* Immidiate load into Y */ - NewVal = GetHexNum (L->Line + 7); - if (NewVal == Y) { - /* Load has no effect */ - Delete = 1; - } else if (NewVal == A) { - /* Requested value is already in A */ - L = ReplaceLine (L, "\ttay"); - } else if (Y != -1 && NewVal == ((Y + 1) & 0xFF)) { - /* Requested value is one more than current contents */ - L = ReplaceLine (L, "\tiny"); - } else if (Y != -1 && NewVal == ((Y - 1) & 0xFF)) { - /* Requested value is one less than current contents */ - L = ReplaceLine (L, "\tdey"); - } - /* Anyway, the new value is now in Y */ - Y = NewVal; - } else { - /* Memory load into Y */ - Y = -1; - } - } else if (LineFullMatch (L, "\tlsr\ta")) { - if (A != -1) { - A >>= 1; - } - } else if (LineMatch (L, "\tora\t#$")) { - if (A != -1) { - A |= GetHexNum (L->Line + 7); - } - } else if (LineMatch (L, "\tora\t")) { - A = -1; - } else if (LineFullMatch (L, "\tpla")) { - A = -1; - } else if (LineFullMatch (L, "\trol\ta")) { - A = -1; - } else if (LineFullMatch (L, "\tror\ta")) { - A = -1; - } else if (LineFullMatch (L, "\trts")) { - A = X = Y = -1; - } else if (LineFullMatch (L, "\trti")) { - A = X = Y = -1; - } else if (LineMatch (L, "\tsbc\t")) { - if (CPU == CPU_65C02 && Y == 0 && L->Line[5] == '(' && IsYAddrMode(L)) { - L->Line[strlen(L->Line)-2] = '\0'; - } - A = -1; - } else if (CPU == CPU_65C02 && LineMatch (L, "\tst")) { - /* Try to replace by stz if possible */ - if (A == 0 && LineMatch (L, "\tsta\t")) { - /* Not indirect and not Y allowed */ - if (L->Line[5] != '(' && !IsYAddrMode (L)) { - L->Line[3] = 'z'; - } - } else if (X == 0 && LineMatch (L, "\tstx\t")) { - /* absolute,y not allowed */ - if (!IsYAddrMode (L)) { - L->Line[3] = 'z'; - } - } else if (Y == 0 && LineMatch (L, "\tsty\t")) { - /* sty and stz share all addressing modes */ - L->Line[3] = 'z'; - } - } else if (LineFullMatch (L, "\ttax")) { - if (A != -1 && X == A) { - /* Load has no effect */ - Delete = 1; - } else { - X = A; - } - } else if (LineFullMatch (L, "\ttay")) { - if (A != -1 && Y == A) { - /* Load has no effect */ - Delete = 1; - } else { - Y = A; - } - } else if (LineFullMatch (L, "\ttsx")) { - X = -1; - } else if (LineFullMatch (L, "\ttxa")) { - if (X != -1 && A == X) { - /* Load has no effect */ - Delete = 1; - } else { - A = X; - } - } else if (LineFullMatch (L, "\ttya")) { - if (Y != -1 && A == Y) { - /* Load has no effect */ - Delete = 1; - } else { - A = Y; - } - } - - /* Set to next line, handle deletions */ - L2 = NextCodeSegLine (L); - if (Delete) { - FreeLine (L); - } - L = L2; - - } - if (L) { - /* Skip the label */ - L = NextCodeSegLine (L); - } - return L; -} - - - -static void OptBlocks (void) -/* Optimize the register contents inside basic blocks */ -{ - Line* L = FirstCode; - while (L) { - L = OptOneBlock (L); - } -} - - - -static void OptJumps (void) -/* Optimize jumps */ -{ - static const char* Jumps [] = { - "\tjeq\tL", - "\tjne\tL", - "\tjmi\tL", - "\tjpl\tL", - "\tjcs\tL", - "\tjcc\tL", - 0 - }; - - Line* L = FirstCode; - while (L) { - int I = LineMatchX (L, Jumps); - if (I >= 0) { - Line* Target = GetTargetLine (L->Line+5); - if (Target->Index > L->Index) { - /* This is a forward jump. Backward jumps are handled - * automagically by the assembler. - */ - unsigned Distance = GetJumpDistance (L, Target); - if (Distance < 123) { /* Safety */ - L->Line [1] = 'b'; /* Make a short branch */ - L->Size = 2; /* Set new size */ - } - } - } - L = NextCodeLine (L); - } - - /* Special treatment for jumps on the 65C02 */ - if (CPU == CPU_65C02) { - - Line* L = FirstCode; - while (L) { - if (LineMatch (L, "\tjmp\tL")) { - Line* Target = GetTargetLine (L->Line+5); - unsigned Distance = GetJumpDistance (L, Target); - if (Distance < 123) { /* Safety */ - L->Line [1] = 'b'; /* Make a short branch */ - L->Line [2] = 'r'; - L->Line [3] = 'a'; - L->Size = 2; /* Set new size */ - } - } - L = NextCodeLine (L); - } - - } -} - - - -static void OptRTS (void) -/* Change sequences of jsr XXX/rts to jmp XXX */ -{ - Line* L = FirstCode; - while (L) { - if (LineMatch (L, "\tjsr\t")) { - /* This is a jsr, get the next instruction */ - Line* L2 = NextCodeLine (L); - if (L2 && LineFullMatch (L2, "\trts")) { - /* We found a sequence */ - FreeLine (L2); - L->Line [2] = 'm'; - L->Line [3] = 'p'; - } - } - /* Try the next line */ - L = NextCodeLine (L); - } -} - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -void OptDoOpt (void) -/* Run the optimizer over the collected stuff */ -{ - typedef void (*OptFunc)(void); - - /* Table with optimizer steps - are called in this order */ - static const OptFunc OptFuncs [] = { - OptCompares1, /* Optimize compares - first step */ - OptDeadJumps, /* Remove dead jumps */ - OptLoads, /* Remove unnecessary loads */ - OptRegLoads, /* Remove unnecessary register loads */ - OptPtrOps, /* Optimize stores through pointers */ - OptRegVars, /* Optimize use of register variables */ - OptDoubleJumps, /* Remove jump cascades - must be used before OptNeg */ - OptNeg, /* Remove unnecessary boolean negates */ - OptJumpRTS, /* Replace jumps to an RTS by an RTS */ - OptBoolTransforms, /* Optimize boolean transforms */ - OptCompares2, /* Optimize compares */ - OptTests, /* Remove unnecessary tests */ - OptBitOps, /* Optimize bit operations */ - OptTriples, /* Optimize several triples */ - OptBlocks, /* Optimize basic blocks */ - OptRegLoads, /* Remove unnecessary register loads (another pass) */ - OptBlocks, /* Optimize basic blocks */ - OptJumps, /* Optimize jumps */ - OptRTS, /* Optimize jsr/rts sequences */ - }; - - unsigned long Flags; - unsigned I; - - /* Find and remember the first line of code */ - FindCodeStart (); - - /* Mark all lines inside the code segment */ - MarkCodeLines (); - - /* Create a list of all local labels for fast access */ - CreateLabelList (); - - /* Ok, now start the real optimizations */ - Flags = 1UL; - for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I, Flags <<= 1) { - if ((OptDisable & Flags) == 0) { - OptFuncs[I] (); - } else if (Verbosity > 0 || Debug) { - printf ("Optimizer pass %u skipped\n", I); - } - } -} - - - diff --git a/src/cc65/optimize.h b/src/cc65/optimize.h deleted file mode 100644 index 503ccba44..000000000 --- a/src/cc65/optimize.h +++ /dev/null @@ -1,68 +0,0 @@ -/*****************************************************************************/ -/* */ -/* optimize.h */ -/* */ -/* An optimizer for the cc65 C compiler */ -/* */ -/* */ -/* */ -/* (C) 1998 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ -/* */ -/* */ -/* 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 OPTIMIZE_H -#define OPTIMIZE_H - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Bitset of flags that switch the different optimizer passes */ -extern unsigned long OptDisable; - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -void OptDoOpt (void); -/* Run the optimizer over the collected stuff */ - - - -/* End of optimize.h */ - -#endif - - -