From ca31e3af1effb268d36235495a11c2580b938682 Mon Sep 17 00:00:00 2001 From: greg-king5 Date: Sat, 12 May 2018 13:46:16 -0400 Subject: [PATCH] Fixed a bug that didn't preserve the accumulator's value when a simple 16-bit fetch-and-store is optimized. (#637) Fix a 16-bit fetch-and-store cc65 optimizer bug. --- src/cc65/coptstore.c | 45 +++++++++++++++++++++--------------------- test/val/assign-use1.c | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 test/val/assign-use1.c diff --git a/src/cc65/coptstore.c b/src/cc65/coptstore.c index 56343c95b..b0dfe3b6d 100644 --- a/src/cc65/coptstore.c +++ b/src/cc65/coptstore.c @@ -380,48 +380,48 @@ unsigned OptStore5 (CodeSeg* S) ** sta something ** stx something-else ** -** and replace it by +** and, replace it by ** -** lda foo -** sta something ** lda bar ** sta something-else +** lda foo +** sta something ** -** if X is not used later. This replacement doesn't save any cycles or bytes, -** but it keeps the value of X, which may be reused later. +** if the new value of X is not used later. That replacement doesn't save any +** cycles or bytes; but, it keeps the old value of X, which may be reused later. */ { unsigned Changes = 0; + unsigned I = 0; /* Walk over the entries */ - unsigned I = 0; while (I < CS_GetEntryCount (S)) { - CodeEntry* L[4]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ - if (L[0]->OPC == OP65_LDA && - !CS_RangeHasLabel (S, I+1, 3) && - CS_GetEntries (S, L+1, I+1, 3) && - L[1]->OPC == OP65_LDX && - L[2]->OPC == OP65_STA && - L[3]->OPC == OP65_STX && + if (L[0]->OPC == OP65_LDA && + !CS_RangeHasLabel (S, I+1, 3) && + CS_GetEntries (S, L+1, I+1, 3) && + L[1]->OPC == OP65_LDX && + L[2]->OPC == OP65_STA && + L[3]->OPC == OP65_STX && !RegXUsed (S, I+4)) { - CodeEntry* X; + CodeEntry* E = CS_GetEntry (S, I+1); - /* Insert the code after the sequence */ - X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI); - CS_InsertEntry (S, X, I+4); - X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); - CS_InsertEntry (S, X, I+5); + /* Move the high-byte code to the beginning of the sequence */ + CS_MoveEntry (S, I+1, I); + CS_MoveEntry (S, I+3, I+1); - /* Delete the old code */ - CS_DelEntry (S, I+3); - CS_DelEntry (S, I+1); + /* Change from the X register to the A register */ + CE_ReplaceOPC (E, OP65_LDA); + CE_ReplaceOPC (CS_GetEntry (S, I+1), OP65_STA); + + /* Move labels from the old first entry to the new first entry */ + CS_MoveLabels (S, CS_GetEntry (S, I+2), E); /* Remember, we had changes */ ++Changes; @@ -429,7 +429,6 @@ unsigned OptStore5 (CodeSeg* S) /* Next entry */ ++I; - } /* Return the number of changes made */ diff --git a/test/val/assign-use1.c b/test/val/assign-use1.c new file mode 100644 index 000000000..744023530 --- /dev/null +++ b/test/val/assign-use1.c @@ -0,0 +1,36 @@ +/* + !!DESCRIPTION!! Assign an int; then, do an operation that depends directly on that assignment. + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Greg King +*/ + +#include + +static unsigned char failures = 0; + +static unsigned int result; +static const unsigned int buffer = 0xABCD; + +int main(void) +{ + result = buffer; + + /* Shift doesn't use high byte (X register); previous assignment should be optimized. */ + result <<= 8; + if (result != 0xCD00) { + ++failures; + printf("assign-use1: left shift is $%X, not $CD00.\n", result); + } + + result = buffer; + + /* Shift does use high byte; previous assignment shouldn't be optimized by OptStore5(). */ + result >>= 8; + if (result != 0x00AB) { + ++failures; + printf("assign-use1: right shift is $%X, not $00AB.\n", result); + } + + return failures; +} -- 2.39.5