From: cuz Date: Thu, 17 Oct 2002 21:37:01 +0000 (+0000) Subject: New store optimization. X-Git-Tag: V2.12.0~2166 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=914b2a7e370709a9fe45d738fc8aaa9b7382f76f;p=cc65 New store optimization. New functions RegValIsKnown and RegValIsUnknown should be used instead of direct compares against zero, so we can change the "unknown" representation one day. git-svn-id: svn://svn.cc65.org/cc65/trunk@1466 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 74a704a96..47d038abc 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -590,6 +590,14 @@ int RegAXUsed (struct CodeSeg* S, unsigned Index) +int RegEAXUsed (struct CodeSeg* S, unsigned Index) +/* Check if any of the four bytes in EAX are used. */ +{ + return (GetRegInfo (S, Index, REG_EAX) & REG_EAX) != 0; +} + + + unsigned GetKnownReg (unsigned Use, const RegContents* RC) /* Return the register or zero page location from the set in Use, thats * contents are known. If Use does not contain any register, or if the diff --git a/src/cc65/codeinfo.h b/src/cc65/codeinfo.h index 7e4eddf98..4e0b16887 100644 --- a/src/cc65/codeinfo.h +++ b/src/cc65/codeinfo.h @@ -154,6 +154,9 @@ int RegYUsed (struct CodeSeg* S, unsigned Index); int RegAXUsed (struct CodeSeg* S, unsigned Index); /* Check if the value in A or(!) the value in X are used. */ +int RegEAXUsed (struct CodeSeg* S, unsigned Index); +/* Check if any of the four bytes in EAX are used. */ + unsigned GetKnownReg (unsigned Use, const struct RegContents* RC); /* Return the register or zero page location from the set in Use, thats * contents are known. If Use does not contain any register, or if the diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 1690a42bc..a1d824d0a 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -55,6 +55,7 @@ #include "coptpush.h" #include "coptsize.h" #include "coptstop.h" +#include "coptstore.h" #include "coptsub.h" #include "copttest.h" #include "cpu.h" @@ -1371,6 +1372,8 @@ static OptFunc DOptShift3 = { OptShift3, "OptShift3", 110, 0, static OptFunc DOptSize1 = { OptSize1, "OptSize1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSize2 = { OptSize2, "OptSize2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore1 = { OptStore1, "OptStore1", 220, 0, 0, 0, 0, 0 }; +static OptFunc DOptStore2 = { OptStore2, "OptStore2", 120, 0, 0, 0, 0, 0 }; static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 }; @@ -1429,6 +1432,8 @@ static OptFunc* OptFuncs[] = { &DOptSize1, &DOptSize2, &DOptStackOps, + &DOptStore1, + &DOptStore2, &DOptStoreLoad, &DOptSub1, &DOptSub2, @@ -1685,6 +1690,8 @@ static unsigned RunOptGroup1 (CodeSeg* S) Changes += RunOptFunc (S, &DOptShift1, 1); Changes += RunOptFunc (S, &DOptShift2, 1); Changes += RunOptFunc (S, &DOptShift3, 1); + Changes += RunOptFunc (S, &DOptStore1, 5); + Changes += RunOptFunc (S, &DOptStore2, 5); /* Return the number of changes */ return Changes; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 98f0c4246..f72d77888 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -800,7 +800,7 @@ unsigned OptDupLoads (CodeSeg* S) switch (E->OPC) { case OP65_LDA: - if (In->RegA >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegA) && /* Value of A is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegA == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ @@ -810,7 +810,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_LDX: - if (In->RegX >= 0 && /* Value of X is known */ + if (RegValIsKnown (In->RegX) && /* Value of X is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegX == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ @@ -820,7 +820,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_LDY: - if (In->RegY >= 0 && /* Value of Y is known */ + if (RegValIsKnown (In->RegY) && /* Value of Y is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegY == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ @@ -834,7 +834,7 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegA >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegA) && /* Value of A is known */ E->AM == AM65_ZP && /* Store into zp */ In->RegA == RegVal (E->Chg, In)) { /* Value identical */ @@ -847,7 +847,7 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegX >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegX) && /* Value of A is known */ E->AM == AM65_ZP && /* Store into zp */ In->RegX == RegVal (E->Chg, In)) { /* Value identical */ @@ -859,7 +859,7 @@ unsigned OptDupLoads (CodeSeg* S) * later. STX does support the zeropage,y addressing mode, * so be sure to check for that. */ - } else if (In->RegX >= 0 && + } else if (RegValIsKnown (In->RegX) && In->RegX == In->RegA && E->AM != AM65_ABSY && E->AM != AM65_ZPY) { @@ -873,7 +873,7 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegY >= 0 && /* Value of Y is known */ + if (RegValIsKnown (In->RegY) && /* Value of Y is known */ E->AM == AM65_ZP && /* Store into zp */ In->RegY == RegVal (E->Chg, In)) { /* Value identical */ @@ -886,7 +886,7 @@ unsigned OptDupLoads (CodeSeg* S) * replacement by X, but check for invalid addressing modes * in this case. */ - } else if (In->RegY >= 0) { + } else if (RegValIsKnown (In->RegY)) { if (In->RegY == In->RegA) { CE_ReplaceOPC (E, OP65_STA); } else if (In->RegY == In->RegX && @@ -910,7 +910,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TAX: - if (In->RegA >= 0 && + if (RegValIsKnown (In->RegA) && In->RegA == In->RegX && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -920,7 +920,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TAY: - if (In->RegA >= 0 && + if (RegValIsKnown (In->RegA) && In->RegA == In->RegY && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -930,7 +930,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TXA: - if (In->RegX >= 0 && + if (RegValIsKnown (In->RegX) && In->RegX == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -940,7 +940,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TYA: - if (In->RegY >= 0 && + if (RegValIsKnown (In->RegY) && In->RegY == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -961,7 +961,7 @@ unsigned OptDupLoads (CodeSeg* S) CS_DelEntry (S, I); /* Remember, we had changes */ - ++Changes; + ++Changes; } else { diff --git a/src/cc65/coptpush.c b/src/cc65/coptpush.c index bede32307..887bbf9be 100644 --- a/src/cc65/coptpush.c +++ b/src/cc65/coptpush.c @@ -80,7 +80,7 @@ unsigned OptPush1 (CodeSeg* S) CS_GetEntries (S, L+1, I+1, 2) && CE_IsCallTo (L[1], "ldaxysp") && CE_IsCallTo (L[2], "pushax") && - (GetRegInfo (S, I+3, REG_AX) & REG_AX) == 0) { + !RegAXUsed (S, I+3)) { /* Insert new code behind the pushax */ const char* Arg; diff --git a/src/cc65/coptsize.c b/src/cc65/coptsize.c index ab5728780..3eaf48dce 100644 --- a/src/cc65/coptsize.c +++ b/src/cc65/coptsize.c @@ -266,10 +266,12 @@ unsigned OptSize2 (CodeSeg* S) I = 0; while (I < CS_GetEntryCount (S)) { - /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); + /* Get the input registers */ + const RegContents* In = &E->RI->In; + /* Assume we have no replacement */ CodeEntry* X = 0; @@ -279,14 +281,14 @@ unsigned OptSize2 (CodeSeg* S) case OP65_LDA: if (CE_KnownImm (E)) { short Val = (short) E->Num; - if (Val == E->RI->In.RegX) { + if (Val == In->RegX) { X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegY) { + } else if (Val == In->RegY) { X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegA >= 0 && CPU >= CPU_65C02) { - if (Val == ((E->RI->In.RegA - 1) & 0xFF)) { + } else if (RegValIsKnown (In->RegA) && CPU >= CPU_65C02) { + if (Val == ((In->RegA - 1) & 0xFF)) { X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI); - } else if (Val == ((E->RI->In.RegA + 1) & 0xFF)) { + } else if (Val == ((In->RegA + 1) & 0xFF)) { X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI); } } @@ -296,11 +298,11 @@ unsigned OptSize2 (CodeSeg* S) case OP65_LDX: if (CE_KnownImm (E)) { short Val = (short) E->Num; - if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX - 1) & 0xFF)) { + if (RegValIsKnown (In->RegX) && Val == ((In->RegX - 1) & 0xFF)) { X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegX >= 0 && Val == ((E->RI->In.RegX + 1) & 0xFF)) { + } else if (RegValIsKnown (In->RegX) && Val == ((In->RegX + 1) & 0xFF)) { X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegA) { + } else if (Val == In->RegA) { X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI); } } @@ -309,11 +311,11 @@ unsigned OptSize2 (CodeSeg* S) case OP65_LDY: if (CE_KnownImm (E)) { short Val = (short) E->Num; - if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY - 1) & 0xFF)) { + if (RegValIsKnown (In->RegY) && Val == ((In->RegY - 1) & 0xFF)) { X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI); - } else if (E->RI->In.RegY >= 0 && Val == ((E->RI->In.RegY + 1) & 0xFF)) { + } else if (RegValIsKnown (In->RegY) && Val == ((In->RegY + 1) & 0xFF)) { X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI); - } else if (Val == E->RI->In.RegA) { + } else if (Val == In->RegA) { X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI); } } diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 4e1c2e6d7..557f4d357 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -207,9 +207,9 @@ static void CheckDirectOp (StackOpData* D) if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) { /* These insns are all ok and replaceable */ D->Flags |= OP_DIRECT; - } else if (E->AM == AM65_ZP_INDY && - E->RI->In.RegY >= 0 && - (E->Use & REG_SP) != 0) { + } else if (E->AM == AM65_ZP_INDY && + RegValIsKnown (E->RI->In.RegY) && + (E->Use & REG_SP) != 0) { /* Load from stack with known offset is also ok */ D->Flags |= (OP_DIRECT | OP_ONSTACK); } @@ -337,7 +337,7 @@ static unsigned Opt_staxspidx (StackOpData* D) 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) { + if (RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Value of X is known */ const char* Arg = MakeHexArg (D->OpEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -396,7 +396,7 @@ static unsigned Opt_tosaddax (StackOpData* D) } else if (D->OpEntry->RI->In.RegX == 0) { /* The high byte is that of the first operand plus carry */ CodeLabel* L; - if (D->PushEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX)) { /* Value of first op high byte is known */ const char* Arg = MakeHexArg (D->PushEntry->RI->In.RegX); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, D->OpEntry->LI); @@ -482,7 +482,8 @@ static unsigned Opt_tosorax (StackOpData* D) AddOpLow (D, OP65_ORA); /* High byte */ - if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX) && + RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Both values known, precalculate the result */ 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); @@ -521,7 +522,8 @@ static unsigned Opt_tosxorax (StackOpData* D) AddOpLow (D, OP65_EOR); /* High byte */ - if (D->PushEntry->RI->In.RegX >= 0 && D->OpEntry->RI->In.RegX >= 0) { + if (RegValIsKnown (D->PushEntry->RI->In.RegX) && + RegValIsKnown (D->OpEntry->RI->In.RegX)) { /* Both values known, precalculate the result */ 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); @@ -661,8 +663,8 @@ unsigned OptStackOps (CodeSeg* S) /* Handling depends if we're inside a sequence or not */ if (InSeq) { - if (((E->Use & REG_SP) != 0 && - (E->AM != AM65_ZP_INDY || E->RI->In.RegY < 0))) { + if (((E->Use & REG_SP) != 0 && + (E->AM != AM65_ZP_INDY || RegValIsUnknown (E->RI->In.RegY)))) { /* All this stuff is not allowed in a sequence */ InSeq = 0; diff --git a/src/cc65/coptstore.c b/src/cc65/coptstore.c new file mode 100644 index 000000000..66e1a7a66 --- /dev/null +++ b/src/cc65/coptstore.c @@ -0,0 +1,277 @@ +/*****************************************************************************/ +/* */ +/* coptstore.c */ +/* */ +/* Optimize stores */ +/* */ +/* */ +/* */ +/* (C) 2002 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. */ +/* */ +/*****************************************************************************/ + + + +/* cc65 */ +#include "codeent.h" +#include "codeinfo.h" +#include "coptstore.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static void InsertStore (CodeSeg* S, unsigned* IP, LineInfo* LI) +{ + CodeEntry* X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, LI); + CS_InsertEntry (S, X, (*IP)++); +} + + + +unsigned OptStore1 (CodeSeg* S) +/* Search for a call to staxysp. If the ax register is not used later, and + * the value is constant, just use the A register and store directly into the + * stack. + */ +{ + unsigned I; + unsigned Changes = 0; + + /* Generate register info */ + CS_GenRegInfo (S); + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Get the input registers */ + const RegInfo* RI = E->RI; + + /* Check for the call */ + if (CE_IsCallTo (E, "staxysp") && + RegValIsKnown (RI->In.RegA) && + RegValIsKnown (RI->In.RegX) && + RegValIsKnown (RI->In.RegY) && + !RegAXUsed (S, I+1)) { + + /* Get the register values */ + unsigned char A = RI->In.RegA; + unsigned char X = RI->In.RegX; + unsigned char Y = RI->In.RegY; + + /* Setup other variables */ + CodeEntry* N; + unsigned IP = I + 1; /* Insertion point */ + + /* Replace the store. We will not remove the loads, since this is + * too complex and will be done by other optimizer steps. + */ + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + + /* Check if we can store one of the other bytes */ + if (A != X) { + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI); + CS_InsertEntry (S, N, IP++); + } + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + + /* Remove the call */ + CS_DelEntry (S, I); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Free the register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptStore2 (CodeSeg* S) +/* Search for a call to steaxysp. If the eax register is not used later, and + * the value is constant, just use the A register and store directly into the + * stack. + */ +{ + unsigned I; + unsigned Changes = 0; + + /* Generate register info */ + CS_GenRegInfo (S); + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Get the input registers */ + const RegInfo* RI = E->RI; + + /* Check for the call */ + if (CE_IsCallTo (E, "steaxysp") && + RegValIsKnown (RI->In.RegA) && + RegValIsKnown (RI->In.RegX) && + RegValIsKnown (RI->In.RegY) && + RegValIsKnown (RI->In.SRegLo) && + RegValIsKnown (RI->In.SRegHi) && + !RegEAXUsed (S, I+1)) { + + /* Get the register values */ + unsigned char A = RI->In.RegA; + unsigned char X = RI->In.RegX; + unsigned char Y = RI->In.RegY; + unsigned char L = RI->In.SRegLo; + unsigned char H = RI->In.SRegHi; + + /* Setup other variables */ + unsigned Done = 0; + CodeEntry* N; + unsigned IP = I + 1; /* Insertion point */ + + /* Replace the store. We will not remove the loads, since this is + * too complex and will be done by other optimizer steps. + */ + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x01; + + /* Check if we can store one of the other bytes */ + if (A == X && (Done & 0x02) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x02; + } + if (A == L && (Done & 0x04) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x04; + } + if (A == H && (Done & 0x08) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x08; + } + + /* Store the second byte */ + if ((Done & 0x02) == 0) { + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI); + CS_InsertEntry (S, N, IP++); + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x02; + } + + /* Check if we can store one of the other bytes */ + if (X == L && (Done & 0x04) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x04; + } + if (X == H && (Done & 0x08) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x08; + } + + /* Store the third byte */ + if ((Done & 0x04) == 0) { + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI); + CS_InsertEntry (S, N, IP++); + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x04; + } + + /* Check if we can store one of the other bytes */ + if (L == H && (Done & 0x08) == 0) { + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x08; + } + + /* Store the fourth byte */ + if ((Done & 0x08) == 0) { + N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI); + CS_InsertEntry (S, N, IP++); + N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); + CS_InsertEntry (S, N, IP++); + InsertStore (S, &IP, E->LI); + Done |= 0x08; + } + + /* Remove the call */ + CS_DelEntry (S, I); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Free the register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + diff --git a/src/cc65/coptstore.h b/src/cc65/coptstore.h new file mode 100644 index 000000000..29a97de7d --- /dev/null +++ b/src/cc65/coptstore.h @@ -0,0 +1,71 @@ +/*****************************************************************************/ +/* */ +/* coptstore.h */ +/* */ +/* Optimize stores */ +/* */ +/* */ +/* */ +/* (C) 2002 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 COPTSTORE_H +#define COPTSTORE_H + + + +/* cc65 */ +#include "codeseg.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +unsigned OptStore1 (CodeSeg* S); +/* Search for a call to staxysp. If the ax register is not used later, and + * the value is constant, just use the A register and store directly into the + * stack. + */ + +unsigned OptStore2 (CodeSeg* S); +/* Search for a call to steaxysp. If the eax register is not used later, and + * the value is constant, just use the A register and store directly into the + * stack. + */ + + + +/* End of coptstore.h */ + +#endif + + + diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 7bd827448..7446bb8d0 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -42,6 +42,7 @@ OBJS = anonname.o \ coptpush.o \ coptsize.o \ coptstop.o \ + coptstore.o \ coptsub.o \ copttest.o \ cpu.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index be067caa1..b55980c18 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -87,6 +87,7 @@ OBJS = anonname.obj \ coptpush.obj \ coptsize.obj \ coptstop.obj \ + coptstore.obj \ coptsub.obj \ copttest.obj \ cpu.obj \ @@ -169,6 +170,7 @@ FILE coptneg.obj FILE coptpush.obj FILE coptsize.obj FILE coptstop.obj +FILE coptstore.obj FILE coptsub.obj FILE copttest.obj FILE cpu.obj diff --git a/src/cc65/reginfo.h b/src/cc65/reginfo.h index 9b2abc866..ecfe08a70 100644 --- a/src/cc65/reginfo.h +++ b/src/cc65/reginfo.h @@ -44,7 +44,7 @@ /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ @@ -82,6 +82,26 @@ void RC_Invalidate (RegContents* C); void RC_InvalidateZP (RegContents* C); /* Invalidate all ZP registers */ +#if defined(HAVE_INLINE) +INLINE int RegValIsKnown (short Val) +/* Return true if the register value is known */ +{ + return (Val >= 0); +} +#else +# define RegValIsKnown(S) ((S) >= 0) +#endif + +#if defined(HAVE_INLINE) +INLINE int RegValIsUnknown (short Val) +/* Return true if the register value is not known */ +{ + return (Val < 0); +} +#else +# define RegValIsUnknown(S) ((S) < 0) +#endif + RegInfo* NewRegInfo (const RegContents* RC); /* Allocate a new register info, initialize and return it. If RC is not * a NULL pointer, it is used to initialize both, the input and output @@ -93,9 +113,11 @@ void FreeRegInfo (RegInfo* RI); + + /* End of reginfo.h */ #endif - +