From e68b8160ed1a2ff1c154ce0ed9f8539531a09c65 Mon Sep 17 00:00:00 2001 From: cuz Date: Tue, 8 Oct 2002 20:56:00 +0000 Subject: [PATCH] Added more size optimizations, separate module git-svn-id: svn://svn.cc65.org/cc65/trunk@1453 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeent.c | 2 +- src/cc65/codeinfo.c | 19 ++- src/cc65/codeopt.c | 272 ++++-------------------------- src/cc65/coptsize.c | 349 +++++++++++++++++++++++++++++++++++++++ src/cc65/coptsize.h | 70 ++++++++ src/cc65/coptstop.c | 2 - src/cc65/make/gcc.mak | 1 + src/cc65/make/watcom.mak | 4 +- 8 files changed, 468 insertions(+), 251 deletions(-) create mode 100644 src/cc65/coptsize.c create mode 100644 src/cc65/coptsize.h diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index 50fa59a4e..6e96aaa07 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -1229,7 +1229,7 @@ void CE_Output (const CodeEntry* E, FILE* F) 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), diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 5014e71a4..3912dae91 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -72,6 +72,8 @@ struct FuncInfo { }; 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 }, @@ -124,7 +126,7 @@ static const FuncInfo FuncInfoTable[] = { { "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 }, @@ -135,9 +137,20 @@ static const FuncInfo FuncInfoTable[] = { { "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 }, @@ -158,16 +171,15 @@ static const FuncInfo FuncInfoTable[] = { { "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 }, @@ -186,6 +198,7 @@ static const FuncInfo FuncInfoTable[] = { { "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])) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 50b014212..1690a42bc 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -53,6 +53,7 @@ #include "coptind.h" #include "coptneg.h" #include "coptpush.h" +#include "coptsize.h" #include "coptstop.h" #include "coptsub.h" #include "copttest.h" @@ -1277,238 +1278,7 @@ static unsigned OptDecouple (CodeSeg* S) /* 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; } @@ -1598,7 +1368,7 @@ static OptFunc DOptPushPop = { OptPushPop, "OptPushPop", 0, 0, 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 }; @@ -1656,7 +1426,7 @@ static OptFunc* OptFuncs[] = { &DOptShift1, &DOptShift2, &DOptShift3, - /*&DOptSize1,*/ + &DOptSize1, &DOptSize2, &DOptStackOps, &DOptStoreLoad, @@ -2037,16 +1807,30 @@ static unsigned RunOptGroup6 (CodeSeg* S) 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); diff --git a/src/cc65/coptsize.c b/src/cc65/coptsize.c new file mode 100644 index 000000000..f5db1dd6c --- /dev/null +++ b/src/cc65/coptsize.c @@ -0,0 +1,349 @@ +/*****************************************************************************/ +/* */ +/* 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 + +/* 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; +} + + + diff --git a/src/cc65/coptsize.h b/src/cc65/coptsize.h new file mode 100644 index 000000000..13eeae038 --- /dev/null +++ b/src/cc65/coptsize.h @@ -0,0 +1,70 @@ +/*****************************************************************************/ +/* */ +/* 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 + + + diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 360e64729..4e1c2e6d7 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -38,8 +38,6 @@ /* cc65 */ #include "codeent.h" #include "codeinfo.h" -#include "codeopt.h" -#include "error.h" #include "coptstop.h" diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 9d33f3387..7bd827448 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -40,6 +40,7 @@ OBJS = anonname.o \ coptind.o \ coptneg.o \ coptpush.o \ + coptsize.o \ coptstop.o \ coptsub.o \ copttest.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 72bb31087..be067caa1 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -85,6 +85,7 @@ OBJS = anonname.obj \ coptind.obj \ coptneg.obj \ coptpush.obj \ + coptsize.obj \ coptstop.obj \ coptsub.obj \ copttest.obj \ @@ -166,6 +167,7 @@ FILE coptcmp.obj FILE coptind.obj FILE coptneg.obj FILE coptpush.obj +FILE coptsize.obj FILE coptstop.obj FILE coptsub.obj FILE copttest.obj @@ -181,7 +183,7 @@ FILE exprnode.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 -- 2.39.5