mirror of
https://github.com/cc65/cc65.git
synced 2024-10-20 08:24:29 +00:00
More optimizations
git-svn-id: svn://svn.cc65.org/cc65/trunk@822 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
ea2c59ef8e
commit
d604ed5e3f
@ -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:
|
||||||
@ -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,17 +3559,32 @@ 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 {
|
} else {
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
|
AddCodeLine ("jsr boolule");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (val < 127) {
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
|
||||||
|
AddCodeLine ("jsr boollt");
|
||||||
|
} else {
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
AddCodeLine ("jsr boolle");
|
AddCodeLine ("jsr boolle");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
@ -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;
|
||||||
|
@ -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 },
|
||||||
|
@ -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 */
|
||||||
{
|
{
|
||||||
@ -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]) &&
|
||||||
@ -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 */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -1000,7 +1078,17 @@ 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 &&
|
||||||
@ -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
|
||||||
@ -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 &&
|
||||||
@ -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 },
|
||||||
|
Loading…
Reference in New Issue
Block a user