From 8d0dfb5b41eb1fd43a7f807ec63ed0f50bb6ca2f Mon Sep 17 00:00:00 2001 From: cuz Date: Tue, 25 Sep 2001 12:34:34 +0000 Subject: [PATCH] More optimizations git-svn-id: svn://svn.cc65.org/cc65/trunk@970 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codegen.c | 28 +++++++-- src/cc65/codeopt.c | 147 +++++++++++++++++++++++++++++++++++++++++---- src/cc65/opcodes.c | 8 +-- src/cc65/opcodes.h | 1 + 4 files changed, 163 insertions(+), 21 deletions(-) diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index d936c1572..83944f503 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -170,7 +170,7 @@ void g_preamble (void) AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); /* Import the stack pointer for direct auto variable access */ - AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1"); + AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1, ptr2"); /* Define long branch macros */ AddTextLine ("\t.macpack\tlongbranch"); @@ -608,7 +608,7 @@ void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs) if (B2 == B4) { AddCodeLine ("stx sreg+1"); Done |= 0x08; - } + } if ((Done & 0x04) == 0 && B1 != B3) { AddCodeLine ("lda #$%02X", B3); AddCodeLine ("sta sreg"); @@ -1701,11 +1701,27 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val) /* FALLTHROUGH */ case CF_INT: - if (flags & CF_CONST) { - g_getimmed (flags, val, 0); - } ldyconst (offs); - AddCodeLine ("jsr addeqysp"); + if (flags & CF_CONST) { + if (CodeSizeFactor >= 400) { + AddCodeLine ("clc"); + AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF)); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("tax"); + AddCodeLine ("dey"); + AddCodeLine ("lda (sp),y"); + } else { + g_getimmed (flags, val, 0); + AddCodeLine ("jsr addeqysp"); + } + } else { + AddCodeLine ("jsr addeqysp"); + } break; case CF_LONG: diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 7be0efb9c..789c177d1 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -256,6 +256,20 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond) +static int GetCmpRegVal (const CodeEntry* E) +/* Return the register value for an immediate compare */ +{ + switch (E->OPC) { + case OP65_CMP: return E->RI->In.RegA; + case OP65_CPX: return E->RI->In.RegX; + case OP65_CPY: return E->RI->In.RegY; + default: Internal ("Invalid opcode in GetCmpRegVal"); + return 0; /* Not reached */ + } +} + + + static int IsCmpToZero (const CodeEntry* E) /* Check if the given instrcuction is a compare to zero instruction */ { @@ -937,6 +951,10 @@ static unsigned OptCmp2 (CodeSeg* S) * lda/and/ora/eor ... * cmp #$00 * jeq/jne + * or + * lda/and/ora/eor ... + * cmp #$00 + * jsr boolxx * * and remove the cmp. */ @@ -963,11 +981,13 @@ static unsigned OptCmp2 (CodeSeg* S) E->OPC == OP65_PLA || E->OPC == OP65_SBC || E->OPC == OP65_TXA || - E->OPC == OP65_TYA) && - CS_GetEntries (S, L, I+1, 2) && - IsCmpToZero (L[0]) && - !CE_HasLabel (L[0]) && - (L[1]->Info & OF_FBRA) != 0 && + E->OPC == OP65_TYA) && + CS_GetEntries (S, L, I+1, 2) && + IsCmpToZero (L[0]) && + !CE_HasLabel (L[0]) && + ((L[1]->Info & OF_FBRA) != 0 || + (L[1]->OPC == OP65_JSR && + FindBoolCmpCond (L[1]->Arg) != CMP_INV)) && !CE_HasLabel (L[1])) { /* Remove the compare */ @@ -985,7 +1005,7 @@ static unsigned OptCmp2 (CodeSeg* S) /* Return the number of changes made */ return Changes; -} +} @@ -1128,7 +1148,7 @@ static unsigned OptCmp4 (CodeSeg* S) ++Changes; } - /* Next entry */ + /* Next entry */ ++I; } @@ -1171,7 +1191,7 @@ static unsigned OptCmp5 (CodeSeg* S) * boolean value but only valid flags. Note: jeq jumps if * the condition is not met, jne jumps if the condition is met. * Invert the code if we jump on condition not met. - */ + */ if (GetBranchCond (N->OPC) == BC_EQ) { /* Jumps if condition false, invert condition */ Cond = CmpInvertTab [Cond]; @@ -1245,6 +1265,110 @@ static unsigned OptCmp6 (CodeSeg* S) +static unsigned OptCmp7 (CodeSeg* S) +/* Check for register compares where the contents of the register and therefore + * the result of the compare is known. + */ +{ + unsigned Changes = 0; + unsigned I; + + /* Generate register info for this step */ + CS_GenRegInfo (S); + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + int RegVal; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for a compare against an immediate value */ + if ((E->Info & OF_CMP) != 0 && + (RegVal = GetCmpRegVal (E)) >= 0 && + CE_KnownImm (E)) { + + /* We are able to evaluate the compare at compile time. Check if + * one or more branches are ahead. + */ + unsigned JumpsChanged = 0; + CodeEntry* N; + while ((N = CS_GetNextEntry (S, I)) != 0 && /* Followed by something.. */ + (N->Info & OF_CBRA) != 0 && /* ..that is a cond branch.. */ + !CE_HasLabel (N)) { /* ..and has no label */ + + /* Evaluate the branch condition */ + int Cond; + switch (GetBranchCond (N->OPC)) { + case BC_CC: + Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num); + break; + + case BC_CS: + Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num); + break; + + case BC_EQ: + Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num); + break; + + case BC_MI: + Cond = ((signed char)RegVal) < ((signed char)E->Num); + break; + + case BC_NE: + Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num); + break; + + case BC_PL: + Cond = ((signed char)RegVal) >= ((signed char)E->Num); + break; + + case BC_VC: + case BC_VS: + } + + /* If the condition is false, we may remove the jump. Otherwise + * the branch will always be taken, so we may replace it by a + * jump (and bail out). + */ + if (!Cond) { + CS_DelEntry (S, I+1); + } else { + CodeLabel* L = N->JumpTo; + CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, L->Name, L, N->LI); + CS_InsertEntry (S, X, I+2); + CS_DelEntry (S, I+1); + } + + /* Remember, we had changes */ + ++JumpsChanged; + ++Changes; + } + + /* If we have made changes above, we may also remove the compare */ + if (JumpsChanged) { + CS_DelEntry (S, I); + } + + } + + /* Next entry */ + ++I; + + } + + /* Free register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + /*****************************************************************************/ /* Optimize tests */ /*****************************************************************************/ @@ -1319,10 +1443,10 @@ static unsigned OptTest1 (CodeSeg* S) /* Remove the two other insns */ CS_DelEntry (S, I+1); - CS_DelEntry (S, I); + CS_DelEntry (S, I); - /* We had changes */ - ++Changes; + /* We had changes */ + ++Changes; } } @@ -2576,6 +2700,7 @@ static OptFunc OptFuncs [] = { OptEntry (OptCmp4, optMain), OptEntry (OptCmp5, optMain), OptEntry (OptCmp6, optMain), + OptEntry (OptCmp7, optMain), /* Optimize tests */ OptEntry (OptTest1, optMain), /* Remove unused loads */ diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index fa8b1d575..a849e7b8c 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -189,21 +189,21 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 0, /* size */ REG_A, /* use */ REG_NONE, /* chg */ - OF_SETF /* flags */ + OF_SETF | OF_CMP /* flags */ }, { OP65_CPX, /* opcode */ "cpx", /* mnemonic */ 0, /* size */ REG_X, /* use */ REG_NONE, /* chg */ - OF_SETF /* flags */ + OF_SETF | OF_CMP /* flags */ }, { OP65_CPY, /* opcode */ "cpy", /* mnemonic */ 0, /* size */ REG_Y, /* use */ REG_NONE, /* chg */ - OF_SETF /* flags */ + OF_SETF | OF_CMP /* flags */ }, { OP65_DEA, /* opcode */ "dea", /* mnemonic */ @@ -581,7 +581,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { static int FindCmp (const void* Key, const void* Desc) /* Compare function for FindOpcode */ -{ +{ return strcmp (Key, ((OPCDesc*)Desc)->Mnemo); } diff --git a/src/cc65/opcodes.h b/src/cc65/opcodes.h index 5ae3349a2..ec798db22 100644 --- a/src/cc65/opcodes.h +++ b/src/cc65/opcodes.h @@ -187,6 +187,7 @@ typedef enum { #define OF_CALL 0x0200U /* A subroutine call */ #define OF_REG_INCDEC 0x0400U /* A register increment or decrement */ #define OF_SETF 0x0800U /* Insn will set all load flags (not carry) */ +#define OF_CMP 0x1000U /* A compare A/X/Y instruction */ /* Combined infos */ #define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */