1
0
mirror of https://github.com/cc65/cc65.git synced 2024-07-31 11:29:16 +00:00

More optimizations

git-svn-id: svn://svn.cc65.org/cc65/trunk@822 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-07-25 21:51:40 +00:00
parent ea2c59ef8e
commit d604ed5e3f
3 changed files with 203 additions and 45 deletions

View File

@ -1339,9 +1339,9 @@ void g_scale (unsigned flags, long val)
} else if (val > 0) { } else if (val > 0) {
/* Scale up */ /* Scale up */
if ((p2 = powerof2 (val)) > 0 && p2 <= 3) { if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
/* Factor is 2, 4 or 8, use special function */ /* Factor is 2, 4, 8 and 16, use special function */
switch (flags & CF_TYPE) { switch (flags & CF_TYPE) {
case CF_CHAR: case CF_CHAR:
@ -1354,11 +1354,11 @@ void g_scale (unsigned flags, long val)
/* FALLTHROUGH */ /* FALLTHROUGH */
case CF_INT: case CF_INT:
if (CodeSizeFactor >= (p2+1)*130U) { if (CodeSizeFactor >= (p2+1)*130U) {
AddCodeLine ("stx tmp1"); AddCodeLine ("stx tmp1");
while (p2--) { while (p2--) {
AddCodeLine ("asl a"); AddCodeLine ("asl a");
AddCodeLine ("rol tmp1"); AddCodeLine ("rol tmp1");
} }
AddCodeLine ("ldx tmp1"); AddCodeLine ("ldx tmp1");
} else { } else {
@ -1394,9 +1394,9 @@ void g_scale (unsigned flags, long val)
/* Scale down */ /* Scale down */
val = -val; val = -val;
if ((p2 = powerof2 (val)) > 0 && p2 <= 3) { if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
/* Factor is 2, 4 or 8, use special function */ /* Factor is 2, 4, 8 and 16 use special function */
switch (flags & CF_TYPE) { switch (flags & CF_TYPE) {
case CF_CHAR: case CF_CHAR:
@ -2959,7 +2959,7 @@ void g_asr (unsigned flags, unsigned long val)
case CF_CHAR: case CF_CHAR:
case CF_INT: case CF_INT:
if (val >= 1 && val <= 3) { if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shrax%ld", val); AddCodeLine ("jsr shrax%ld", val);
} else { } else {
@ -2974,7 +2974,7 @@ void g_asr (unsigned flags, unsigned long val)
break; break;
case CF_LONG: case CF_LONG:
if (val >= 1 && val <= 3) { if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shreax%ld", val); AddCodeLine ("jsr shreax%ld", val);
} else { } else {
@ -3042,7 +3042,7 @@ void g_asl (unsigned flags, unsigned long val)
case CF_CHAR: case CF_CHAR:
case CF_INT: case CF_INT:
if (val >= 1 && val <= 3) { if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shlax%ld", val); AddCodeLine ("jsr shlax%ld", val);
} else { } else {
@ -3057,7 +3057,7 @@ void g_asl (unsigned flags, unsigned long val)
break; break;
case CF_LONG: case CF_LONG:
if (val >= 1 && val <= 3) { if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shleax%ld", val); AddCodeLine ("jsr shleax%ld", val);
} else { } else {
@ -3559,16 +3559,31 @@ void g_le (unsigned flags, unsigned long val)
*/ */
if (flags & CF_CONST) { if (flags & CF_CONST) {
/* <= is not very effective on the 6502, so try to convert
* it into < if the value is in a valid range.
*/
/* Look at the type */ /* Look at the type */
switch (flags & CF_TYPE) { switch (flags & CF_TYPE) {
case CF_CHAR: case CF_CHAR:
if (flags & CF_FORCECHAR) { if (flags & CF_FORCECHAR) {
AddCodeLine ("cmp #$%02X", (unsigned char)val);
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr boolule"); if (val < 255) {
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
AddCodeLine ("jsr boolult");
} else {
AddCodeLine ("cmp #$%02X", (unsigned char)val);
AddCodeLine ("jsr boolule");
}
} else { } else {
AddCodeLine ("jsr boolle"); if (val < 127) {
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
AddCodeLine ("jsr boollt");
} else {
AddCodeLine ("cmp #$%02X", (unsigned char)val);
AddCodeLine ("jsr boolle");
}
} }
return; return;
} }
@ -3577,11 +3592,16 @@ void g_le (unsigned flags, unsigned long val)
case CF_INT: case CF_INT:
if (flags & CF_UNSIGNED) { if (flags & CF_UNSIGNED) {
unsigned L = GetLocalLabel(); unsigned L = GetLocalLabel();
const char* Name = "boolule";
if (val < 65535) {
++val;
Name = "boolult";
}
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("bne %s", LocalLabelName (L));
AddCodeLine ("cmp #$%02X", (unsigned char)val); AddCodeLine ("cmp #$%02X", (unsigned char)val);
g_defcodelabel (L); g_defcodelabel (L);
AddCodeLine ("jsr boolule"); AddCodeLine ("jsr %s", Name);
return; return;
} }
break; break;

View File

@ -125,9 +125,11 @@ static const FuncInfo FuncInfoTable[] = {
{ "shrax1", REG_AX, REG_AX }, { "shrax1", REG_AX, REG_AX },
{ "shrax2", REG_AX, REG_AX }, { "shrax2", REG_AX, REG_AX },
{ "shrax3", REG_AX, REG_AX }, { "shrax3", REG_AX, REG_AX },
{ "shrax4", REG_AX, REG_AX },
{ "shreax1", REG_AX, REG_AX }, { "shreax1", REG_AX, REG_AX },
{ "shreax2", REG_AX, REG_AX }, { "shreax2", REG_AX, REG_AX },
{ "shreax3", REG_AX, REG_AX }, { "shreax3", REG_AX, REG_AX },
{ "shreax4", REG_AX, REG_AX },
{ "staspidx", REG_A | REG_Y, REG_Y }, { "staspidx", REG_A | REG_Y, REG_Y },
{ "tosicmp", REG_AX, REG_AXY }, { "tosicmp", REG_AX, REG_AXY },
{ "tosdiva0", REG_AX, REG_AXY }, { "tosdiva0", REG_AX, REG_AXY },
@ -140,7 +142,7 @@ static const FuncInfo FuncInfoTable[] = {
{ "tosumula0", REG_AX, REG_AXY }, { "tosumula0", REG_AX, REG_AXY },
{ "tosumulax", REG_AX, REG_AXY }, { "tosumulax", REG_AX, REG_AXY },
{ "tosumuleax", REG_AX, REG_AXY }, { "tosumuleax", REG_AX, REG_AXY },
}; };
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0])) #define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
/* Table with names of zero page locations used by the compiler */ /* Table with names of zero page locations used by the compiler */

View File

@ -181,8 +181,8 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
* @L: ... * @L: ...
*/ */
if ((N = CS_GetNextEntry (S, I)) == 0) { if ((N = CS_GetNextEntry (S, I)) == 0) {
/* No such entry */ /* No such entry */
Internal ("Invalid program flow"); Internal ("Invalid program flow");
} }
L = CS_GenLabel (S, N); L = CS_GenLabel (S, N);
N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI); N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
@ -253,14 +253,6 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
static int IsBitOp (const CodeEntry* E)
/* Check if E is one of the bit operations (and, or, eor) */
{
return (E->OPC == OP65_AND || E->OPC == OP65_ORA || E->OPC == OP65_EOR);
}
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 */
{ {
@ -523,7 +515,7 @@ static unsigned OptSub2 (CodeSeg* S)
*/ */
if (CE_HasLabel (E)) { if (CE_HasLabel (E)) {
CS_MoveLabels (S, E, L[0]); CS_MoveLabels (S, E, L[0]);
} }
/* Remember, we had changes */ /* Remember, we had changes */
++Changes; ++Changes;
@ -683,7 +675,17 @@ static unsigned OptCmp2 (CodeSeg* S)
CodeEntry* E = CS_GetEntry (S, I); CodeEntry* E = CS_GetEntry (S, I);
/* Check for the sequence */ /* Check for the sequence */
if ((E->OPC == OP65_LDA || IsBitOp (E)) && if ((E->OPC == OP65_ADC ||
E->OPC == OP65_AND ||
E->OPC == OP65_DEA ||
E->OPC == OP65_EOR ||
E->OPC == OP65_INA ||
E->OPC == OP65_LDA ||
E->OPC == OP65_ORA ||
E->OPC == OP65_PLA ||
E->OPC == OP65_SBC ||
E->OPC == OP65_TXA ||
E->OPC == OP65_TYA) &&
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]) &&
@ -760,7 +762,7 @@ static unsigned OptCmp3 (CodeSeg* S)
CS_MoveEntry (S, I, I+4); CS_MoveEntry (S, I, I+4);
/* We will replace the ldx/cpx by lda/cmp */ /* We will replace the ldx/cpx by lda/cmp */
CE_ReplaceOPC (L[0], OP65_LDA); CE_ReplaceOPC (L[0], OP65_LDA);
CE_ReplaceOPC (L[1], OP65_CMP); CE_ReplaceOPC (L[1], OP65_CMP);
/* Beware: If the first LDA instruction had a label, we have /* Beware: If the first LDA instruction had a label, we have
@ -796,7 +798,7 @@ static unsigned OptCmp4 (CodeSeg* S)
* lda (sp),y * lda (sp),y
* cpx #a * cpx #a
* bne L1 * bne L1
* cmp #b * cmp #b
* jne/jeq L2 * jne/jeq L2
*/ */
{ {
@ -817,7 +819,7 @@ static unsigned OptCmp4 (CodeSeg* S)
* ldy #o * ldy #o
* lda (sp),y * lda (sp),y
* dey * dey
* ora (sp),y * ora (sp),y
* jne/jeq ... * jne/jeq ...
*/ */
CE_ReplaceOPC (L[4], OP65_ORA); CE_ReplaceOPC (L[4], OP65_ORA);
@ -910,7 +912,7 @@ static unsigned OptCmp5 (CodeSeg* S)
} }
/* Next entry */ /* Next entry */
++I; ++I;
} }
@ -921,6 +923,82 @@ static unsigned OptCmp5 (CodeSeg* S)
/*****************************************************************************/
/* Optimize tests */
/*****************************************************************************/
static unsigned OptTest1 (CodeSeg* S)
/* On a sequence
*
* stx xxx
* ora xxx
* beq/bne ...
*
* if X is zero, the sequence may be changed
*
* cmp #$00
* beq/bne ...
*
* which may be optimized further by another step.
*/
{
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)) {
CodeEntry* L[3];
/* Get next entry */
L[0] = CS_GetEntry (S, I);
/* Check if it's the sequence we're searching for */
if (L[0]->OPC == OP65_STX &&
L[0]->RI->In.RegX == 0 &&
CS_GetEntries (S, L+1, I+1, 2) &&
!CE_HasLabel (L[1]) &&
L[1]->OPC == OP65_ORA &&
strcmp (L[0]->Arg, L[1]->Arg) == 0 &&
!CE_HasLabel (L[2]) &&
(L[2]->Info & OF_ZBRA) != 0) {
/* Insert the compare */
CodeEntry* N = NewCodeEntry (OP65_CMP, AM65_IMM, "$00", 0, L[0]->LI);
CS_InsertEntry (S, N, I);
/* Remove the two other insns */
CS_DelEntry (S, I+2);
CS_DelEntry (S, I+1);
/* We had changes */
++Changes;
}
/* Next entry */
++I;
}
/* Free register info */
CS_FreeRegInfo (S);
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/ /*****************************************************************************/
/* nega optimizations */ /* nega optimizations */
/*****************************************************************************/ /*****************************************************************************/
@ -930,7 +1008,7 @@ static unsigned OptCmp5 (CodeSeg* S)
static unsigned OptNegA1 (CodeSeg* S) static unsigned OptNegA1 (CodeSeg* S)
/* Check for /* Check for
* *
* ldx #$00 * ldx #$00
* lda .. * lda ..
* jsr bnega * jsr bnega
* *
@ -953,7 +1031,7 @@ static unsigned OptNegA1 (CodeSeg* S)
E->AM == AM65_IMM && E->AM == AM65_IMM &&
(E->Flags & CEF_NUMARG) != 0 && (E->Flags & CEF_NUMARG) != 0 &&
E->Num == 0 && E->Num == 0 &&
CS_GetEntries (S, L, I+1, 2) && CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_LDA && L[0]->OPC == OP65_LDA &&
(L[0]->Use & REG_X) == 0 && (L[0]->Use & REG_X) == 0 &&
L[1]->OPC == OP65_JSR && L[1]->OPC == OP65_JSR &&
@ -1000,11 +1078,21 @@ static unsigned OptNegA2 (CodeSeg* S)
CodeEntry* E = CS_GetEntry (S, I); CodeEntry* E = CS_GetEntry (S, I);
/* Check for the sequence */ /* Check for the sequence */
if (E->OPC == OP65_LDA && if ((E->OPC == OP65_ADC ||
E->OPC == OP65_AND ||
E->OPC == OP65_DEA ||
E->OPC == OP65_EOR ||
E->OPC == OP65_INA ||
E->OPC == OP65_LDA ||
E->OPC == OP65_ORA ||
E->OPC == OP65_PLA ||
E->OPC == OP65_SBC ||
E->OPC == OP65_TXA ||
E->OPC == OP65_TYA) &&
CS_GetEntries (S, L, I+1, 2) && CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_JSR && L[0]->OPC == OP65_JSR &&
strcmp (L[0]->Arg, "bnega") == 0 && strcmp (L[0]->Arg, "bnega") == 0 &&
!CE_HasLabel (L[0]) && !CE_HasLabel (L[0]) &&
(L[1]->Info & OF_ZBRA) != 0) { (L[1]->Info & OF_ZBRA) != 0) {
/* Invert the branch */ /* Invert the branch */
@ -1036,6 +1124,52 @@ static unsigned OptNegA2 (CodeSeg* S)
static unsigned OptNegAX1 (CodeSeg* S) static unsigned OptNegAX1 (CodeSeg* S)
/* On a call to bnegax, if X is zero, the result depends only on the value in
* A, so change the call to a call to bnega. This will get further optimized
* later if possible.
*/
{
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)) {
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
/* Check if this is a call to bnegax, and if X is known and zero */
if (E->OPC == OP65_JSR &&
E->RI->In.RegX == 0 &&
strcmp (E->Arg, "bnegax") == 0) {
/* We're cheating somewhat here ... */
E->Arg[5] = '\0';
E->Use &= ~REG_X;
/* We had changes */
++Changes;
}
/* Next entry */
++I;
}
/* Free register info */
CS_FreeRegInfo (S);
/* Return the number of changes made */
return Changes;
}
static unsigned OptNegAX2 (CodeSeg* S)
/* Search for the sequence: /* Search for the sequence:
* *
* lda (xx),y * lda (xx),y
@ -1082,7 +1216,7 @@ static unsigned OptNegAX1 (CodeSeg* S)
/* lda --> ora */ /* lda --> ora */
CE_ReplaceOPC (L[2], OP65_ORA); CE_ReplaceOPC (L[2], OP65_ORA);
/* Invert the branch */ /* Invert the branch */
CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC)); CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
/* Delete the entries no longer needed. Beware: Deleting entries /* Delete the entries no longer needed. Beware: Deleting entries
@ -1107,7 +1241,7 @@ static unsigned OptNegAX1 (CodeSeg* S)
static unsigned OptNegAX2 (CodeSeg* S) static unsigned OptNegAX3 (CodeSeg* S)
/* Search for the sequence: /* Search for the sequence:
* *
* lda xx * lda xx
@ -1168,16 +1302,16 @@ static unsigned OptNegAX2 (CodeSeg* S)
static unsigned OptNegAX3 (CodeSeg* S) static unsigned OptNegAX4 (CodeSeg* S)
/* Search for the sequence: /* Search for the sequence:
* *
* jsr _xxx * jsr xxx
* jsr bnega(x) * jsr bnega(x)
* jeq/jne ... * jeq/jne ...
* *
* and replace it by: * and replace it by:
* *
* jsr _xxx * jsr xxx
* <boolean test> * <boolean test>
* jne/jeq ... * jne/jeq ...
*/ */
@ -1195,7 +1329,6 @@ static unsigned OptNegAX3 (CodeSeg* S)
/* Check for the sequence */ /* Check for the sequence */
if (E->OPC == OP65_JSR && if (E->OPC == OP65_JSR &&
E->Arg[0] == '_' &&
CS_GetEntries (S, L, I+1, 2) && CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_JSR && L[0]->OPC == OP65_JSR &&
strncmp (L[0]->Arg,"bnega",5) == 0 && strncmp (L[0]->Arg,"bnega",5) == 0 &&
@ -1211,7 +1344,7 @@ static unsigned OptNegAX3 (CodeSeg* S)
if (ByteSized) { if (ByteSized) {
/* Test bytes */ /* Test bytes */
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI); X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
CS_InsertEntry (S, X, I+2); CS_InsertEntry (S, X, I+2);
} else { } else {
/* Test words */ /* Test words */
X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI); X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
@ -1288,12 +1421,15 @@ static OptFunc OptFuncs [] = {
{ OptNegAX1, "OptNegAX1", 0 }, { OptNegAX1, "OptNegAX1", 0 },
{ OptNegAX2, "OptNegAX2", 0 }, { OptNegAX2, "OptNegAX2", 0 },
{ OptNegAX3, "OptNegAX3", 0 }, { OptNegAX3, "OptNegAX3", 0 },
{ OptNegAX4, "OptNegAX4", 0 },
/* Optimize compares */ /* Optimize compares */
{ OptCmp1, "OptCmp1", 0 }, { OptCmp1, "OptCmp1", 0 },
{ OptCmp2, "OptCmp2", 0 }, { OptCmp2, "OptCmp2", 0 },
{ OptCmp3, "OptCmp3", 0 }, { OptCmp3, "OptCmp3", 0 },
{ OptCmp4, "OptCmp4", 0 }, { OptCmp4, "OptCmp4", 0 },
{ OptCmp5, "OptCmp5", 0 }, { OptCmp5, "OptCmp5", 0 },
/* Optimize tests */
{ OptTest1, "OptTest1", 0 },
/* Remove unused loads */ /* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 }, { OptUnusedLoads, "OptUnusedLoads", 0 },
{ OptDuplicateLoads, "OptDuplicateLoads", 0 }, { OptDuplicateLoads, "OptDuplicateLoads", 0 },