Merge pull request #2778 from colinleroy/optimise-ldaxi

Optimise ldaxi
This commit is contained in:
Bob Andrews
2025-07-10 17:03:28 +02:00
committed by GitHub
4 changed files with 121 additions and 17 deletions

View File

@@ -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);

View File

@@ -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' */
{ {

View File

@@ -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
View 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