Optimize multiple incax* and incax*/ldaxi
- Group multiple calls to incax* and decax* into a single one - Replace incaxN/jsr ldaxi with ldy #N+1/jsr ldaxidx Fixes #2055
This commit is contained in:
@@ -113,6 +113,8 @@ static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 65, 0,
|
|||||||
static OptFunc DOptAdd4 = { OptAdd4, "OptAdd4", 90, 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd4 = { OptAdd4, "OptAdd4", 90, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptAdd5 = { OptAdd5, "OptAdd5", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd5 = { OptAdd5, "OptAdd5", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptAdd6 = { OptAdd6, "OptAdd6", 40, 0, 0, 0, 0, 0 };
|
static OptFunc DOptAdd6 = { OptAdd6, "OptAdd6", 40, 0, 0, 0, 0, 0 };
|
||||||
|
static OptFunc DOptAXLoad = { OptAXLoad, "OptAXLoad", 50, 0, 0, 0, 0, 0 };
|
||||||
|
static OptFunc DOptAXOps = { OptAXOps, "OptAXOps", 50, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptBNegA1 = { OptBNegA1, "OptBNegA1", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptBNegA1 = { OptBNegA1, "OptBNegA1", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptBNegA2 = { OptBNegA2, "OptBNegA2", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptBNegA2 = { OptBNegA2, "OptBNegA2", 100, 0, 0, 0, 0, 0 };
|
||||||
static OptFunc DOptBNegAX1 = { OptBNegAX1, "OptBNegAX1", 100, 0, 0, 0, 0, 0 };
|
static OptFunc DOptBNegAX1 = { OptBNegAX1, "OptBNegAX1", 100, 0, 0, 0, 0, 0 };
|
||||||
@@ -236,6 +238,7 @@ static OptFunc* OptFuncs[] = {
|
|||||||
&DOptAdd4,
|
&DOptAdd4,
|
||||||
&DOptAdd5,
|
&DOptAdd5,
|
||||||
&DOptAdd6,
|
&DOptAdd6,
|
||||||
|
&DOptAXOps,
|
||||||
&DOptBNegA1,
|
&DOptBNegA1,
|
||||||
&DOptBNegA2,
|
&DOptBNegA2,
|
||||||
&DOptBNegAX1,
|
&DOptBNegAX1,
|
||||||
@@ -629,6 +632,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
|
|||||||
|
|
||||||
Changes += RunOptFunc (S, &DOptGotoSPAdj, 1);
|
Changes += RunOptFunc (S, &DOptGotoSPAdj, 1);
|
||||||
Changes += RunOptFunc (S, &DOptStackPtrOps, 5);
|
Changes += RunOptFunc (S, &DOptStackPtrOps, 5);
|
||||||
|
Changes += RunOptFunc (S, &DOptAXOps, 5);
|
||||||
Changes += RunOptFunc (S, &DOptAdd3, 1); /* Before OptPtrLoad5! */
|
Changes += RunOptFunc (S, &DOptAdd3, 1); /* Before OptPtrLoad5! */
|
||||||
Changes += RunOptFunc (S, &DOptPtrStore1, 1);
|
Changes += RunOptFunc (S, &DOptPtrStore1, 1);
|
||||||
Changes += RunOptFunc (S, &DOptPtrStore2, 1);
|
Changes += RunOptFunc (S, &DOptPtrStore2, 1);
|
||||||
@@ -871,6 +875,7 @@ static unsigned RunOptGroup7 (CodeSeg* S)
|
|||||||
** may have opened new oportunities.
|
** may have opened new oportunities.
|
||||||
*/
|
*/
|
||||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||||
|
Changes += RunOptFunc (S, &DOptAXLoad, 5);
|
||||||
Changes += RunOptFunc (S, &DOptUnusedStores, 1);
|
Changes += RunOptFunc (S, &DOptUnusedStores, 1);
|
||||||
Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
|
Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
|
||||||
Changes += RunOptFunc (S, &DOptStore5, 1);
|
Changes += RunOptFunc (S, &DOptStore5, 1);
|
||||||
|
|||||||
@@ -380,8 +380,8 @@ unsigned OptIndLoads2 (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static signed IsSPShift (const CodeEntry* E)
|
static signed IsShift (const CodeEntry* E, const char* dec, const char* inc, const char* sub, const char* add)
|
||||||
/* Check if this is an insn that increments/decrements the stack pointer.
|
/* Check if this is an insn that increments/decrements the stack pointer or AX.
|
||||||
** If so, return the value (negative for dec, positive for inc). If not, return zero.
|
** If so, return the value (negative for dec, positive for inc). If not, return zero.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@@ -389,28 +389,28 @@ static signed IsSPShift (const CodeEntry* E)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp (E->Arg, "decsp", 5) == 0) {
|
if (strncmp (E->Arg, dec, 5) == 0) {
|
||||||
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
|
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
|
||||||
return -(E->Arg[5] - '0');
|
return -(E->Arg[5] - '0');
|
||||||
}
|
}
|
||||||
} else if (strcmp (E->Arg, "subysp") == 0 && RegValIsKnown (E->RI->In.RegY)) {
|
} else if (strcmp (E->Arg, sub) == 0 && RegValIsKnown (E->RI->In.RegY)) {
|
||||||
return -(E->RI->In.RegY);
|
return -(E->RI->In.RegY);
|
||||||
} else if (strncmp (E->Arg, "incsp", 5) == 0) {
|
} else if (strncmp (E->Arg, inc, 5) == 0) {
|
||||||
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
|
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
|
||||||
return (E->Arg[5] - '0');
|
return (E->Arg[5] - '0');
|
||||||
}
|
}
|
||||||
} else if (strcmp (E->Arg, "addysp") == 0 && RegValIsKnown (E->RI->In.RegY)) {
|
} else if (strcmp (E->Arg, add) == 0 && RegValIsKnown (E->RI->In.RegY)) {
|
||||||
return (E->RI->In.RegY);
|
return (E->RI->In.RegY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we come here, it's not a dec/incsp op */
|
/* If we come here, it's not a dec/inc op */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned OptStackPtrOps (CodeSeg* S)
|
static unsigned OptIncDecOps (CodeSeg* S, const char* dec, const char* inc, const char* sub, const char* add)
|
||||||
/* Merge adjacent calls to inc/decsp into one. NOTE: This function won't merge all
|
/* Merge adjacent calls to inc/dec/add/sub into one. NOTE: This function won't merge all
|
||||||
** known cases!
|
** known cases!
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@@ -430,10 +430,10 @@ unsigned OptStackPtrOps (CodeSeg* S)
|
|||||||
|
|
||||||
/* Check for decspn, incspn, subysp or addysp */
|
/* Check for decspn, incspn, subysp or addysp */
|
||||||
if (E->OPC == OP65_JSR &&
|
if (E->OPC == OP65_JSR &&
|
||||||
(Val1 = IsSPShift (E)) != 0 &&
|
(Val1 = IsShift (E, dec, inc, sub, add)) != 0 &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
(N->OPC == OP65_JSR || N->OPC == OP65_JMP) &&
|
(N->OPC == OP65_JSR || N->OPC == OP65_JMP) &&
|
||||||
(Val2 = IsSPShift (N)) != 0 &&
|
(Val2 = IsShift (N, dec, inc, sub, add)) != 0 &&
|
||||||
abs(Val1 += Val2) <= 255 &&
|
abs(Val1 += Val2) <= 255 &&
|
||||||
!CE_HasLabel (N)) {
|
!CE_HasLabel (N)) {
|
||||||
|
|
||||||
@@ -443,19 +443,19 @@ unsigned OptStackPtrOps (CodeSeg* S)
|
|||||||
if (Val1 != 0) {
|
if (Val1 != 0) {
|
||||||
/* We can combine the two */
|
/* We can combine the two */
|
||||||
if (abs(Val1) <= 8) {
|
if (abs(Val1) <= 8) {
|
||||||
/* Insert a call to inc/decsp using the last OPC */
|
/* Insert a call to inc/dec using the last OPC */
|
||||||
xsprintf (Buf, sizeof (Buf), "%ssp%u", Val1 < 0 ? "dec":"inc", abs(Val1));
|
xsprintf (Buf, sizeof (Buf), "%s%u", Val1 < 0 ? dec:inc, abs(Val1));
|
||||||
X = NewCodeEntry (N->OPC, AM65_ABS, Buf, 0, N->LI);
|
X = NewCodeEntry (N->OPC, AM65_ABS, Buf, 0, N->LI);
|
||||||
CS_InsertEntry (S, X, I+2);
|
CS_InsertEntry (S, X, I+2);
|
||||||
} else {
|
} else {
|
||||||
/* Insert a call to subysp */
|
/* Insert a call to add/sub */
|
||||||
const char* Arg = MakeHexArg (abs(Val1));
|
const char* Arg = MakeHexArg (abs(Val1));
|
||||||
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
|
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
|
||||||
CS_InsertEntry (S, X, I+2);
|
CS_InsertEntry (S, X, I+2);
|
||||||
if (Val1 < 0) {
|
if (Val1 < 0) {
|
||||||
X = NewCodeEntry (N->OPC, AM65_ABS, "subysp", 0, N->LI);
|
X = NewCodeEntry (N->OPC, AM65_ABS, sub, 0, N->LI);
|
||||||
} else {
|
} else {
|
||||||
X = NewCodeEntry (N->OPC, AM65_ABS, "addysp", 0, N->LI);
|
X = NewCodeEntry (N->OPC, AM65_ABS, add, 0, N->LI);
|
||||||
}
|
}
|
||||||
CS_InsertEntry (S, X, I+3);
|
CS_InsertEntry (S, X, I+3);
|
||||||
}
|
}
|
||||||
@@ -484,6 +484,77 @@ unsigned OptStackPtrOps (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptStackPtrOps (CodeSeg* S)
|
||||||
|
{
|
||||||
|
return OptIncDecOps(S, "decsp", "incsp", "subysp", "addysp");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptAXOps (CodeSeg* S)
|
||||||
|
{
|
||||||
|
return OptIncDecOps(S, "decax", "incax", "decaxy", "incaxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptAXLoad (CodeSeg* S)
|
||||||
|
/* Merge jsr incax/jsr ldaxi into ldy/jsr ldaxidx */
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
unsigned I;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
I = 0;
|
||||||
|
while (I < CS_GetEntryCount (S)) {
|
||||||
|
|
||||||
|
signed Val;
|
||||||
|
const CodeEntry* N;
|
||||||
|
|
||||||
|
/* Get the next entry */
|
||||||
|
const CodeEntry* E = CS_GetEntry (S, I);
|
||||||
|
|
||||||
|
/* Check for incax followed by jsr/jmp ldaxi */
|
||||||
|
if (E->OPC == OP65_JSR &&
|
||||||
|
strncmp (E->Arg, "incax", 5) == 0 &&
|
||||||
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
|
(N->OPC == OP65_JSR || N->OPC == OP65_JMP) &&
|
||||||
|
strcmp (N->Arg, "ldaxi") == 0 &&
|
||||||
|
!CE_HasLabel (N)) {
|
||||||
|
|
||||||
|
CodeEntry* X;
|
||||||
|
const char* Arg;
|
||||||
|
|
||||||
|
Val = E->Arg[5] - '0';
|
||||||
|
Arg = MakeHexArg (Val + 1);
|
||||||
|
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
|
||||||
|
CS_InsertEntry (S, X, I+2);
|
||||||
|
X = NewCodeEntry (N->OPC, AM65_ABS, "ldaxidx", 0, N->LI);
|
||||||
|
CS_InsertEntry (S, X, I+3);
|
||||||
|
|
||||||
|
/* Delete the old code */
|
||||||
|
CS_DelEntries (S, I, 2);
|
||||||
|
|
||||||
|
/* Regenerate register info */
|
||||||
|
CS_GenRegInfo (S);
|
||||||
|
|
||||||
|
/* Remember we had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned OptGotoSPAdj (CodeSeg* S)
|
unsigned OptGotoSPAdj (CodeSeg* S)
|
||||||
/* Optimize SP adjustment for forward 'goto' */
|
/* Optimize SP adjustment for forward 'goto' */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -92,10 +92,18 @@ unsigned OptIndLoads2 (CodeSeg* S);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned OptStackPtrOps (CodeSeg* S);
|
unsigned OptStackPtrOps (CodeSeg* S);
|
||||||
/* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
|
/* Merge adjacent calls to decsp/incax into one. NOTE: This function won't merge all
|
||||||
** known cases!
|
** known cases!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
unsigned OptAXOps (CodeSeg* S);
|
||||||
|
/* Merge adjacent calls to decax/incax into one. NOTE: This function won't merge all
|
||||||
|
** known cases!
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned OptAXLoad (CodeSeg* S);
|
||||||
|
/* Merge adjacent calls to incax/ldaxi into ldy/ldaxidx */
|
||||||
|
|
||||||
unsigned OptGotoSPAdj (CodeSeg* S);
|
unsigned OptGotoSPAdj (CodeSeg* S);
|
||||||
/* Optimize SP adjustment for forward 'goto' */
|
/* Optimize SP adjustment for forward 'goto' */
|
||||||
|
|
||||||
|
|||||||
20
test/val/bug2205.c
Normal file
20
test/val/bug2205.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "unittest.h"
|
||||||
|
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
int data[10];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Object object_data = { 0x0102, {0x0304, 0x0506,
|
||||||
|
0x0708, 0x090A, 0x0B0C,
|
||||||
|
0x0D0E, 0x0F10, 0x1112,
|
||||||
|
0x1314, 0x1516}};
|
||||||
|
|
||||||
|
TEST
|
||||||
|
{
|
||||||
|
struct Object *o = &object_data;
|
||||||
|
ASSERT_IsTrue(o->a == 0x0102, "Wrong value for a");
|
||||||
|
ASSERT_IsTrue(o->data[2] == 0x0708, "Wrong value for data[2]");
|
||||||
|
}
|
||||||
|
ENDTEST
|
||||||
Reference in New Issue
Block a user