From 7ce4196829a53194a546c752dfb4239013f0b16b Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 5 Oct 2002 20:32:31 +0000 Subject: [PATCH] New/changed optimizations git-svn-id: svn://svn.cc65.org/cc65/trunk@1443 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeopt.c | 9 +- src/cc65/codeseg.c | 2 + src/cc65/codeseg.h | 4 +- src/cc65/coptadd.c | 117 +++++---- src/cc65/coptind.c | 87 ++++++- src/cc65/coptind.h | 5 +- src/cc65/coptstop.c | 621 +++++++++++++++++++++----------------------- 7 files changed, 463 insertions(+), 382 deletions(-) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index f155e4b02..5bbc46e6e 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -1013,7 +1013,7 @@ static unsigned OptDecouple (CodeSeg* S) break; case OP65_INY: - if (E->RI->In.RegY >= 0) { + if (E->RI->In.RegY >= 0) { Arg = MakeHexArg ((E->RI->In.RegY + 1) & 0xFF); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } @@ -1097,7 +1097,7 @@ static unsigned OptDecouple (CodeSeg* S) break; case OP65_TXA: - if (E->RI->In.RegX >= 0) { + if (E->RI->In.RegX >= 0) { Arg = MakeHexArg (In->RegX); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } @@ -1425,6 +1425,7 @@ static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 100, 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 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 DOptShift2 = { OptShift2, "OptShift2", 100, 0, 0, 0, 0, 0 }; /*static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 };*/ @@ -1477,7 +1478,8 @@ static OptFunc* OptFuncs[] = { &DOptPtrLoad6, &DOptPtrStore1, &DOptPtrStore2, - &DOptPush1, + &DOptPush1, + &DOptPushPop, &DOptRTS, &DOptRTSJumps1, &DOptRTSJumps2, @@ -1805,6 +1807,7 @@ static unsigned RunOptGroup3 (CodeSeg* S) C += RunOptFunc (S, &DOptDupLoads, 1); C += RunOptFunc (S, &DOptStoreLoad, 1); C += RunOptFunc (S, &DOptTransfers, 1); + C += RunOptFunc (S, &DOptPushPop, 1); Changes += C; diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index eda3ae502..530ffe205 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -594,6 +594,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index) /* Delete an entry from the code segment. This includes moving any associated * labels, removing references to labels and even removing the referenced labels * 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 */ diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index 67de3efba..c149a2dc7 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2001 Ullrich von Bassewitz */ +/* (C) 2001-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* 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 * labels, removing references to labels and even removing the referenced labels * 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); diff --git a/src/cc65/coptadd.c b/src/cc65/coptadd.c index 93d2a70fc..558dd85ab 100644 --- a/src/cc65/coptadd.c +++ b/src/cc65/coptadd.c @@ -49,20 +49,27 @@ unsigned OptAdd1 (CodeSeg* S) /* Search for the sequence * - * jsr pushax - * ldy xxx - * ldx #$00 - * lda (sp),y + * ldy #xx + * jsr ldaxysp + * jsr pushax + * ldy #yy + * jsr ldaxysp * jsr tosaddax * * and replace it by: - * - * ldy xxx-2 + * + * ldy #xx-1 + * lda (sp),y * clc + * ldy #yy-3 * adc (sp),y - * bcc L - * inx - * L: + * pha + * ldy #xx + * lda (sp),y + * ldy #yy-2 + * adc (sp),y + * tax + * pla */ { unsigned Changes = 0; @@ -71,58 +78,78 @@ unsigned OptAdd1 (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[5]; + CodeEntry* L[6]; /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); + L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (CE_IsCall (E, "pushax") && - CS_GetEntries (S, L, I+1, 5) && - L[0]->OPC == OP65_LDY && + if (L[0]->OPC == OP65_LDY && CE_KnownImm (L[0]) && - !CE_HasLabel (L[0]) && - L[1]->OPC == OP65_LDX && - CE_KnownImm (L[1]) && - L[1]->Num == 0 && - !CE_HasLabel (L[1]) && - L[2]->OPC == OP65_LDA && - !CE_HasLabel (L[2]) && - CE_IsCall (L[3], "tosaddax") && - !CE_HasLabel (L[3])) { + !CS_RangeHasLabel (S, I+1, 5) && + CS_GetEntries (S, L+1, I+1, 5) && + CE_IsCall (L[1], "ldaxysp") && + CE_IsCall (L[2], "pushax") && + L[3]->OPC == OP65_LDY && + CE_KnownImm (L[3]) && + CE_IsCall (L[4], "ldaxysp") && + CE_IsCall (L[5], "tosaddax")) { CodeEntry* X; - CodeLabel* Label; + const char* Arg; - /* Remove the call to pushax */ - CS_DelEntry (S, I); + /* Correct the stack of the first Y register load */ + CE_SetNumArg (L[0], L[0]->Num - 1); - /* Correct the stack offset (needed since pushax was removed) */ - CE_SetNumArg (L[0], L[0]->Num - 2); + /* lda (sp),y */ + X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); + CS_InsertEntry (S, X, I+1); - /* Add the clc . */ - X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); - CS_InsertEntry (S, X, I+1); - - /* Remove the load */ - CS_DelEntry (S, I+3); /* lda */ - CS_DelEntry (S, I+2); /* ldx */ - - /* Add the adc */ - X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); + /* clc */ + X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+2); - /* Generate the branch label and the branch */ - Label = CS_GenLabel (S, L[4]); - X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI); + /* ldy #yy-3 */ + Arg = MakeHexArg (L[3]->Num - 3); + X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+3); - /* Generate the increment of the high byte */ - X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI); + /* adc (sp),y */ + X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI); CS_InsertEntry (S, X, I+4); - /* Delete the call to tosaddax */ - CS_DelEntry (S, I+5); + /* pha */ + 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 */ ++Changes; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index d0b9809c9..f517088e2 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -1054,9 +1054,9 @@ unsigned OptTransfers (CodeSeg* S) (N->Info & OF_XFR) != 0) { /* Check if it's a transfer and back */ - if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) || - (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) || - (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (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+1)) || + (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !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 @@ -1074,16 +1074,16 @@ unsigned OptTransfers (CodeSeg* S) P = CS_GetEntry (S, I-1); if ((P->Info & OF_SETF) == 0) { /* Does not set the flags */ - goto NextEntry; - } - } + goto NextEntry; + } + } - /* Remove both transfers */ - CS_DelEntry (S, I+1); - CS_DelEntry (S, I); + /* Remove both transfers */ + CS_DelEntry (S, I+1); + CS_DelEntry (S, I); - /* Remember, we had changes */ - ++Changes; + /* Remember, we had changes */ + ++Changes; } } @@ -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 */ /*****************************************************************************/ diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index 44fe8f1ce..0eb4cf33c 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2001 Ullrich von Bassewitz */ +/* (C) 2001-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@cc65.org */ @@ -105,6 +105,9 @@ unsigned OptStoreLoad (CodeSeg* S); unsigned OptTransfers (CodeSeg* S); /* 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); /* Change branches for the distance needed. */ diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 39691a3ce..cca49c871 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -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 */ #define OP_DIRECT 0x01 /* Direct op may be used */ #define OP_ONSTACK 0x02 /* Operand is on stack */ @@ -57,13 +73,13 @@ /*****************************************************************************/ -/* Helpers */ +/* Helpers */ /*****************************************************************************/ static unsigned AdjustStackOffset (CodeSeg* S, unsigned Start, unsigned Stop, - unsigned Offs) + unsigned Offs) /* Adjust the offset for all stack accesses in the range Start to Stop, both * inclusive. The function returns the number of instructions that have been * inserted. @@ -123,64 +139,173 @@ 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 * 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 * 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->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { /* These insns are all ok and replaceable */ - Flags |= OP_DIRECT; + D->Flags |= OP_DIRECT; } else if (E->AM == AM65_ZP_INDY && E->RI->In.RegY >= 0 && - strcmp (E->Arg, "sp") == 0) { + (E->Use & REG_SP) != 0) { /* Load from stack with known offset is also ok */ - Flags |= (OP_DIRECT | OP_ONSTACK); + D->Flags |= (OP_DIRECT | OP_ONSTACK); + } + } +} + + + +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); } - return Flags; + 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); } /*****************************************************************************/ -/* Actual optimization functions */ +/* Actual optimization functions */ /*****************************************************************************/ -static unsigned Opt_staspidx (CodeSeg* S, unsigned Push, unsigned Store, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_staspidx (StackOpData* D) /* Optimize the staspidx sequence if possible */ { 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 */ - 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); + ReplacePushByStore (D); - /* Inline the store */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI); - CS_InsertEntry (S, X, Store+1); + /* Replace the store subroutine call by a direct op */ + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + InsertEntry (D, X, D->OpIndex+1); /* Remove the push and the call to the staspidx function */ - CS_DelEntry (S, Store); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ 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, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_staxspidx (StackOpData* D) /* Optimize the staxspidx sequence if possible */ { 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 */ - 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); + ReplacePushByStore (D); /* Inline the store */ - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI); - CS_InsertEntry (S, X, Store+1); - X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, StoreEntry->LI); - CS_InsertEntry (S, X, Store+2); - if (StoreEntry->RI->In.RegX >= 0) { + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + InsertEntry (D, X, D->OpIndex+1); + X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI); + InsertEntry (D, X, D->OpIndex+2); + if (D->OpEntry->RI->In.RegX >= 0) { /* Value of X is known */ - const char* Arg = MakeHexArg (StoreEntry->RI->In.RegX); - X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, StoreEntry->LI); + const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX); + X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI); } else { /* 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); - X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, StoreEntry->LI); - CS_InsertEntry (S, X, Store+4); + InsertEntry (D, X, D->OpIndex+3); + X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI); + InsertEntry (D, X, D->OpIndex+4); /* Remove the push and the call to the staspidx function */ - CS_DelEntry (S, Store); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ 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, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_tosaddax (StackOpData* D) /* Optimize the tosaddax sequence if possible */ { - CodeEntry* P; - CodeEntry* N; CodeEntry* X; - CodeEntry* PushEntry; - CodeEntry* AddEntry; - unsigned Flags; /* We need the entry behind the add */ - CHECK ((N = CS_GetNextEntry (S, Add)) != 0); - - /* And the entry before the push */ - CHECK ((P = CS_GetPrevEntry (S, Push)) != 0); - - /* Get the push entry */ - PushEntry = CS_GetEntry (S, Push); + CHECK (D->NextEntry != 0); /* 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 * location for the op and must not save the value in the zero page * location. */ - Flags = DirectOp (P); + CheckDirectOp (D); /* Store the value into the zeropage instead of pushing it */ - X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); - 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); + ReplacePushByStore (D); /* Inline the add */ - X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, AddEntry->LI); - CS_InsertEntry (S, X, Add+1); - if ((Flags & OP_DIRECT) != 0) { - /* Add 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, AddEntry->LI); - CS_InsertEntry (S, X, Add); - ++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) { + D->IP = D->OpIndex+1; + X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + + /* Low byte */ + AddOpLow (D, OP65_ADC); + + /* High byte */ + if (D->PushEntry->RI->In.RegX == 0) { /* The high byte is the value in X plus the carry */ - 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 if (AddEntry->RI->In.RegX == 0) { - /* The high byte is that of the first operand plus carry */ + CodeLabel* L = CS_GenLabel (D->Code, D->NextEntry); + X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + } else if (D->OpEntry->RI->In.RegX == 0) { + /* The high byte is that of the first operand plus carry */ CodeLabel* L; - if (PushEntry->RI->In.RegX >= 0) { + if (D->PushEntry->RI->In.RegX >= 0) { /* Value of first op high byte is known */ - const char* Arg = MakeHexArg (PushEntry->RI->In.RegX); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, AddEntry->LI); + const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); } else { /* 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); - L = CS_GenLabel (S, N); - X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, AddEntry->LI); - CS_InsertEntry (S, X, Add+4); - X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, AddEntry->LI); - CS_InsertEntry (S, X, Add+5); + InsertEntry (D, X, D->IP++); + L = CS_GenLabel (D->Code, D->NextEntry); + X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); } 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); + AddOpHigh (D, OP65_ADC); } /* Remove the push and the call to the tosaddax function */ - CS_DelEntry (S, Add); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ 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, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_tosandax (StackOpData* D) /* Optimize the tosandax sequence if possible */ { - CodeEntry* P; 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 * 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. */ - Flags = DirectOp (P); + CheckDirectOp (D); /* Store the value into the zeropage instead of pushing it */ - X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); - 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 */ - } + ReplacePushByStore (D); - /* Get a pointer to the and entry */ - AndEntry = CS_GetEntry (S, And); + /* Inline the and, low byte */ + D->IP = D->OpIndex + 1; + AddOpLow (D, OP65_AND); - /* Inline the and */ - if ((Flags & OP_DIRECT) != 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) { + /* High byte */ + if (D->PushEntry->RI->In.RegX == 0 || D->OpEntry->RI->In.RegX == 0) { /* The high byte is zero */ - X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, AndEntry->LI); - CS_InsertEntry (S, X, And+2); + X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); } else { /* High byte is unknown */ - X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, AndEntry->LI); - 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); + AddOpHigh (D, OP65_AND); } /* Remove the push and the call to the tosandax function */ - CS_DelEntry (S, And); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ 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, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_tosorax (StackOpData* D) /* Optimize the tosorax sequence if possible */ { - CodeEntry* P; 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 * 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. */ - Flags = DirectOp (P); + CheckDirectOp (D); /* Store the value into the zeropage instead of pushing it */ - X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); - 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 */ - } + ReplacePushByStore (D); - /* Get a pointer to the or entry */ - OrEntry = CS_GetEntry (S, Or); + /* Inline the or, low byte */ + D->IP = D->OpIndex + 1; + AddOpLow (D, OP65_ORA); - /* Inline the or */ - if ((Flags & OP_DIRECT) != 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) { + /* High byte */ + if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { /* Both values known, precalculate the result */ - const char* Arg = MakeHexArg (PushEntry->RI->In.RegX | OrEntry->RI->In.RegX); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, OrEntry->LI); - CS_InsertEntry (S, X, Or+2); - } else if (PushEntry->RI->In.RegX != 0) { + const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX | D->OpEntry->RI->In.RegX); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + } else if (D->PushEntry->RI->In.RegX != 0) { /* High byte is unknown */ - X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, OrEntry->LI); - 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); + AddOpHigh (D, OP65_ORA); } /* Remove the push and the call to the tosorax function */ - CS_DelEntry (S, Or); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ 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, - const char* ZPLo, const char* ZPHi) +static unsigned Opt_tosxorax (StackOpData* D) /* Optimize the tosxorax sequence if possible */ { - CodeEntry* P; 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 * 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. */ - Flags = DirectOp (P); + CheckDirectOp (D); /* Store the value into the zeropage instead of pushing it */ - X = NewCodeEntry (OP65_STX, AM65_ZP, ZPHi, 0, PushEntry->LI); - 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 */ - } + ReplacePushByStore (D); - /* Get a pointer to the entry */ - XorEntry = CS_GetEntry (S, Xor); + /* Inline the xor, low byte */ + D->IP = D->OpIndex + 1; + AddOpLow (D, OP65_EOR); - /* Inline the xor */ - if ((Flags & OP_DIRECT) != 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) { + /* High byte */ + if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { /* Both values known, precalculate the result */ - const char* Arg = MakeHexArg (PushEntry->RI->In.RegX ^ XorEntry->RI->In.RegX); - X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, XorEntry->LI); - CS_InsertEntry (S, X, Xor+2); - } else if (PushEntry->RI->In.RegX != 0) { + const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX ^ D->OpEntry->RI->In.RegX); + X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); + InsertEntry (D, X, D->IP++); + } else if (D->PushEntry->RI->In.RegX != 0) { /* High byte is unknown */ - X = NewCodeEntry (OP65_STA, AM65_ZP, ZPLo, 0, XorEntry->LI); - 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); + AddOpHigh (D, OP65_EOR); } /* Remove the push and the call to the tosandax function */ - CS_DelEntry (S, Xor); - CS_DelEntry (S, Push); + RemovePushAndOp (D); /* We changed the sequence */ return 1; @@ -593,13 +537,12 @@ static unsigned Opt_tosxorax (CodeSeg* S, unsigned Push, unsigned Xor, /* Flags for the functions */ typedef enum { - STOP_NONE, /* Nothing special */ + STOP_NONE, /* Nothing special */ STOP_A_UNUSED /* Call only if a unused later */ } STOP_FLAGS; -typedef unsigned (*OptFunc) (CodeSeg* S, unsigned Push, unsigned Store, - const char* ZPLo, const char* ZPHi); +typedef unsigned (*OptFunc) (StackOpData* D); typedef struct OptFuncDesc OptFuncDesc; struct OptFuncDesc { 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 */ /*****************************************************************************/ @@ -646,11 +616,12 @@ static const OptFuncDesc* FindFunc (const char* Name) unsigned OptStackOps (CodeSeg* S) /* Optimize operations that take operands via the stack */ { - unsigned Changes = 0; /* Number of changes in one run */ - int InSeq = 0; /* Inside a sequence */ - unsigned Push = 0; /* Index of pushax */ - unsigned UsedRegs = 0; /* Zeropage registers used in sequence */ - unsigned I; + unsigned Changes = 0; /* Number of changes in one run */ + int InSeq = 0; /* Inside a sequence */ + unsigned Push = 0; /* Index of pushax */ + unsigned UsedRegs = 0; /* Zeropage registers used in sequence */ + unsigned I; + /* Generate register info */ CS_GenRegInfo (S); @@ -694,9 +665,8 @@ unsigned OptStackOps (CodeSeg* S) const OptFuncDesc* F = FindFunc (E->Arg); if (F) { - const char* ZPLo = 0; - const char* ZPHi = 0; - int PreCondOk = 1; + StackOpData Data; + int PreCondOk = 1; /* Check the flags */ if (F->Flags & STOP_A_UNUSED) { @@ -712,14 +682,14 @@ unsigned OptStackOps (CodeSeg* S) UsedRegs |= GetRegInfo (S, I+1, REG_SREG | REG_PTR1 | REG_PTR2); if ((UsedRegs & REG_SREG) == REG_NONE) { /* SREG is available */ - ZPLo = "sreg"; - ZPHi = "sreg+1"; + Data.ZPLo = "sreg"; + Data.ZPHi = "sreg+1"; } else if ((UsedRegs & REG_PTR1) == REG_NONE) { - ZPLo = "ptr1"; - ZPHi = "ptr1+1"; + Data.ZPLo = "ptr1"; + Data.ZPHi = "ptr1+1"; } else if ((UsedRegs & REG_PTR2) == REG_NONE) { - ZPLo = "ptr2"; - ZPHi = "ptr2+1"; + Data.ZPLo = "ptr2"; + Data.ZPHi = "ptr2+1"; } else { /* No registers available */ PreCondOk = 0; @@ -730,13 +700,22 @@ unsigned OptStackOps (CodeSeg* S) if (PreCondOk) { /* Adjust stack offsets */ - unsigned Op = I + AdjustStackOffset (S, Push, I, 2); - - /* Call the optimizer function */ - Changes += F->Func (S, Push, Op, ZPLo, ZPHi); - - /* Regenerate register info */ - CS_GenRegInfo (S); + 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 */ + Changes += F->Func (&Data); + + /* Regenerate register info */ + CS_GenRegInfo (S); } /* End of sequence */ @@ -746,7 +725,7 @@ unsigned OptStackOps (CodeSeg* S) /* Restart the sequence */ Push = I; UsedRegs = REG_NONE; - } else { + } else if (!HarmlessCall (E->Arg)) { /* A call to an unkown subroutine ends the sequence */ InSeq = 0; } -- 2.39.5