Added more size optimizations, separate module
git-svn-id: svn://svn.cc65.org/cc65/trunk@1453 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
9ca21c07e0
commit
e68b8160ed
8 changed files with 468 additions and 251 deletions
|
@ -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),
|
||||
|
|
|
@ -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]))
|
||||
|
|
|
@ -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);
|
||||
|
|
349
src/cc65/coptsize.c
Normal file
349
src/cc65/coptsize.c
Normal file
|
@ -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 <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;
|
||||
}
|
||||
|
||||
|
||||
|
70
src/cc65/coptsize.h
Normal file
70
src/cc65/coptsize.h
Normal file
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -38,8 +38,6 @@
|
|||
/* cc65 */
|
||||
#include "codeent.h"
|
||||
#include "codeinfo.h"
|
||||
#include "codeopt.h"
|
||||
#include "error.h"
|
||||
#include "coptstop.h"
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ OBJS = anonname.o \
|
|||
coptind.o \
|
||||
coptneg.o \
|
||||
coptpush.o \
|
||||
coptsize.o \
|
||||
coptstop.o \
|
||||
coptsub.o \
|
||||
copttest.o \
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue