New/changed optimizations

git-svn-id: svn://svn.cc65.org/cc65/trunk@1443 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz
2002-10-05 20:32:31 +00:00
parent 3f1eba36f3
commit 7ce4196829
7 changed files with 461 additions and 380 deletions

View File

@@ -1425,6 +1425,7 @@ static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 100, 0,
static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptPush1 = { OptPush1, "OptPush1", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptPush1 = { OptPush1, "OptPush1", 65, 0, 0, 0, 0, 0 };
static OptFunc DOptPushPop = { OptPushPop, "OptPushPop", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptShift1 = { OptShift1, "OptShift1", 100, 0, 0, 0, 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 DOptShift2 = { OptShift2, "OptShift2", 100, 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 };*/
@@ -1478,6 +1479,7 @@ static OptFunc* OptFuncs[] = {
&DOptPtrStore1, &DOptPtrStore1,
&DOptPtrStore2, &DOptPtrStore2,
&DOptPush1, &DOptPush1,
&DOptPushPop,
&DOptRTS, &DOptRTS,
&DOptRTSJumps1, &DOptRTSJumps1,
&DOptRTSJumps2, &DOptRTSJumps2,
@@ -1805,6 +1807,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
C += RunOptFunc (S, &DOptDupLoads, 1); C += RunOptFunc (S, &DOptDupLoads, 1);
C += RunOptFunc (S, &DOptStoreLoad, 1); C += RunOptFunc (S, &DOptStoreLoad, 1);
C += RunOptFunc (S, &DOptTransfers, 1); C += RunOptFunc (S, &DOptTransfers, 1);
C += RunOptFunc (S, &DOptPushPop, 1);
Changes += C; Changes += C;

View File

@@ -594,6 +594,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index)
/* Delete an entry from the code segment. This includes moving any associated /* Delete an entry from the code segment. This includes moving any associated
* labels, removing references to labels and even removing the referenced labels * labels, removing references to labels and even removing the referenced labels
* if the reference count drops to zero. * if the reference count drops to zero.
* Note: Labels are moved forward if possible, that is, they are moved to the
* next insn (not the preceeding one).
*/ */
{ {
/* Get the code entry for the given index */ /* Get the code entry for the given index */

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2001 Ullrich von Bassewitz */ /* (C) 2001-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@@ -112,6 +112,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index);
/* Delete an entry from the code segment. This includes moving any associated /* Delete an entry from the code segment. This includes moving any associated
* labels, removing references to labels and even removing the referenced labels * labels, removing references to labels and even removing the referenced labels
* if the reference count drops to zero. * if the reference count drops to zero.
* Note: Labels are moved forward if possible, that is, they are moved to the
* next insn (not the preceeding one).
*/ */
void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count); void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count);

View File

@@ -49,20 +49,27 @@
unsigned OptAdd1 (CodeSeg* S) unsigned OptAdd1 (CodeSeg* S)
/* Search for the sequence /* Search for the sequence
* *
* ldy #xx
* jsr ldaxysp
* jsr pushax * jsr pushax
* ldy xxx * ldy #yy
* ldx #$00 * jsr ldaxysp
* lda (sp),y
* jsr tosaddax * jsr tosaddax
* *
* and replace it by: * and replace it by:
* *
* ldy xxx-2 * ldy #xx-1
* lda (sp),y
* clc * clc
* ldy #yy-3
* adc (sp),y * adc (sp),y
* bcc L * pha
* inx * ldy #xx
* L: * lda (sp),y
* ldy #yy-2
* adc (sp),y
* tax
* pla
*/ */
{ {
unsigned Changes = 0; unsigned Changes = 0;
@@ -71,58 +78,78 @@ unsigned OptAdd1 (CodeSeg* S)
unsigned I = 0; unsigned I = 0;
while (I < CS_GetEntryCount (S)) { while (I < CS_GetEntryCount (S)) {
CodeEntry* L[5]; CodeEntry* L[6];
/* Get next entry */ /* Get next entry */
CodeEntry* E = CS_GetEntry (S, I); L[0] = CS_GetEntry (S, I);
/* Check for the sequence */ /* Check for the sequence */
if (CE_IsCall (E, "pushax") && if (L[0]->OPC == OP65_LDY &&
CS_GetEntries (S, L, I+1, 5) &&
L[0]->OPC == OP65_LDY &&
CE_KnownImm (L[0]) && CE_KnownImm (L[0]) &&
!CE_HasLabel (L[0]) && !CS_RangeHasLabel (S, I+1, 5) &&
L[1]->OPC == OP65_LDX && CS_GetEntries (S, L+1, I+1, 5) &&
CE_KnownImm (L[1]) && CE_IsCall (L[1], "ldaxysp") &&
L[1]->Num == 0 && CE_IsCall (L[2], "pushax") &&
!CE_HasLabel (L[1]) && L[3]->OPC == OP65_LDY &&
L[2]->OPC == OP65_LDA && CE_KnownImm (L[3]) &&
!CE_HasLabel (L[2]) && CE_IsCall (L[4], "ldaxysp") &&
CE_IsCall (L[3], "tosaddax") && CE_IsCall (L[5], "tosaddax")) {
!CE_HasLabel (L[3])) {
CodeEntry* X; CodeEntry* X;
CodeLabel* Label; const char* Arg;
/* Remove the call to pushax */ /* Correct the stack of the first Y register load */
CS_DelEntry (S, I); CE_SetNumArg (L[0], L[0]->Num - 1);
/* Correct the stack offset (needed since pushax was removed) */ /* lda (sp),y */
CE_SetNumArg (L[0], L[0]->Num - 2); X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
/* Add the clc . */
X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
CS_InsertEntry (S, X, I+1); CS_InsertEntry (S, X, I+1);
/* Remove the load */ /* clc */
CS_DelEntry (S, I+3); /* lda */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI);
CS_DelEntry (S, I+2); /* ldx */
/* Add the adc */
X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
CS_InsertEntry (S, X, I+2); CS_InsertEntry (S, X, I+2);
/* Generate the branch label and the branch */ /* ldy #yy-3 */
Label = CS_GenLabel (S, L[4]); Arg = MakeHexArg (L[3]->Num - 3);
X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
CS_InsertEntry (S, X, I+3); CS_InsertEntry (S, X, I+3);
/* Generate the increment of the high byte */ /* adc (sp),y */
X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI); X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
CS_InsertEntry (S, X, I+4); CS_InsertEntry (S, X, I+4);
/* Delete the call to tosaddax */ /* pha */
CS_DelEntry (S, I+5); X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[5]->LI);
CS_InsertEntry (S, X, I+5);
/* ldy #xx (beware: L[0] has changed) */
Arg = MakeHexArg (L[0]->Num + 1);
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
CS_InsertEntry (S, X, I+6);
/* lda (sp),y */
X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
CS_InsertEntry (S, X, I+7);
/* ldy #yy-2 */
Arg = MakeHexArg (L[3]->Num - 2);
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
CS_InsertEntry (S, X, I+8);
/* adc (sp),y */
X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
CS_InsertEntry (S, X, I+9);
/* tax */
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[5]->LI);
CS_InsertEntry (S, X, I+10);
/* pla */
X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[5]->LI);
CS_InsertEntry (S, X, I+11);
/* Delete the old code */
CS_DelEntries (S, I+12, 5);
/* Remember, we had changes */ /* Remember, we had changes */
++Changes; ++Changes;

View File

@@ -1054,9 +1054,9 @@ unsigned OptTransfers (CodeSeg* S)
(N->Info & OF_XFR) != 0) { (N->Info & OF_XFR) != 0) {
/* Check if it's a transfer and back */ /* Check if it's a transfer and back */
if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) || if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+1)) ||
(E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) || (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+1)) ||
(E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) || (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+1)) ||
(E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+1))) { (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+1))) {
/* If the next insn is a conditional branch, check if the insn /* If the next insn is a conditional branch, check if the insn
@@ -1099,6 +1099,71 @@ NextEntry:
unsigned OptPushPop (CodeSeg* S)
/* Remove a PHA/PLA sequence were A is not used later */
{
unsigned Changes = 0;
/* Walk over the entries */
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
CodeEntry* N;
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
/* Check if it is a PLA instruction that does not have a label and
* where the register value is not used later and that is not followed
* by a conditional branch.
*/
if (E->OPC == OP65_PLA &&
!CE_HasLabel (E) &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_CBRA) == 0 &&
!RegAUsed (S, I+1)) {
/* Search back until we find the matching PHA instruction. If we
* find a label or another PLA somewhere in between, bail out
* since this may have side effects.
*/
unsigned J = I;
while (J-- > 0) {
/* Get the previous entry */
CodeEntry* P = CS_GetEntry (S, J);
/* Check this entry */
if (P->OPC == OP65_PHA) {
/* Found the matching push, remove both */
CS_DelEntry (S, I);
CS_DelEntry (S, J);
/* Remember that we had changes and bail out */
++Changes;
break;
} else if (CE_HasLabel (P) || P->OPC == OP65_PLA) {
/* OOPS - too dangerous! */
break;
}
}
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/ /*****************************************************************************/
/* Optimize branch types */ /* Optimize branch types */
/*****************************************************************************/ /*****************************************************************************/

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2001 Ullrich von Bassewitz */ /* (C) 2001-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@@ -105,6 +105,9 @@ unsigned OptStoreLoad (CodeSeg* S);
unsigned OptTransfers (CodeSeg* S); unsigned OptTransfers (CodeSeg* S);
/* Remove transfers from one register to another and back */ /* Remove transfers from one register to another and back */
unsigned OptPushPop (CodeSeg* S);
/* Remove a PHA/PLA sequence were A is not used later */
unsigned OptBranchDist (CodeSeg* S); unsigned OptBranchDist (CodeSeg* S);
/* Change branches for the distance needed. */ /* Change branches for the distance needed. */

View File

@@ -50,6 +50,22 @@
/* Structure that holds the needed data */
typedef struct StackOpData StackOpData;
struct StackOpData {
CodeSeg* Code; /* Pointer to code segment */
unsigned Flags; /* Flags to remember things */
unsigned PushIndex; /* Index of call to pushax in codeseg */
unsigned OpIndex; /* Index of actual operation */
CodeEntry* PrevEntry; /* Entry before the call to pushax */
CodeEntry* PushEntry; /* Pointer to entry with call to pushax */
CodeEntry* OpEntry; /* Pointer to entry with op */
CodeEntry* NextEntry; /* Entry after the op */
const char* ZPLo; /* Lo byte of zero page loc to use */
const char* ZPHi; /* Hi byte of zero page loc to use */
unsigned IP; /* Insertion point used by some routines */
};
/* Flags returned by DirectOp */ /* Flags returned by DirectOp */
#define OP_DIRECT 0x01 /* Direct op may be used */ #define OP_DIRECT 0x01 /* Direct op may be used */
#define OP_ONSTACK 0x02 /* Operand is on stack */ #define OP_ONSTACK 0x02 /* Operand is on stack */
@@ -123,26 +139,149 @@ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop,
static unsigned DirectOp (CodeEntry* E) static void InsertEntry (StackOpData* D, CodeEntry* E, unsigned Index)
/* Insert a new entry. Depending on Index, D->PushIndex and D->OpIndex will
* be adjusted by this function.
*/
{
/* Insert the entry into the code segment */
CS_InsertEntry (D->Code, E, Index);
/* Adjust the indices if necessary */
if (D->PushEntry && Index <= D->PushIndex) {
++D->PushIndex;
}
if (D->OpEntry && Index <= D->OpIndex) {
++D->OpIndex;
}
}
static void DelEntry (StackOpData* D, unsigned Index)
/* Delete an entry. Depending on Index, D->PushIndex and D->OpIndex will be
* adjusted by this function, and PushEntry/OpEntry may get invalidated.
*/
{
/* Delete the entry from the code segment */
CS_DelEntry (D->Code, Index);
/* Adjust the indices if necessary */
if (Index < D->PushIndex) {
--D->PushIndex;
} else if (Index == D->PushIndex) {
D->PushEntry = 0;
}
if (Index < D->OpIndex) {
--D->OpIndex;
} else if (Index == D->OpIndex) {
D->OpEntry = 0;
}
}
static void CheckDirectOp (StackOpData* D)
/* Check if the given entry is a lda instruction with an addressing mode /* Check if the given entry is a lda instruction with an addressing mode
* that allows us to replace it by another operation (like ora). If so, we may * that allows us to replace it by another operation (like ora). If so, we may
* use this location for the or and must not save the value in the zero * use this location for the or and must not save the value in the zero
* page location. * page location.
*/ */
{ {
unsigned Flags = 0; /* We need the entry before the push */
CodeEntry* E;
CHECK ((E = D->PrevEntry) != 0);
if (E->OPC == OP65_LDA) { if (E->OPC == OP65_LDA) {
if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) {
/* These insns are all ok and replaceable */ /* These insns are all ok and replaceable */
Flags |= OP_DIRECT; D->Flags |= OP_DIRECT;
} else if (E->AM == AM65_ZP_INDY && } else if (E->AM == AM65_ZP_INDY &&
E->RI->In.RegY >= 0 && E->RI->In.RegY >= 0 &&
strcmp (E->Arg, "sp") == 0) { (E->Use & REG_SP) != 0) {
/* Load from stack with known offset is also ok */ /* Load from stack with known offset is also ok */
Flags |= (OP_DIRECT | OP_ONSTACK); D->Flags |= (OP_DIRECT | OP_ONSTACK);
} }
} }
return Flags; }
static void ReplacePushByStore (StackOpData* D)
/* Replace the call to the push subroutine by a store into the zero page
* location (actually, the push is not replaced, because we need it for
* later, but the name is still ok since the push will get removed at the
* end of each routine.
*/
{
CodeEntry* X;
/* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STX, AM65_ZP, D->ZPHi, 0, D->PushEntry->LI);
InsertEntry (D, X, D->PushIndex+1);
if ((D->Flags & OP_DIRECT) == 0) {
X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPLo, 0, D->PushEntry->LI);
InsertEntry (D, X, D->PushIndex+1);
}
}
static void AddOpLow (StackOpData* D, opc_t OPC)
/* Add an op for the low byte of an operator. This function honours the
* OP_DIRECT and OP_ONSTACK flags and generates the necessary instructions.
* All code is inserted at the current insertion point.
*/
{
CodeEntry* X;
if ((D->Flags & OP_DIRECT) != 0) {
/* Op with a variable location. If the location is on the stack, we
* need to reload the Y register.
*/
if ((D->Flags & OP_ONSTACK) != 0) {
const char* Arg = MakeHexArg (D->PrevEntry->RI->In.RegY);
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
}
X = NewCodeEntry (OPC, D->PrevEntry->AM, D->PrevEntry->Arg, 0, D->OpEntry->LI);
} else {
/* Op with temp storage */
X = NewCodeEntry (OPC, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
}
InsertEntry (D, X, D->IP++);
}
static void AddOpHigh (StackOpData* D, opc_t OPC)
/* Add an op for the high byte of an operator. Special cases (constant values
* or similar have to be checked separately, the function covers only the
* generic case. Code is inserted at the insertion point.
*/
{
CodeEntry* X;
/* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OPC, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OP65_LDA, AM65_ZP, D->ZPLo, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
}
static void RemovePushAndOp (StackOpData* D)
/* Remove the call to pushax and the call to the operator subroutine */
{
DelEntry (D, D->OpIndex);
DelEntry (D, D->PushIndex);
} }
@@ -153,34 +292,20 @@ static unsigned DirectOp (CodeEntry* E)
static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store, static unsigned Opt_staspidx (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the staspidx sequence if possible */ /* Optimize the staspidx sequence if possible */
{ {
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* StoreEntry;
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI); ReplacePushByStore (D);
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 */ /* Replace the store subroutine call by a direct op */
Store += 2; X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
StoreEntry = CS_GetEntry (S, Store); InsertEntry (D, X, D->OpIndex+1);
/* 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 */ /* Remove the push and the call to the staspidx function */
CS_DelEntry (S, Store); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -188,47 +313,33 @@ static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store,
static unsigned Opt_staxspidx (CodeSeg* S, unsigned Push, unsigned Store, static unsigned Opt_staxspidx (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the staxspidx sequence if possible */ /* Optimize the staxspidx sequence if possible */
{ {
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* StoreEntry;
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI); ReplacePushByStore (D);
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 */ /* Inline the store */
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI); X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Store+1); InsertEntry (D, X, D->OpIndex+1);
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, StoreEntry->LI); X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Store+2); InsertEntry (D, X, D->OpIndex+2);
if (StoreEntry->RI->In.RegX >= 0) { if (D->OpEntry->RI->In.RegX >= 0) {
/* Value of X is known */ /* Value of X is known */
const char* Arg = MakeHexArg (StoreEntry->RI->In.RegX); const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX);
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, StoreEntry->LI); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
} else { } else {
/* Value unknown */ /* Value unknown */
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, StoreEntry->LI); X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
} }
CS_InsertEntry (S, X, Store+3); InsertEntry (D, X, D->OpIndex+3);
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI); X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Store+4); InsertEntry (D, X, D->OpIndex+4);
/* Remove the push and the call to the staspidx function */ /* Remove the push and the call to the staspidx function */
CS_DelEntry (S, Store); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -236,106 +347,65 @@ static unsigned Opt_staxspidx (CodeSeg* S, unsigned Push, unsigned Store,
static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add, static unsigned Opt_tosaddax (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the tosaddax sequence if possible */ /* Optimize the tosaddax sequence if possible */
{ {
CodeEntry* P;
CodeEntry* N;
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* AddEntry;
unsigned Flags;
/* We need the entry behind the add */ /* We need the entry behind the add */
CHECK ((N = CS_GetNextEntry (S, Add)) != 0); CHECK (D->NextEntry != 0);
/* And the entry before the push */
CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Check the entry before the push. If it's a lda instruction with an /* Check the entry before the push. If it's a lda instruction with an
* addressing mode that allows us to replace it, we may use this * addressing mode that allows us to replace it, we may use this
* location for the op and must not save the value in the zero page * location for the op and must not save the value in the zero page
* location. * location.
*/ */
Flags = DirectOp (P); CheckDirectOp (D);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); ReplacePushByStore (D);
CS_InsertEntry (S, X, Push+1);
++Add; /* Correct the index */
if ((Flags & OP_DIRECT) == 0) {
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
++Add; /* Correct the index */
}
/* Get a pointer to the add entry */
AddEntry = CS_GetEntry (S, Add);
/* Inline the add */ /* Inline the add */
X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI); D->IP = D->OpIndex+1;
CS_InsertEntry (S, X, Add+1); X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, D->OpEntry->LI);
if ((Flags & OP_DIRECT) != 0) { InsertEntry (D, X, D->IP++);
/* Add a variable location. If the location is on the stack, we
* need to reload the Y register. /* Low byte */
*/ AddOpLow (D, OP65_ADC);
if ((Flags & OP_ONSTACK) != 0) {
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, AddEntry->LI); /* High byte */
CS_InsertEntry (S, X, Add); if (D->PushEntry->RI->In.RegX == 0) {
++Add;
}
X = NewCodeEntry (OP65_ADC, P->AM, P->Arg, 0, AddEntry->LI);
} else {
/* Add from temp storage */
X = NewCodeEntry (OP65_ADC, AM65_ZP, ZPLo, 0, AddEntry->LI);
}
CS_InsertEntry (S, X, Add+2);
if (PushEntry->RI->In.RegX == 0) {
/* The high byte is the value in X plus the carry */ /* The high byte is the value in X plus the carry */
CodeLabel* L = CS_GenLabel (S, N); CodeLabel* L = CS_GenLabel (D->Code, D->NextEntry);
X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI); X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI);
CS_InsertEntry (S, X, Add+3); InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI); X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Add+4); InsertEntry (D, X, D->IP++);
} else if (AddEntry->RI->In.RegX == 0) { } else if (D->OpEntry->RI->In.RegX == 0) {
/* The high byte is that of the first operand plus carry */ /* The high byte is that of the first operand plus carry */
CodeLabel* L; CodeLabel* L;
if (PushEntry->RI->In.RegX >= 0) { if (D->PushEntry->RI->In.RegX >= 0) {
/* Value of first op high byte is known */ /* Value of first op high byte is known */
const char* Arg = MakeHexArg (PushEntry->RI->In.RegX); const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX);
X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, AddEntry->LI); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
} else { } else {
/* Value of first op high byte is unknown */ /* Value of first op high byte is unknown */
X = NewCodeEntry (OP65_LDX, AM65_ZP, ZPHi, 0, AddEntry->LI); X = NewCodeEntry (OP65_LDX, AM65_ZP, D->ZPHi, 0, D->OpEntry->LI);
} }
CS_InsertEntry (S, X, Add+3); InsertEntry (D, X, D->IP++);
L = CS_GenLabel (S, N); L = CS_GenLabel (D->Code, D->NextEntry);
X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI); X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI);
CS_InsertEntry (S, X, Add+4); InsertEntry (D, X, D->IP++);
X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI); X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Add+5); InsertEntry (D, X, D->IP++);
} else { } else {
/* High byte is unknown */ /* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AddEntry->LI); AddOpHigh (D, OP65_ADC);
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 */ /* Remove the push and the call to the tosaddax function */
CS_DelEntry (S, Add); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -343,79 +413,37 @@ static unsigned Opt_tosaddax (CodeSeg* S, unsigned Push, unsigned Add,
static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And, static unsigned Opt_tosandax (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the tosandax sequence if possible */ /* Optimize the tosandax sequence if possible */
{ {
CodeEntry* P;
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* AndEntry;
unsigned Flags;
/* Get the entry before the push */
CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Check the entry before the push. If it's a lda instruction with an /* Check the entry before the push. If it's a lda instruction with an
* addressing mode that allows us to replace it, we may use this * addressing mode that allows us to replace it, we may use this
* location for the op and must not save the value in the zero page * location for the op and must not save the value in the zero page
* location. * location.
*/ */
Flags = DirectOp (P); CheckDirectOp (D);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); ReplacePushByStore (D);
CS_InsertEntry (S, X, Push+1);
++And; /* Correct the index */
if ((Flags & OP_DIRECT) == 0) {
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
++And; /* Correct the index */
}
/* Get a pointer to the and entry */ /* Inline the and, low byte */
AndEntry = CS_GetEntry (S, And); D->IP = D->OpIndex + 1;
AddOpLow (D, OP65_AND);
/* Inline the and */ /* High byte */
if ((Flags & OP_DIRECT) != 0) { if (D->PushEntry->RI->In.RegX == 0 || D->OpEntry->RI->In.RegX == 0) {
/* And with variable location. If the location is on the stack, we
* need to reload the Y register.
*/
if ((Flags & OP_ONSTACK) != 0) {
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, AndEntry->LI);
CS_InsertEntry (S, X, And);
++And;
}
X = NewCodeEntry (OP65_AND, P->AM, P->Arg, 0, AndEntry->LI);
} else {
/* And with temp storage */
X = NewCodeEntry (OP65_AND, AM65_ZP, ZPLo, 0, AndEntry->LI);
}
CS_InsertEntry (S, X, And+1);
if (PushEntry->RI->In.RegX == 0 || AndEntry->RI->In.RegX == 0) {
/* The high byte is zero */ /* The high byte is zero */
X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, AndEntry->LI); X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI);
CS_InsertEntry (S, X, And+2); InsertEntry (D, X, D->IP++);
} else { } else {
/* High byte is unknown */ /* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AndEntry->LI); AddOpHigh (D, OP65_AND);
CS_InsertEntry (S, X, And+2);
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, AndEntry->LI);
CS_InsertEntry (S, X, And+3);
X = NewCodeEntry (OP65_AND, AM65_ZP, ZPHi, 0, AndEntry->LI);
CS_InsertEntry (S, X, And+4);
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, AndEntry->LI);
CS_InsertEntry (S, X, And+5);
X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, AndEntry->LI);
CS_InsertEntry (S, X, And+6);
} }
/* Remove the push and the call to the tosandax function */ /* Remove the push and the call to the tosandax function */
CS_DelEntry (S, And); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -423,80 +451,38 @@ static unsigned Opt_tosandax (CodeSeg* S, unsigned Push, unsigned And,
static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or, static unsigned Opt_tosorax (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the tosorax sequence if possible */ /* Optimize the tosorax sequence if possible */
{ {
CodeEntry* P;
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* OrEntry;
unsigned Flags;
/* Get the entry before the push */
CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Check the entry before the push. If it's a lda instruction with an /* Check the entry before the push. If it's a lda instruction with an
* addressing mode that allows us to replace it, we may use this * addressing mode that allows us to replace it, we may use this
* location for the op and must not save the value in the zero page * location for the op and must not save the value in the zero page
* location. * location.
*/ */
Flags = DirectOp (P); CheckDirectOp (D);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); ReplacePushByStore (D);
CS_InsertEntry (S, X, Push+1);
++Or; /* Correct the index */
if ((Flags & OP_DIRECT) == 0) {
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
++Or; /* Correct the index */
}
/* Get a pointer to the or entry */ /* Inline the or, low byte */
OrEntry = CS_GetEntry (S, Or); D->IP = D->OpIndex + 1;
AddOpLow (D, OP65_ORA);
/* Inline the or */ /* High byte */
if ((Flags & OP_DIRECT) != 0) { if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) {
/* Or with variable location. If the location is on the stack, we
* need to reload the Y register.
*/
if ((Flags & OP_ONSTACK) != 0) {
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, OrEntry->LI);
CS_InsertEntry (S, X, Or);
++Or;
}
X = NewCodeEntry (OP65_ORA, P->AM, P->Arg, 0, OrEntry->LI);
} else {
/* Or with temp storage */
X = NewCodeEntry (OP65_ORA, AM65_ZP, ZPLo, 0, OrEntry->LI);
}
CS_InsertEntry (S, X, Or+1);
if (PushEntry->RI->In.RegX >= 0 && OrEntry->RI->In.RegX >= 0) {
/* Both values known, precalculate the result */ /* Both values known, precalculate the result */
const char* Arg = MakeHexArg (PushEntry->RI->In.RegX | OrEntry->RI->In.RegX); const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX | D->OpEntry->RI->In.RegX);
X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, OrEntry->LI); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Or+2); InsertEntry (D, X, D->IP++);
} else if (PushEntry->RI->In.RegX != 0) { } else if (D->PushEntry->RI->In.RegX != 0) {
/* High byte is unknown */ /* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, OrEntry->LI); AddOpHigh (D, OP65_ORA);
CS_InsertEntry (S, X, Or+2);
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, OrEntry->LI);
CS_InsertEntry (S, X, Or+3);
X = NewCodeEntry (OP65_ORA, AM65_ZP, ZPHi, 0, OrEntry->LI);
CS_InsertEntry (S, X, Or+4);
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, OrEntry->LI);
CS_InsertEntry (S, X, Or+5);
X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, OrEntry->LI);
CS_InsertEntry (S, X, Or+6);
} }
/* Remove the push and the call to the tosorax function */ /* Remove the push and the call to the tosorax function */
CS_DelEntry (S, Or); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -504,80 +490,38 @@ static unsigned Opt_tosorax (CodeSeg* S, unsigned Push, unsigned Or,
static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor, static unsigned Opt_tosxorax (StackOpData* D)
const char* ZPLo, const char* ZPHi)
/* Optimize the tosxorax sequence if possible */ /* Optimize the tosxorax sequence if possible */
{ {
CodeEntry* P;
CodeEntry* X; CodeEntry* X;
CodeEntry* PushEntry;
CodeEntry* XorEntry;
unsigned Flags;
/* Get the entry before the push */
CHECK ((P = CS_GetPrevEntry (S, Push)) != 0);
/* Get the push entry */
PushEntry = CS_GetEntry (S, Push);
/* Check the entry before the push. If it's a lda instruction with an /* Check the entry before the push. If it's a lda instruction with an
* addressing mode that allows us to replace it, we may use this * addressing mode that allows us to replace it, we may use this
* location for the op and must not save the value in the zero page * location for the op and must not save the value in the zero page
* location. * location.
*/ */
Flags = DirectOp (P); CheckDirectOp (D);
/* Store the value into the zeropage instead of pushing it */ /* Store the value into the zeropage instead of pushing it */
X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); ReplacePushByStore (D);
CS_InsertEntry (S, X, Push+1);
++Xor; /* Correct the index */
if ((Flags & OP_DIRECT) != 0) {
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, PushEntry->LI);
CS_InsertEntry (S, X, Push+1);
++Xor; /* Correct the index */
}
/* Get a pointer to the entry */ /* Inline the xor, low byte */
XorEntry = CS_GetEntry (S, Xor); D->IP = D->OpIndex + 1;
AddOpLow (D, OP65_EOR);
/* Inline the xor */ /* High byte */
if ((Flags & OP_DIRECT) != 0) { if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) {
/* Xor with a variable location. If the location is on the stack, we
* need to reload the Y register.
*/
if ((Flags & OP_ONSTACK) != 0) {
X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (P->RI->In.RegY), 0, XorEntry->LI);
CS_InsertEntry (S, X, Xor);
++Xor;
}
X = NewCodeEntry (OP65_EOR, P->AM, P->Arg, 0, XorEntry->LI);
} else {
/* Xor with temp storage */
X = NewCodeEntry (OP65_EOR, AM65_ZP, ZPLo, 0, XorEntry->LI);
}
CS_InsertEntry (S, X, Xor+1);
if (PushEntry->RI->In.RegX >= 0 && XorEntry->RI->In.RegX >= 0) {
/* Both values known, precalculate the result */ /* Both values known, precalculate the result */
const char* Arg = MakeHexArg (PushEntry->RI->In.RegX ^ XorEntry->RI->In.RegX); const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX ^ D->OpEntry->RI->In.RegX);
X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, XorEntry->LI); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI);
CS_InsertEntry (S, X, Xor+2); InsertEntry (D, X, D->IP++);
} else if (PushEntry->RI->In.RegX != 0) { } else if (D->PushEntry->RI->In.RegX != 0) {
/* High byte is unknown */ /* High byte is unknown */
X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, XorEntry->LI); AddOpHigh (D, OP65_EOR);
CS_InsertEntry (S, X, Xor+2);
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, XorEntry->LI);
CS_InsertEntry (S, X, Xor+3);
X = NewCodeEntry (OP65_EOR, AM65_ZP, ZPHi, 0, XorEntry->LI);
CS_InsertEntry (S, X, Xor+4);
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, XorEntry->LI);
CS_InsertEntry (S, X, Xor+5);
X = NewCodeEntry (OP65_LDA, AM65_ZP, ZPLo, 0, XorEntry->LI);
CS_InsertEntry (S, X, Xor+6);
} }
/* Remove the push and the call to the tosandax function */ /* Remove the push and the call to the tosandax function */
CS_DelEntry (S, Xor); RemovePushAndOp (D);
CS_DelEntry (S, Push);
/* We changed the sequence */ /* We changed the sequence */
return 1; return 1;
@@ -598,8 +542,7 @@ typedef enum {
} STOP_FLAGS; } STOP_FLAGS;
typedef unsigned (*OptFunc) (CodeSeg* S, unsigned Push, unsigned Store, typedef unsigned (*OptFunc) (StackOpData* D);
const char* ZPLo, const char* ZPHi);
typedef struct OptFuncDesc OptFuncDesc; typedef struct OptFuncDesc OptFuncDesc;
struct OptFuncDesc { struct OptFuncDesc {
const char* Name; /* Name of the replaced runtime function */ const char* Name; /* Name of the replaced runtime function */
@@ -637,6 +580,33 @@ static const OptFuncDesc* FindFunc (const char* Name)
static int CmpHarmless (const void* Key, const void* Entry)
/* Compare function for bsearch */
{
return strcmp (Key, *(const char**)Entry);
}
static int HarmlessCall (const char* Name)
/* Check if this is a call to a harmless subroutine that will not interrupt
* the pushax/op sequence when encountered.
*/
{
static const char* Tab[] = {
"ldaxysp",
};
void* R = bsearch (Name,
Tab,
sizeof (Tab) / sizeof (Tab[0]),
sizeof (Tab[0]),
CmpHarmless);
return (R != 0);
}
/*****************************************************************************/ /*****************************************************************************/
/* Code */ /* Code */
/*****************************************************************************/ /*****************************************************************************/
@@ -652,6 +622,7 @@ unsigned OptStackOps (CodeSeg* S)
unsigned UsedRegs = 0; /* Zeropage registers used in sequence */ unsigned UsedRegs = 0; /* Zeropage registers used in sequence */
unsigned I; unsigned I;
/* Generate register info */ /* Generate register info */
CS_GenRegInfo (S); CS_GenRegInfo (S);
@@ -694,8 +665,7 @@ unsigned OptStackOps (CodeSeg* S)
const OptFuncDesc* F = FindFunc (E->Arg); const OptFuncDesc* F = FindFunc (E->Arg);
if (F) { if (F) {
const char* ZPLo = 0; StackOpData Data;
const char* ZPHi = 0;
int PreCondOk = 1; int PreCondOk = 1;
/* Check the flags */ /* Check the flags */
@@ -712,14 +682,14 @@ unsigned OptStackOps (CodeSeg* S)
UsedRegs |= GetRegInfo (S, I+1, REG_SREG | REG_PTR1 | REG_PTR2); UsedRegs |= GetRegInfo (S, I+1, REG_SREG | REG_PTR1 | REG_PTR2);
if ((UsedRegs & REG_SREG) == REG_NONE) { if ((UsedRegs & REG_SREG) == REG_NONE) {
/* SREG is available */ /* SREG is available */
ZPLo = "sreg"; Data.ZPLo = "sreg";
ZPHi = "sreg+1"; Data.ZPHi = "sreg+1";
} else if ((UsedRegs & REG_PTR1) == REG_NONE) { } else if ((UsedRegs & REG_PTR1) == REG_NONE) {
ZPLo = "ptr1"; Data.ZPLo = "ptr1";
ZPHi = "ptr1+1"; Data.ZPHi = "ptr1+1";
} else if ((UsedRegs & REG_PTR2) == REG_NONE) { } else if ((UsedRegs & REG_PTR2) == REG_NONE) {
ZPLo = "ptr2"; Data.ZPLo = "ptr2";
ZPHi = "ptr2+1"; Data.ZPHi = "ptr2+1";
} else { } else {
/* No registers available */ /* No registers available */
PreCondOk = 0; PreCondOk = 0;
@@ -730,10 +700,19 @@ unsigned OptStackOps (CodeSeg* S)
if (PreCondOk) { if (PreCondOk) {
/* Adjust stack offsets */ /* Adjust stack offsets */
unsigned Op = I + AdjustStackOffset (S, Push, I, 2); Data.OpIndex = I + AdjustStackOffset (S, Push, I, 2);
/* Prepare the remainder of the data structure */
Data.Code = S;
Data.Flags = 0;
Data.PushIndex = Push;
Data.PrevEntry = CS_GetPrevEntry (S, Data.PushIndex);
Data.PushEntry = CS_GetEntry (S, Data.PushIndex);
Data.OpEntry = E;
Data.NextEntry = CS_GetNextEntry (S, Data.OpIndex);
/* Call the optimizer function */ /* Call the optimizer function */
Changes += F->Func (S, Push, Op, ZPLo, ZPHi); Changes += F->Func (&Data);
/* Regenerate register info */ /* Regenerate register info */
CS_GenRegInfo (S); CS_GenRegInfo (S);
@@ -746,7 +725,7 @@ unsigned OptStackOps (CodeSeg* S)
/* Restart the sequence */ /* Restart the sequence */
Push = I; Push = I;
UsedRegs = REG_NONE; UsedRegs = REG_NONE;
} else { } else if (!HarmlessCall (E->Arg)) {
/* A call to an unkown subroutine ends the sequence */ /* A call to an unkown subroutine ends the sequence */
InSeq = 0; InSeq = 0;
} }