char Use [128];
char Chg [128];
fprintf (F,
- "%*s; USE: %-20s CHG: %-20s SIZE: %u\n",
+ "%*s; USE: %-12s CHG: %-12s SIZE: %u\n",
30-Chars, "",
RegInfoDesc (E->Use, Use),
RegInfoDesc (E->Chg, Chg),
};
static const FuncInfo FuncInfoTable[] = {
+ { "addeq0sp", REG_AX, REG_AXY },
+ { "addeqysp", REG_AXY, REG_AXY },
{ "addysp", REG_Y, REG_NONE },
{ "aslax1", REG_AX, REG_AX | REG_TMP1 },
{ "aslax2", REG_AX, REG_AX | REG_TMP1 },
{ "laddeqa", REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
{ "ldaidx", REG_AXY, REG_AX | REG_PTR1 },
{ "ldauidx", REG_AXY, REG_AX | REG_PTR1 },
- { "ldax0sp", REG_Y, REG_AX },
+ { "ldax0sp", REG_NONE, REG_AXY },
{ "ldaxi", REG_AX, REG_AXY | REG_PTR1 },
{ "ldaxidx", REG_AXY, REG_AXY | REG_PTR1 },
{ "ldaxysp", REG_Y, REG_AXY },
{ "lsubeqa", REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
{ "lsubeqysp", REG_EAXY, REG_EAXY },
{ "negax", REG_AX, REG_AX },
+ { "push0", REG_NONE, REG_AXY },
+ { "push1", REG_NONE, REG_AXY },
+ { "push2", REG_NONE, REG_AXY },
+ { "push3", REG_NONE, REG_AXY },
+ { "push4", REG_NONE, REG_AXY },
+ { "push5", REG_NONE, REG_AXY },
+ { "push6", REG_NONE, REG_AXY },
+ { "push7", REG_NONE, REG_AXY },
{ "pusha", REG_A, REG_Y },
{ "pusha0", REG_A, REG_XY },
{ "pushax", REG_AX, REG_Y },
+ { "pushc0", REG_NONE, REG_A | REG_Y },
+ { "pushc1", REG_NONE, REG_A | REG_Y },
+ { "pushc2", REG_NONE, REG_A | REG_Y },
{ "pusheax", REG_EAX, REG_Y },
{ "pushw0sp", REG_NONE, REG_AXY },
{ "pushwysp", REG_Y, REG_AXY },
{ "staxysp", REG_AXY, REG_Y },
{ "subeq0sp", REG_AX, REG_AXY },
{ "subeqysp", REG_AXY, REG_AXY },
- { "tsteax", REG_EAX, REG_Y },
{ "tosadda0", REG_A, REG_AXY },
{ "tosaddax", REG_AX, REG_AXY },
- { "tosicmp", REG_AX, REG_AXY | REG_SREG },
{ "tosdiva0", REG_AX, REG_ALL },
{ "tosdivax", REG_AX, REG_ALL },
{ "tosdiveax", REG_EAX, REG_ALL },
{ "toseqeax", REG_EAX, REG_AXY | REG_PTR1 },
{ "tosgeeax", REG_EAX, REG_AXY | REG_PTR1 },
{ "tosgteax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosicmp", REG_AX, REG_AXY | REG_SREG },
{ "toslcmp", REG_EAX, REG_A | REG_Y | REG_PTR1 },
{ "tosleeax", REG_EAX, REG_AXY | REG_PTR1 },
{ "toslteax", REG_EAX, REG_AXY | REG_PTR1 },
{ "tosumula0", REG_AX, REG_ALL },
{ "tosumulax", REG_AX, REG_ALL },
{ "tosumuleax", REG_EAX, REG_ALL },
+ { "tsteax", REG_EAX, REG_Y },
{ "utsteax", REG_EAX, REG_Y },
};
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
#include "coptind.h"
#include "coptneg.h"
#include "coptpush.h"
+#include "coptsize.h"
#include "coptstop.h"
#include "coptsub.h"
#include "copttest.h"
/* Insert the replacement if we have one */
if (X) {
- CS_InsertEntry (S, X, I+1);
- CS_DelEntry (S, I);
- ++Changes;
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Free register info */
- CS_FreeRegInfo (S);
-
- /* Return the number of changes made */
- return Changes;
-}
-
-
-
-/*****************************************************************************/
-/* Size optimization */
-/*****************************************************************************/
-
-
-
-#if 0
-static unsigned OptSize1 (CodeSeg* S)
-/* Do size optimization by calling special subroutines that preload registers.
- * This routine does not work standalone, it needs a following register load
- * removal pass.
- */
-{
- typedef struct CallDesc CallDesc;
- struct CallDesc {
- const char* LongFunc; /* Long function name */
- short A, X, Y; /* Register contents */
- const char* ShortFunc; /* Short function name */
- };
-
- static const CallDesc CallTable [] = {
- { "staxysp", -1, -1, 0, "stax0sp" },
- { "addeqysp", -1, -1, 0, "addeq0sp" },
- { "ldaxysp", -1, -1, 1, "ldax0sp" },
- { "ldeaxysp", -1, -1, 3, "ldeax0sp" },
- { "pushax", 0, 0, -1, "push0" },
- { "pushax", -1, 0, -1, "pusha0" },
- { "pushax", -1, 0xFF, -1, "pushaFF" },
- { "pushaysp", -1, -1, 0, "pusha0sp" },
- { "tosaddax", -1, 0, -1, "tosadda0" },
- { "tosandax", -1, 0, -1, "tosanda0" },
- { "tosdivax", -1, 0, -1, "tosdiva0" },
- { "toseqax", -1, 0, -1, "toseqa0" },
- { "tosgeax", -1, 0, -1, "tosgea0" },
- { "tosgtax", -1, 0, -1, "tosgta0" },
- { "laddeqysp", -1, -1, 0, "laddeq0sp" },
- { "ldaxidx", -1, -1, 1, "ldaxi" },
- { "ldeaxidx", -1, -1, 3, "ldeaxi" },
- { "ldeaxysp", -1, -1, 3, "ldeax0sp" },
- { "tosleax", -1, 0, -1, "toslea0" },
- { "lsubeqysp", -1, -1, 0, "lsubeq0sp" },
-
- "toslta0", /* tosltax, x = 0 */
- "tosmoda0", /* tosmodax, x = 0 */
- "tosmula0", /* tosmulax, x = 0 */
- "tosumula0", /* tosumulax, x = 0 */
- "tosnea0", /* tosneax, x = 0 */
- "tosora0", /* tosorax, x = 0 */
- "push1", /* pushax, x = 0, a = 1 */
- "push2", /* pushax, x = 0, a = 2 */
- "push3", /* pushax, x = 0, a = 3 */
- "push4", /* pushax, x = 0, a = 4 */
- "push5", /* pushax, x = 0, a = 5 */
- "push6", /* pushax, x = 0, a = 6 */
- "push7", /* pushax, x = 0, a = 7 */
- "pushc0", /* pusha, a = 0 */
- "pushc1", /* pusha, a = 1 */
- "pushc2", /* pusha, a = 2 */
- "tosrsuba0", /* tosrsubax, x = 0 */
- "tosshla0", /* tosshlax, x = 0 */
- "tosasla0", /* tosaslax, x = 0 */
- "tosshra0", /* tosshrax, x = 0 */
- "tosasra0", /* tosasrax, x = 0 */
- "steax0sp", /* steaxsp, y = 0 */
- "tossuba0", /* tossubax, x = 0 */
- "subeq0sp", /* subeqysp, y = 0 */
- "tosudiva0", /* tosudivax, x = 0 */
- "tosugea0", /* tosugeax, x = 0 */
- "tosugta0", /* tosugtax, x = 0 */
- "tosulea0", /* tosuleax, x = 0 */
- "tosulta0", /* tosultax, x = 0 */
- "tosumoda0", /* tosumodax, x = 0 */
- "tosxora0", /* tosxorax, x = 0 */
-
- "tosadd0ax", /* tosaddeax, sreg = 0 */
- "laddeqa", /* laddeq, sreg = 0, x = 0 */
- "laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */
- "tosand0ax", /* tosandeax, sreg = 0 */
- "tosdiv0ax", /* tosdiveax, sreg = 0 */
- "tosmod0ax", /* tosmodeax, sreg = 0 */
- "tosmul0ax", /* tosmuleax, sreg = 0 */
- "tosumul0ax", /* tosumuleax, sreg = 0 */
- "tosor0ax", /* tosoreax, sreg = 0 */
- "push0ax", /* pusheax, sreg = 0 */
- "tosrsub0ax", /* tosrsubeax, sreg = 0 */
- "tosshl0ax", /* tosshleax, sreg = 0 */
- "tosasl0ax", /* tosasleax, sreg = 0 */
- "tosshr0ax", /* tosshreax, sreg = 0 */
- "tosasr0ax", /* tosasreax, sreg = 0 */
- "tossub0ax", /* tossubeax, sreg = 0 */
- "lsubeqa", /* lsubeq, sreg = 0, x = 0 */
- "lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */
- "tosudiv0ax", /* tosudiveax, sreg = 0 */
- "tosumod0ax", /* tosumodeax, sreg = 0 */
- "tosxor0ax", /* tosxoreax, sreg = 0 */
-
- };
-
- unsigned Changes = 0;
- unsigned I;
-
- /* Generate register info for the following step */
- CS_GenRegInfo (S);
-
- /* Walk over the entries */
- I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Check if it's a subroutine call */
- if (E->OPC == OP65_JSR) {
-
- /* Check for any of the known functions */
-
-
-
- }
-
- /* Next entry */
- ++I;
-
- }
-
- /* Free register info */
- CS_FreeRegInfo (S);
-
- /* Return the number of changes made */
- return Changes;
-}
-#endif
-
-
-
-static unsigned OptSize2 (CodeSeg* S)
-/* Do size optimization by using shorter code sequences, even if this
- * introduces relations between instructions. This step must be one of the
- * last steps, because it makes further work much more difficult.
- */
-{
- unsigned Changes = 0;
- unsigned I;
-
- /* Generate register info for the following step */
- CS_GenRegInfo (S);
-
- /* Walk over the entries */
- I = 0;
- while (I < CS_GetEntryCount (S)) {
-
-
- /* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
-
- /* Assume we have no replacement */
- CodeEntry* X = 0;
-
- /* Check the instruction */
- switch (E->OPC) {
-
- case OP65_LDA:
- if (CE_KnownImm (E)) {
- short Val = (short) E->Num;
- if (Val == E->RI->In.RegX) {
- X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
- } else if (Val == E->RI->In.RegY) {
- X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
- } else if (E->RI->In.RegA >= 0 && CPU >= CPU_65C02) {
- if (Val == ((E->RI->In.RegA - 1) & 0xFF)) {
- X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
- } else if (Val == ((E->RI->In.RegA + 1) & 0xFF)) {
- X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
- }
- }
- }
- break;
-
- case OP65_LDX:
- if (CE_KnownImm (E)) {
- short Val = (short) E->Num;
- if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX - 1) & 0xFF)) {
- X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
- } else if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX + 1) & 0xFF)) {
- X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
- } else if (Val == E->RI->In.RegA) {
- X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
- }
- }
- break;
-
- case OP65_LDY:
- if (CE_KnownImm (E)) {
- short Val = (short) E->Num;
- if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY - 1) & 0xFF)) {
- X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
- } else if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY + 1) & 0xFF)) {
- X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
- } else if (Val == E->RI->In.RegA) {
- X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI);
- }
- }
- break;
-
- default:
- /* Avoid gcc warnings */
- break;
-
- }
-
- /* Insert the replacement if we have one */
- if (X) {
- CS_InsertEntry (S, X, I+1);
+ CS_InsertEntry (S, X, I+1);
CS_DelEntry (S, I);
++Changes;
}
static OptFunc DOptShift1 = { OptShift1, "OptShift1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptShift2 = { OptShift2, "OptShift2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptShift3 = { OptShift3, "OptShift3", 110, 0, 0, 0, 0, 0 };
-/*static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 };*/
+static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptSize2 = { OptSize2, "OptSize2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0, 0 };
&DOptShift1,
&DOptShift2,
&DOptShift3,
- /*&DOptSize1,*/
+ &DOptSize1,
&DOptSize2,
&DOptStackOps,
&DOptStoreLoad,
unsigned Changes = 0;
unsigned C;
- /* Optimize for size, that is replace operations by shorter ones, even
- * if this does hinder further optimizations (no problem since we're
- * done soon).
- */
- Changes += RunOptFunc (S, &DOptSize2, 1);
-
- /* Run the jump target optimization again, since the size optimization
- * above may have opened new oportunities.
- */
- Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+ if (CodeSizeFactor <= 100) {
+ /* Optimize for size, that is replace operations by shorter ones, even
+ * if this does hinder further optimizations (no problem since we're
+ * done soon).
+ */
+ C = RunOptFunc (S, &DOptSize1, 1);
+ if (C) {
+ Changes += C;
+ /* Run some optimization passes again, since the size optimizations
+ * may have opened new oportunities.
+ */
+ Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+ Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+ }
+ }
+ C = RunOptFunc (S, &DOptSize2, 1);
+ if (C) {
+ Changes += C;
+ /* Run some optimization passes again, since the size optimizations
+ * may have opened new oportunities.
+ */
+ Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+ Changes += RunOptFunc (S, &DOptJumpTarget, 5);
+ }
/* Adjust branch distances */
Changes += RunOptFunc (S, &DOptBranchDist, 3);
--- /dev/null
+/*****************************************************************************/
+/* */
+/* coptsize.c */
+/* */
+/* Size optimizations */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+/* cc65 */
+#include "codeent.h"
+#include "codeinfo.h"
+#include "cpu.h"
+#include "coptsize.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+typedef struct CallDesc CallDesc;
+struct CallDesc {
+ const char* LongFunc; /* Long function name */
+ short A, X, Y; /* Register contents */
+ const char* ShortFunc; /* Short function name */
+};
+
+/* Note: The table is sorted. If there is more than one entry with the same
+ * name, entries are sorted best match first, so when searching linear for
+ * a match, the first one can be used because it is also the best one (or
+ * at least none of the following ones are better).
+ */
+static const CallDesc CallTable [] = {
+ { "addeqysp", -1, -1, 0, "addeq0sp" },
+ { "laddeqysp", -1, -1, 0, "laddeq0sp" },
+ { "ldaxysp", -1, -1, 1, "ldax0sp" },
+ { "ldeaxidx", -1, -1, 3, "ldeaxi" },
+ { "ldeaxysp", -1, -1, 3, "ldeax0sp" },
+ { "pusha", 0, -1, -1, "pushc0" },
+ { "pusha", 1, -1, -1, "pushc1" },
+ { "pusha", 2, -1, -1, "pushc2" },
+ { "pushax", 0, 0, -1, "push0" },
+ { "pushax", 1, 0, -1, "push1" },
+ { "pushax", 2, 0, -1, "push2" },
+ { "pushax", 3, 0, -1, "push3" },
+ { "pushax", 4, 0, -1, "push4" },
+ { "pushax", 5, 0, -1, "push5" },
+ { "pushax", 6, 0, -1, "push6" },
+ { "pushax", 7, 0, -1, "push7" },
+ { "pushax", -1, 0, -1, "pusha0" },
+ { "pushax", -1, 0xFF, -1, "pushaFF" },
+ { "pushaysp", -1, -1, 0, "pusha0sp" },
+ { "staxysp", -1, -1, 0, "stax0sp" },
+ { "tosaddax", -1, 0, -1, "tosadda0" },
+ { "tosandax", -1, 0, -1, "tosanda0" },
+ { "tosdivax", -1, 0, -1, "tosdiva0" },
+ { "toseqax", -1, 0, -1, "toseqa0" },
+ { "tosgeax", -1, 0, -1, "tosgea0" },
+ { "tosgtax", -1, 0, -1, "tosgta0" },
+ { "tosleax", -1, 0, -1, "toslea0" },
+ { "tosorax", -1, 0, -1, "tosora0" },
+ { "ldaxidx", -1, -1, 1, "ldaxi" },
+ { "ldeaxysp", -1, -1, 3, "ldeax0sp" },
+ { "lsubeqysp", -1, -1, 0, "lsubeq0sp" },
+ { "steaxysp", -1, -1, 0, "steax0sp" },
+ { "subeqysp", -1, -1, 0, "subeq0sp" },
+ { "tosaslax", -1, 0, -1, "tosasla0" },
+ { "tosasrax", -1, 0, -1, "tosasra0" },
+ { "tosltax", -1, 0, -1, "toslta0" },
+ { "tosmodax", -1, 0, -1, "tosmoda0" },
+ { "tosmulax", -1, 0, -1, "tosmula0" },
+ { "tosneax", -1, 0, -1, "tosnea0" },
+ { "tosrsubax", -1, 0, -1, "tosrsuba0" },
+ { "tosshlax", -1, 0, -1, "tosshla0" },
+ { "tosshrax", -1, 0, -1, "tosshra0" },
+ { "tossubax", -1, 0, -1, "tossuba0" },
+ { "tosudivax", -1, 0, -1, "tosudiva0" },
+ { "tosugeax", -1, 0, -1, "tosugea0" },
+ { "tosugtax", -1, 0, -1, "tosugta0" },
+ { "tosuleax", -1, 0, -1, "tosulea0" },
+ { "tosultax", -1, 0, -1, "tosulta0" },
+ { "tosumodax", -1, 0, -1, "tosumoda0" },
+ { "tosumulax", -1, 0, -1, "tosumula0" },
+ { "tosxorax", -1, 0, -1, "tosxora0" },
+ { "zzzzzzzz", -1, -1, -1, "zzzzzzzz" },
+
+#if 0
+ "tosadd0ax", /* tosaddeax, sreg = 0 */
+ "laddeqa", /* laddeq, sreg = 0, x = 0 */
+ "laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */
+ "tosand0ax", /* tosandeax, sreg = 0 */
+ "tosdiv0ax", /* tosdiveax, sreg = 0 */
+ "tosmod0ax", /* tosmodeax, sreg = 0 */
+ "tosmul0ax", /* tosmuleax, sreg = 0 */
+ "tosumul0ax", /* tosumuleax, sreg = 0 */
+ "tosor0ax", /* tosoreax, sreg = 0 */
+ "push0ax", /* pusheax, sreg = 0 */
+ "tosrsub0ax", /* tosrsubeax, sreg = 0 */
+ "tosshl0ax", /* tosshleax, sreg = 0 */
+ "tosasl0ax", /* tosasleax, sreg = 0 */
+ "tosshr0ax", /* tosshreax, sreg = 0 */
+ "tosasr0ax", /* tosasreax, sreg = 0 */
+ "tossub0ax", /* tossubeax, sreg = 0 */
+ "lsubeqa", /* lsubeq, sreg = 0, x = 0 */
+ "lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */
+ "tosudiv0ax", /* tosudiveax, sreg = 0 */
+ "tosumod0ax", /* tosumodeax, sreg = 0 */
+ "tosxor0ax", /* tosxoreax, sreg = 0 */
+#endif
+};
+#define CALL_COUNT (sizeof(CallTable) / sizeof(CallTable[0]))
+
+
+
+/*****************************************************************************/
+/* Helpers */
+/*****************************************************************************/
+
+
+
+static const CallDesc* FindCall (const char* Name)
+/* Find the function with the given name. Return a pointer to the table entry
+ * or NULL if the function was not found.
+ */
+{
+ /* Do a binary search */
+ int First = 0;
+ int Last = (sizeof(CallTable) / sizeof(CallTable[0])) - 1;
+ int Current;
+ int Result;
+ int Found = 0;
+
+ while (First <= Last) {
+
+ /* Set current to mid of range */
+ Current = (Last + First) / 2;
+
+ /* Do a compare */
+ Result = strcmp (CallTable[Current].LongFunc, Name);
+ if (Result < 0) {
+ First = Current + 1;
+ } else {
+ Last = Current - 1;
+ if (Result == 0) {
+ /* Found. Repeat the procedure until the first of all entries
+ * with the same name is found.
+ */
+ Found = 1;
+ }
+ }
+
+ }
+
+ /* Return the first entry if found, or NULL otherwise */
+ return Found? &CallTable[First] : 0;
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned OptSize1 (CodeSeg* S)
+/* Do size optimization by calling special subroutines that preload registers.
+ * This routine does not work standalone, it needs a following register load
+ * removal pass.
+ */
+{
+ CodeEntry* E;
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Generate register info for the following step */
+ CS_GenRegInfo (S);
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ /* Get next entry */
+ E = CS_GetEntry (S, I);
+
+ /* Check if it's a subroutine call */
+ if (E->OPC == OP65_JSR) {
+
+ /* Check for any of the known functions. */
+ const CallDesc* D = FindCall (E->Arg);
+ while (D && strcmp (D->LongFunc, E->Arg) == 0) {
+ /* Check the registers */
+ if ((D->A < 0 || D->A == E->RI->In.RegA) &&
+ (D->X < 0 || D->X == E->RI->In.RegX) &&
+ (D->Y < 0 || D->Y == E->RI->In.RegY)) {
+ /* Ok, match for all registers */
+ CodeEntry* X;
+ X = NewCodeEntry (E->OPC, E->AM, D->ShortFunc, 0, E->LI);
+ CS_InsertEntry (S, X, I+1);
+ CS_DelEntry (S, I);
+
+ /* Remember that we had changes */
+ ++Changes;
+ }
+ ++D;
+ }
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+unsigned OptSize2 (CodeSeg* S)
+/* Do size optimization by using shorter code sequences, even if this
+ * introduces relations between instructions. This step must be one of the
+ * last steps, because it makes further work much more difficult.
+ */
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Generate register info for the following step */
+ CS_GenRegInfo (S);
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Assume we have no replacement */
+ CodeEntry* X = 0;
+
+ /* Check the instruction */
+ switch (E->OPC) {
+
+ case OP65_LDA:
+ if (CE_KnownImm (E)) {
+ short Val = (short) E->Num;
+ if (Val == E->RI->In.RegX) {
+ X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
+ } else if (Val == E->RI->In.RegY) {
+ X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
+ } else if (E->RI->In.RegA >= 0 && CPU >= CPU_65C02) {
+ if (Val == ((E->RI->In.RegA - 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
+ } else if (Val == ((E->RI->In.RegA + 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
+ }
+ }
+ }
+ break;
+
+ case OP65_LDX:
+ if (CE_KnownImm (E)) {
+ short Val = (short) E->Num;
+ if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX - 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
+ } else if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX + 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
+ } else if (Val == E->RI->In.RegA) {
+ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
+ }
+ }
+ break;
+
+ case OP65_LDY:
+ if (CE_KnownImm (E)) {
+ short Val = (short) E->Num;
+ if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY - 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
+ } else if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY + 1) & 0xFF)) {
+ X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
+ } else if (Val == E->RI->In.RegA) {
+ X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI);
+ }
+ }
+ break;
+
+ default:
+ /* Avoid gcc warnings */
+ break;
+
+ }
+
+ /* Insert the replacement if we have one */
+ if (X) {
+ CS_InsertEntry (S, X, I+1);
+ CS_DelEntry (S, I);
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* coptsize.c */
+/* */
+/* Size optimizations */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef COPTSIZE_H
+#define COPTSIZE_H
+
+
+
+/* cc65 */
+#include "codeseg.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned OptSize1 (CodeSeg* S);
+/* Do size optimization by calling special subroutines that preload registers.
+ * This routine does not work standalone, it needs a following register load
+ * removal pass.
+ */
+
+unsigned OptSize2 (CodeSeg* S);
+/* Do size optimization by using shorter code sequences, even if this
+ * introduces relations between instructions. This step must be one of the
+ * last steps, because it makes further work much more difficult.
+ */
+
+
+
+/* End of coptsize.h */
+#endif
+
+
+
/* cc65 */
#include "codeent.h"
#include "codeinfo.h"
-#include "codeopt.h"
-#include "error.h"
#include "coptstop.h"
coptind.o \
coptneg.o \
coptpush.o \
+ coptsize.o \
coptstop.o \
coptsub.o \
copttest.o \
coptind.obj \
coptneg.obj \
coptpush.obj \
+ coptsize.obj \
coptstop.obj \
coptsub.obj \
copttest.obj \
FILE coptind.obj
FILE coptneg.obj
FILE coptpush.obj
+FILE coptsize.obj
FILE coptstop.obj
FILE coptsub.obj
FILE copttest.obj
FILE funcdesc.obj
FILE function.obj
FILE global.obj
-FILE goto.obj
+FILE goto.obj
FILE hexval.obj
FILE ident.obj
FILE incpath.obj