mirror of
https://github.com/cc65/cc65.git
synced 2024-10-07 23:56:05 +00:00
More optimizations
git-svn-id: svn://svn.cc65.org/cc65/trunk@970 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
9b9508cbd8
commit
8d0dfb5b41
@ -170,7 +170,7 @@ void g_preamble (void)
|
|||||||
AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
|
AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
|
||||||
|
|
||||||
/* Import the stack pointer for direct auto variable access */
|
/* 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 */
|
/* Define long branch macros */
|
||||||
AddTextLine ("\t.macpack\tlongbranch");
|
AddTextLine ("\t.macpack\tlongbranch");
|
||||||
@ -1701,11 +1701,27 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val)
|
|||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
case CF_INT:
|
case CF_INT:
|
||||||
if (flags & CF_CONST) {
|
|
||||||
g_getimmed (flags, val, 0);
|
|
||||||
}
|
|
||||||
ldyconst (offs);
|
ldyconst (offs);
|
||||||
|
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");
|
AddCodeLine ("jsr addeqysp");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AddCodeLine ("jsr addeqysp");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CF_LONG:
|
case CF_LONG:
|
||||||
|
@ -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)
|
static int IsCmpToZero (const CodeEntry* E)
|
||||||
/* Check if the given instrcuction is a compare to zero instruction */
|
/* Check if the given instrcuction is a compare to zero instruction */
|
||||||
{
|
{
|
||||||
@ -937,6 +951,10 @@ static unsigned OptCmp2 (CodeSeg* S)
|
|||||||
* lda/and/ora/eor ...
|
* lda/and/ora/eor ...
|
||||||
* cmp #$00
|
* cmp #$00
|
||||||
* jeq/jne
|
* jeq/jne
|
||||||
|
* or
|
||||||
|
* lda/and/ora/eor ...
|
||||||
|
* cmp #$00
|
||||||
|
* jsr boolxx
|
||||||
*
|
*
|
||||||
* and remove the cmp.
|
* and remove the cmp.
|
||||||
*/
|
*/
|
||||||
@ -967,7 +985,9 @@ static unsigned OptCmp2 (CodeSeg* S)
|
|||||||
CS_GetEntries (S, L, I+1, 2) &&
|
CS_GetEntries (S, L, I+1, 2) &&
|
||||||
IsCmpToZero (L[0]) &&
|
IsCmpToZero (L[0]) &&
|
||||||
!CE_HasLabel (L[0]) &&
|
!CE_HasLabel (L[0]) &&
|
||||||
(L[1]->Info & OF_FBRA) != 0 &&
|
((L[1]->Info & OF_FBRA) != 0 ||
|
||||||
|
(L[1]->OPC == OP65_JSR &&
|
||||||
|
FindBoolCmpCond (L[1]->Arg) != CMP_INV)) &&
|
||||||
!CE_HasLabel (L[1])) {
|
!CE_HasLabel (L[1])) {
|
||||||
|
|
||||||
/* Remove the compare */
|
/* Remove the compare */
|
||||||
@ -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 */
|
/* Optimize tests */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -2576,6 +2700,7 @@ static OptFunc OptFuncs [] = {
|
|||||||
OptEntry (OptCmp4, optMain),
|
OptEntry (OptCmp4, optMain),
|
||||||
OptEntry (OptCmp5, optMain),
|
OptEntry (OptCmp5, optMain),
|
||||||
OptEntry (OptCmp6, optMain),
|
OptEntry (OptCmp6, optMain),
|
||||||
|
OptEntry (OptCmp7, optMain),
|
||||||
/* Optimize tests */
|
/* Optimize tests */
|
||||||
OptEntry (OptTest1, optMain),
|
OptEntry (OptTest1, optMain),
|
||||||
/* Remove unused loads */
|
/* Remove unused loads */
|
||||||
|
@ -189,21 +189,21 @@ const OPCDesc OPCTable[OPCODE_COUNT] = {
|
|||||||
0, /* size */
|
0, /* size */
|
||||||
REG_A, /* use */
|
REG_A, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_SETF /* flags */
|
OF_SETF | OF_CMP /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_CPX, /* opcode */
|
{ OP65_CPX, /* opcode */
|
||||||
"cpx", /* mnemonic */
|
"cpx", /* mnemonic */
|
||||||
0, /* size */
|
0, /* size */
|
||||||
REG_X, /* use */
|
REG_X, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_SETF /* flags */
|
OF_SETF | OF_CMP /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_CPY, /* opcode */
|
{ OP65_CPY, /* opcode */
|
||||||
"cpy", /* mnemonic */
|
"cpy", /* mnemonic */
|
||||||
0, /* size */
|
0, /* size */
|
||||||
REG_Y, /* use */
|
REG_Y, /* use */
|
||||||
REG_NONE, /* chg */
|
REG_NONE, /* chg */
|
||||||
OF_SETF /* flags */
|
OF_SETF | OF_CMP /* flags */
|
||||||
},
|
},
|
||||||
{ OP65_DEA, /* opcode */
|
{ OP65_DEA, /* opcode */
|
||||||
"dea", /* mnemonic */
|
"dea", /* mnemonic */
|
||||||
|
@ -187,6 +187,7 @@ typedef enum {
|
|||||||
#define OF_CALL 0x0200U /* A subroutine call */
|
#define OF_CALL 0x0200U /* A subroutine call */
|
||||||
#define OF_REG_INCDEC 0x0400U /* A register increment or decrement */
|
#define OF_REG_INCDEC 0x0400U /* A register increment or decrement */
|
||||||
#define OF_SETF 0x0800U /* Insn will set all load flags (not carry) */
|
#define OF_SETF 0x0800U /* Insn will set all load flags (not carry) */
|
||||||
|
#define OF_CMP 0x1000U /* A compare A/X/Y instruction */
|
||||||
|
|
||||||
/* Combined infos */
|
/* Combined infos */
|
||||||
#define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */
|
#define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */
|
||||||
|
Loading…
Reference in New Issue
Block a user