1
0
mirror of https://github.com/cc65/cc65.git synced 2024-07-05 21:29:03 +00:00

More optimizations

git-svn-id: svn://svn.cc65.org/cc65/trunk@971 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-09-25 20:37:58 +00:00
parent 8d0dfb5b41
commit 42326113cb
8 changed files with 416 additions and 29 deletions

View File

@ -144,6 +144,8 @@ static const FuncInfo FuncInfoTable[] = {
{ "staspidx", REG_A | REG_Y, REG_Y | REG_TMP1 | REG_PTR1 },
{ "stax0sp", REG_AX, REG_Y },
{ "staxysp", REG_AXY, 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 },
@ -164,22 +166,24 @@ static const ZPInfo ZPInfoTable[] = {
{ 0, "ptr1+1", REG_PTR1_HI, REG_PTR1 },
{ 0, "ptr2", REG_PTR2_LO, REG_PTR2 },
{ 0, "ptr2+1", REG_PTR2_HI, REG_PTR2 },
{ 4, "ptr3", REG_NONE, REG_NONE },
{ 4, "ptr4", REG_NONE, REG_NONE },
{ 7, "regbank", REG_NONE, REG_NONE },
{ 4, "ptr3", REG_NONE, REG_NONE },
{ 4, "ptr4", REG_NONE, REG_NONE },
{ 7, "regbank", REG_NONE, REG_NONE },
{ 0, "regsave", REG_SAVE_LO, REG_SAVE },
{ 0, "regsave+1", REG_SAVE_HI, REG_SAVE },
{ 2, "sp", REG_NONE, REG_NONE },
{ 0, "sp", REG_SP_LO, REG_SP },
{ 0, "sp+1", REG_SP_HI, REG_SP },
{ 0, "sreg", REG_SREG_LO, REG_SREG },
{ 0, "sreg+1", REG_SREG_HI, REG_SREG },
{ 0, "tmp1", REG_TMP1, REG_TMP1 },
{ 0, "tmp2", REG_NONE, REG_NONE },
{ 0, "tmp3", REG_NONE, REG_NONE },
{ 0, "tmp4", REG_NONE, REG_NONE },
{ 0, "tmp1", REG_TMP1, REG_TMP1 },
{ 0, "tmp2", REG_NONE, REG_NONE },
{ 0, "tmp3", REG_NONE, REG_NONE },
{ 0, "tmp4", REG_NONE, REG_NONE },
};
#define ZPInfoCount (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0]))
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@ -395,7 +399,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
unsigned U2;
U1 = GetRegInfo2 (S, E->JumpTo->Owner, -1, Visited, Used, Unused, Wanted);
if (U1 == REG_AXY) {
if (U1 == REG_ALL) {
/* All registers used, no need for second call */
return REG_AXY;
}
@ -434,7 +438,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
}
static unsigned GetRegInfo1 (CodeSeg* S,
CodeEntry* E,
int Index,

View File

@ -68,17 +68,21 @@ struct CodeSeg;
#define REG_SREG_HI 0x0200U
#define REG_SAVE_LO 0x0400U
#define REG_SAVE_HI 0x0800U
#define REG_SP_LO 0x1000U
#define REG_SP_HI 0x2000U
/* Combined register defines */
#define REG_PTR1 (REG_PTR1_LO | REG_PTR1_HI)
#define REG_PTR2 (REG_PTR2_LO | REG_PTR2_HI)
#define REG_SREG (REG_SREG_LO | REG_SREG_HI)
#define REG_SAVE (REG_SAVE_LO | REG_SAVE_HI)
#define REG_SP (REG_SP_LO | REG_SP_HI)
#define REG_AX (REG_A | REG_X)
#define REG_AY (REG_A | REG_Y)
#define REG_XY (REG_X | REG_Y)
#define REG_AXY (REG_AX | REG_Y)
#define REG_EAX (REG_AX | REG_SREG)
#define REG_EAX (REG_AX | REG_SREG)
#define REG_EAXY (REG_EAX | REG_Y)
#define REG_ZP 0xFFF8U
#define REG_ALL 0xFFFFU

View File

@ -47,6 +47,7 @@
#include "codeent.h"
#include "codeinfo.h"
#include "coptind.h"
#include "coptstop.h"
#include "error.h"
#include "global.h"
#include "codeopt.h"
@ -1005,7 +1006,7 @@ static unsigned OptCmp2 (CodeSeg* S)
/* Return the number of changes made */
return Changes;
}
}
@ -1301,25 +1302,25 @@ static unsigned OptCmp7 (CodeSeg* S)
/* Evaluate the branch condition */
int Cond;
switch (GetBranchCond (N->OPC)) {
case BC_CC:
Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
break;
switch (GetBranchCond (N->OPC)) {
case BC_CC:
Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
break;
case BC_CS:
Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
break;
case BC_CS:
Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
break;
case BC_EQ:
Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
break;
case BC_EQ:
Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
break;
case BC_MI:
case BC_MI:
Cond = ((signed char)RegVal) < ((signed char)E->Num);
break;
break;
case BC_NE:
Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
case BC_NE:
Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
break;
case BC_PL:
@ -1328,7 +1329,17 @@ static unsigned OptCmp7 (CodeSeg* S)
case BC_VC:
case BC_VS:
}
/* Not set by the compare operation, bail out (Note:
* Just skipping anything here is rather stupid, but
* the sequence is never generated by the compiler,
* so it's quite safe to skip).
*/
goto NextEntry;
default:
Internal ("Unknown branch condition");
}
/* If the condition is false, we may remove the jump. Otherwise
* the branch will always be taken, so we may replace it by a
@ -1355,7 +1366,8 @@ static unsigned OptCmp7 (CodeSeg* S)
}
/* Next entry */
NextEntry:
/* Next entry */
++I;
}
@ -2709,6 +2721,8 @@ static OptFunc OptFuncs [] = {
OptEntry (OptDuplicateLoads, optMain),
OptEntry (OptStoreLoad, optMain),
OptEntry (OptTransfers, optMain),
/* Optimize operations that use the stack to pass operands */
OptEntry (OptStackOps, optMain),
/* Optimize branch distance */
OptEntry (OptBranchDist, optPost),
};

