From a9702f8a52c405159e12722e91043d438b815e0d Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 20 May 2001 09:38:20 +0000 Subject: [PATCH] Working git-svn-id: svn://svn.cc65.org/cc65/trunk@733 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeopt.c | 180 ++++++++++++++++++++++++++++++++++++++------- src/cc65/codeseg.c | 23 ++++-- src/cc65/codeseg.h | 7 +- 3 files changed, 171 insertions(+), 39 deletions(-) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 5b196840c..208414526 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -203,8 +203,76 @@ static int IsCmpToZero (const CodeEntry* E) +static int IsSpLoad (const CodeEntry* E) +/* Return true if this is the load of A from the stack */ +{ + return E->OPC == OPC_LDA && E->AM == AM_ZP_INDY && strcmp (E->Arg, "sp") == 0; +} + + + +static int IsLocalLoad16 (CodeSeg* S, unsigned Index, + CodeEntry** L, unsigned Count) +/* Check if a 16 bit load of a local variable follows: + * + * ldy #$xx + * lda (sp),y + * tax + * dey + * lda (sp),y + * + * If so, read Count entries following the first ldy into L and return true + * if this is possible. Otherwise return false. + */ +{ + /* Be sure we read enough entries for the check */ + CHECK (Count >= 5); + + /* Read the first entry */ + L[0] = GetCodeEntry (S, Index); + + /* Check for the sequence */ + return (L[0]->OPC == OPC_LDY && + L[0]->AM == AM_IMM && + (L[0]->Flags & CEF_NUMARG) != 0 && + GetCodeEntries (S, L+1, Index+1, Count-1) && + IsSpLoad (L[1]) && + !CodeEntryHasLabel (L[1]) && + L[2]->OPC == OPC_TAX && + !CodeEntryHasLabel (L[2]) && + L[3]->OPC == OPC_DEY && + !CodeEntryHasLabel (L[3]) && + IsSpLoad (L[4]) && + !CodeEntryHasLabel (L[4])); +} + + + +static int IsImmCmp16 (CodeSeg* S, CodeEntry** L) +/* Check if the instructions at L are an immidiate compare of a/x: + * + * + */ +{ + return (L[0]->OPC == OPC_CPX && + L[0]->AM == AM_IMM && + (L[0]->Flags & CEF_NUMARG) != 0 && + !CodeEntryHasLabel (L[0]) && + (L[1]->OPC == OPC_JNE || L[1]->OPC == OPC_BNE) && + L[1]->JumpTo != 0 && + !CodeEntryHasLabel (L[1]) && + L[2]->OPC == OPC_CMP && + L[2]->AM == AM_IMM && + (L[2]->Flags & CEF_NUMARG) != 0 && + (L[3]->Info & OF_ZBRA) != 0 && + L[3]->JumpTo != 0 && + (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo)); +} + + + /*****************************************************************************/ -/* Remove calls to the bool transformer subroutines */ +/* Remove calls to the bool transformer subroutines */ /*****************************************************************************/ @@ -499,40 +567,96 @@ static unsigned OptCmp3 (CodeSeg* S) GetCodeEntries (S, L, I+1, 5) && L[0]->OPC == OPC_LDX && !CodeEntryHasLabel (L[0]) && - L[1]->OPC == OPC_CPX && - L[1]->AM == AM_IMM && - (L[1]->Flags & CEF_NUMARG) != 0 && - !CodeEntryHasLabel (L[1]) && - (L[2]->OPC == OPC_JNE || L[2]->OPC == OPC_BNE) && - L[2]->JumpTo != 0 && - !CodeEntryHasLabel (L[2]) && - L[3]->OPC == OPC_CMP && - L[3]->AM == AM_IMM && - (L[3]->Flags & CEF_NUMARG) != 0 && - (L[4]->Info & OF_ZBRA) != 0 && - L[4]->JumpTo != 0 && - (L[2]->JumpTo->Owner == L[4] || L[2]->JumpTo == L[4]->JumpTo)) { - - /* Get the compare value */ - unsigned Val = ((L[1]->Num & 0xFF) << 8) | (L[3]->Num & 0xFF); - - if (Val == 0) { + IsImmCmp16 (S, L+1)) { + + if (L[1]->Num == 0 && L[3]->Num == 0) { /* The value is zero, we may use the simple code version. */ ReplaceOPC (L[0], OPC_ORA); DelCodeEntries (S, I+2, 3); } else { - /* Move the lda instruction after the first branch */ - CodeEntry* N = RetrieveCodeEntry (S, I); - InsertCodeEntry (S, N, I+3); + /* Move the lda instruction after the first branch. This will + * improve speed, since the load is delayed after the first + * test. + */ + MoveCodeEntry (S, I, I+4); - /* Replace the ldx/cpx by lda/cmp */ + /* We will replace the ldx/cpx by lda/cmp */ ReplaceOPC (L[0], OPC_LDA); ReplaceOPC (L[1], OPC_CMP); - /* The high byte is zero, remove the CMP */ - if ((Val & 0xFF00) == 0) { - DelCodeEntry (S, I+1); - } + } + + ++Changes; + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +static unsigned OptCmp4 (CodeSeg* S) +/* Optimize compares of local variables: + * + * ldy #o + * lda (sp),y + * tax + * dey + * lda (sp),y + * cpx #a + * bne L1 + * cmp #b + * jne/jeq L2 + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < GetCodeEntryCount (S)) { + + CodeEntry* L[9]; + + /* Check for the sequence */ + if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) { + + if (L[5]->Num == 0 && L[7]->Num == 0) { + + /* The value is zero, we may use the simple code version: + * ldy #o + * lda (sp),y + * dey + * ora (sp),y + * jne/jeq ... + */ + ReplaceOPC (L[4], OPC_ORA); + DelCodeEntries (S, I+5, 3); /* cpx/bne/cmp */ + DelCodeEntry (S, I+2); /* tax */ + + } else { + + /* Change the code to just use the A register. Move the load + * of the low byte after the first branch if possible: + * + * ldy #o + * lda (sp),y + * cmp #a + * bne L1 + * dey + * lda (sp),y + * cmp #b + * jne/jeq ... + */ + DelCodeEntry (S, I+2); /* tax */ + ReplaceOPC (L[5], OPC_CMP); /* cpx -> cmp */ + MoveCodeEntry (S, I+4, I+2); /* cmp */ + MoveCodeEntry (S, I+5, I+3); /* bne */ + } ++Changes; @@ -915,6 +1039,8 @@ static OptFunc OptFuncs [] = { { OptCmp2, "OptCmp2", 0 }, /* Optimize compares */ { OptCmp3, "OptCmp3", 0 }, + /* Optimize compares */ + { OptCmp4, "OptCmp4", 0 }, /* Remove unused loads */ { OptUnusedLoads, "OptUnusedLoads", 0 }, /* Optimize branch distance */ diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index c41554403..fb971183a 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -542,16 +542,23 @@ void DelCodeEntries (CodeSeg* S, unsigned Start, unsigned Count) -struct CodeEntry* RetrieveCodeEntry (CodeSeg* S, unsigned Index) -/* Retrieve a code entry. This means, the code entry is removed from the - * entry collection, but not deleted and returned instead. The entry may - * then be inserted again at another position. +void MoveCodeEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos) +/* Move an entry from one position to another. OldPos is the current position + * of the entry, NewPos is the new position of the entry. */ { - /* Get the code entry, remove it from the collection and return it */ - CodeEntry* E = GetCodeEntry (S, Index); - CollDelete (&S->Entries, Index); - return E; + /* Get the code entry and remove it from the collection */ + CodeEntry* E = GetCodeEntry (S, OldPos); + CollDelete (&S->Entries, OldPos); + + /* Correct NewPos if needed */ + if (NewPos >= OldPos) { + /* Position has changed with removal */ + --NewPos; + } + + /* Now insert it at the new position */ + CollInsert (&S->Entries, E, NewPos); } diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index fbbe472c6..3fce28158 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -112,10 +112,9 @@ void DelCodeEntries (CodeSeg* S, unsigned Start, unsigned Count); * labels attached to the entries and so on. */ -struct CodeEntry* RetrieveCodeEntry (CodeSeg* S, unsigned Index); -/* Retrieve a code entry. This means, the code entry is removed from the - * entry collection, but not deleted and returned instead. The entry may - * then be inserted again at another position. +void MoveCodeEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos); +/* Move an entry from one position to another. OldPos is the current position + * of the entry, NewPos is the new position of the entry. */ #if defined(HAVE_INLINE) -- 2.39.5