View File

@ -38,12 +38,13 @@
/* cc65 */
#include "codeseg.h"
/*****************************************************************************/
/* Code */
/* Code */
/*****************************************************************************/

299
src/cc65/coptstop.c Normal file
View File

@ -0,0 +1,299 @@
/*****************************************************************************/
/* */
/* coptstop.c */
/* */
/* Optimize operations that take operands via the stack */
/* */
/* */
/* */
/* (C) 2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
/* cc65 */
#include "codeent.h"
#include "codeinfo.h"
#include "codeopt.h"
#include "error.h"
#include "coptstop.h"
/*****************************************************************************/
/* Helpers */
/*****************************************************************************/
static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add)
/* Optimize the tosaddax sequence if possible */
{
unsigned I;
CodeEntry* N;
CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* AddEntry;
const char* ZPLo;
const char* ZPHi;
/* Check if the sequence is safe. This means that there may not be any
* jumps between the two data points, and no usage of the stack. Handling
* these conditions is possible and may be done later.
*/
unsigned UsedRegs = REG_NONE;
for (I = Push + 1; I < Add; ++I) {
CodeEntry* E = CS_GetEntry (S, I);
if ((E->Info & OF_BRA) != 0 ||
(E->Use & REG_SP) != 0 ||
CE_HasLabel (E)) {
/* A jump or stack pointer usage - bail out */
return 0;
}
UsedRegs |= (E->Use | E->Chg);
}
/* We prefer usage of sreg for the intermediate value, since sreg is
* tracked and optimized.
*/
UsedRegs |= GetRegInfo (S, Push+1, REG_ALL);
if ((UsedRegs & REG_SREG) == REG_NONE) {
/* SREG is available */
ZPLo = "sreg";
ZPHi = "sreg+1";
} else if ((UsedRegs & REG_PTR1) == REG_NONE) {
ZPLo = "ptr1";
ZPHi = "ptr1+1";
} else if ((UsedRegs & REG_PTR2) == REG_NONE) {
ZPLo = "ptr2";
ZPHi = "ptr2+1";
} else {
/* No registers available */
return 0;
}
/* We need the entry behind the add */
if ((N = CS_GetNextEntry (S, Add)) == 0) {
/* Unavailable */
return 0;
}
/* Generate register info */
CS_GenRegInfo (S);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Store the value into sreg instead of pushing it */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+2);
/* Correct the index of the add and get a pointer to the entry */
Add += 2;
AddEntry = CS_GetEntry (S, Add);
/* Inline the add */
X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+1);
X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+2);
if (PushEntry->RI->In.RegX == 0 && AddEntry->RI->In.RegX == 0) {
/* The high byte is zero on entry */
CodeLabel* L = CS_GenLabel (S, N);
X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI);
CS_InsertEntry (S, X, Add+3);
X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+4);
} else {
/* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+3);
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+4);
X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPHi, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+5);
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+6);
X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, AddEntry->LI);
CS_InsertEntry (S, X, Add+7);
}
/* Remove the push and the call to the tosaddax function */
CS_DelEntry (S, Add);
CS_DelEntry (S, Push);
/* Free the register info */
CS_FreeRegInfo (S);
/* We changed the sequence */
return 1;
}
static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store)
/* Optimize the staspidx sequence if possible */
{
unsigned I;
CodeEntry* N;
CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* StoreEntry;
const char* ZPLo;
const char* ZPHi;
/* Check if the sequence is safe. This means that there may not be any
* jumps between the two data points, and no usage of the stack. Handling
* these conditions is possible and may be done later.
*/
unsigned UsedRegs = REG_NONE;
for (I = Push + 1; I < Store; ++I) {
CodeEntry* E = CS_GetEntry (S, I);
if ((E->Info & OF_BRA) != 0 ||
(E->Use & REG_SP) != 0 ||
CE_HasLabel (E)) {
/* A jump or stack pointer usage - bail out */
return 0;
}
UsedRegs |= (E->Use | E->Chg);
}
/* We prefer usage of sreg for the intermediate value, since sreg is
* tracked and optimized.
*/
UsedRegs |= GetRegInfo (S, Push+1, REG_SREG | REG_PTR1 | REG_PTR2);
if ((UsedRegs & REG_SREG) == REG_NONE) {
/* SREG is available */
ZPLo = "sreg";
ZPHi = "sreg+1";
} else if ((UsedRegs & REG_PTR1) == REG_NONE) {
ZPLo = "ptr1";
ZPHi = "ptr1+1";
} else if ((UsedRegs & REG_PTR2) == REG_NONE) {
ZPLo = "ptr2";
ZPHi = "ptr2+1";
} else {
/* No registers available */
return 0;
}
/* We need the entry behind the store */
if ((N = CS_GetNextEntry (S, Store)) == 0) {
/* Unavailable */
return 0;
}
/* Generate register info */
CS_GenRegInfo (S);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Store the value into sreg instead of pushing it */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+2);
/* Correct the index of the store and get a pointer to the entry */
Store += 2;
StoreEntry = CS_GetEntry (S, Store);
/* Inline the store */
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI);
CS_InsertEntry (S, X, Store+1);
/* Remove the push and the call to the staspidx function */
CS_DelEntry (S, Store);
CS_DelEntry (S, Push);
/* Free the register info */
CS_FreeRegInfo (S);
/* We changed the sequence */
return 1;
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned OptStackOps (CodeSeg* S)
/* Optimize operations that take operands via the stack */
{
unsigned Changes = 0; /* Number of changes in one run */
int LastPush = -1; /* Last call to pushax */
/* Walk over all entries */
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
/* Get the next entry */
CodeEntry* E = CS_GetEntry (S, I);
/* Check for a subroutine call */
if (E->OPC == OP65_JSR) {
/* We look for two things: A call to pushax, and a call to one
* of the known functions we're going to replace. We're only
* interested in the latter ones, if we had a push before.
*/
if (strcmp (E->Arg, "pushax") == 0) {
/* Just remember it */
LastPush = I;
} else if (LastPush >= 0) {
if (strcmp (E->Arg, "tosaddax") == 0) {
Changes += Opt_tosaddax (S, LastPush, I);
LastPush = -1;
} else if (strcmp (E->Arg, "staspidx") == 0) {
Changes += Opt_staspidx (S, LastPush, I);
LastPush = -1;
}
}
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}

61
src/cc65/coptstop.h Normal file
View File

@ -0,0 +1,61 @@
/*****************************************************************************/
/* */
/* coptstop.h */
/* */
/* Optimize operations that take operands via the stack */
/* */
/* */
/* */
/* (C) 2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef COPTSTOP_H
#define COPTSTOP_H
/* cc65 */
#include "codeseg.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned OptStackOps (CodeSeg* S);
/* Optimize operations that take operands via the stack */
/* End of coptstop.h */
#endif

View File

@ -34,6 +34,7 @@ OBJS = anonname.o \
codeseg.o \
compile.o \
coptind.o \
coptstop.o \
cpu.o \
dataseg.o \
datatype.o \
@ -105,3 +106,4 @@ depend dep: $(OBJS:.o=.c)
$(CC) -I$(COMMON) -MM $^ > .depend

View File

@ -79,6 +79,7 @@ OBJS = anonname.obj \
codeseg.obj \
compile.obj \
coptind.obj \
coptstop.obj \
cpu.obj \
dataseg.obj \
datatype.obj \
@ -148,6 +149,7 @@ FILE codeopt.obj
FILE codeseg.obj
FILE compile.obj
FILE coptind.obj
FILE coptstop.obj
FILE cpu.obj
FILE dataseg.obj
FILE datatype.obj