Merge pull request #2776 from colinleroy/optimize-incdecsp-further

Further optimize inc/decsp
This commit is contained in:
Bob Andrews
2025-07-10 17:02:32 +02:00
committed by GitHub
3 changed files with 83 additions and 30 deletions

View File

@@ -907,6 +907,11 @@ static unsigned RunOptGroup7 (CodeSeg* S)
between branches */ between branches */
C += RunOptFunc (S, &DOptBranchDist, 3); C += RunOptFunc (S, &DOptBranchDist, 3);
/* Re-optimize inc/decsp that may now be grouped */
C += RunOptFunc (S, &DOptStackPtrOps, 5);
/* Re-optimize JSR/RTS that may now be grouped */
C += RunOptFunc (S, &DOptRTS, 1);
Changes += C; Changes += C;
/* If we had changes, we must run dead code elimination again, /* If we had changes, we must run dead code elimination again,
** since the changes may have introduced dead code. ** since the changes may have introduced dead code.

View File

@@ -380,28 +380,37 @@ unsigned OptIndLoads2 (CodeSeg* S)
static unsigned IsDecSP (const CodeEntry* E) static signed IsSPShift (const CodeEntry* E)
/* Check if this is an insn that decrements the stack pointer. If so, return /* Check if this is an insn that increments/decrements the stack pointer.
** the decrement. If not, return zero. ** If so, return the value (negative for dec, positive for inc). If not, return zero.
** The function expects E to be a subroutine call.
*/ */
{ {
if (E->OPC != OP65_JSR && E->OPC != OP65_JMP) {
return 0;
}
if (strncmp (E->Arg, "decsp", 5) == 0) { if (strncmp (E->Arg, "decsp", 5) == 0) {
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
return -(E->Arg[5] - '0');
}
} else if (strcmp (E->Arg, "subysp") == 0 && RegValIsKnown (E->RI->In.RegY)) {
return -(E->RI->In.RegY);
} else if (strncmp (E->Arg, "incsp", 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, "addysp") == 0 && RegValIsKnown (E->RI->In.RegY)) {
return E->RI->In.RegY; return (E->RI->In.RegY);
} }
/* If we come here, it's not a decsp op */ /* If we come here, it's not a dec/incsp op */
return 0; return 0;
} }
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 inc/decsp into one. NOTE: This function won't merge all
** known cases! ** known cases!
*/ */
{ {
@@ -412,38 +421,45 @@ unsigned OptStackPtrOps (CodeSeg* S)
I = 0; I = 0;
while (I < CS_GetEntryCount (S)) { while (I < CS_GetEntryCount (S)) {
unsigned Dec1; signed Val1;
unsigned Dec2; signed Val2;
const CodeEntry* N; const CodeEntry* N;
/* Get the next entry */ /* Get the next entry */
const CodeEntry* E = CS_GetEntry (S, I); const CodeEntry* E = CS_GetEntry (S, I);
/* Check for decspn or subysp */ /* Check for decspn, incspn, subysp or addysp */
if (E->OPC == OP65_JSR && if (E->OPC == OP65_JSR &&
(Dec1 = IsDecSP (E)) > 0 && (Val1 = IsSPShift (E)) != 0 &&
(N = CS_GetNextEntry (S, I)) != 0 && (N = CS_GetNextEntry (S, I)) != 0 &&
(Dec2 = IsDecSP (N)) > 0 && (N->OPC == OP65_JSR || N->OPC == OP65_JMP) &&
(Dec1 += Dec2) <= 255 && (Val2 = IsSPShift (N)) != 0 &&
abs(Val1 += Val2) <= 255 &&
!CE_HasLabel (N)) { !CE_HasLabel (N)) {
CodeEntry* X; CodeEntry* X;
char Buf[20]; char Buf[20];
/* We can combine the two */ if (Val1 != 0) {
if (Dec1 <= 8) { /* We can combine the two */
/* Insert a call to decsp */ if (abs(Val1) <= 8) {
xsprintf (Buf, sizeof (Buf), "decsp%u", Dec1); /* Insert a call to inc/decsp using the last OPC */
X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, N->LI); xsprintf (Buf, sizeof (Buf), "%ssp%u", Val1 < 0 ? "dec":"inc", abs(Val1));
CS_InsertEntry (S, X, I+2); X = NewCodeEntry (N->OPC, AM65_ABS, Buf, 0, N->LI);
} else { CS_InsertEntry (S, X, I+2);
/* Insert a call to subysp */ } else {
const char* Arg = MakeHexArg (Dec1); /* Insert a call to subysp */
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI); const char* Arg = MakeHexArg (abs(Val1));
CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, N->LI); CS_InsertEntry (S, X, I+2);
CS_InsertEntry (S, X, I+3); if (Val1 < 0) {
} X = NewCodeEntry (N->OPC, AM65_ABS, "subysp", 0, N->LI);
} else {
X = NewCodeEntry (N->OPC, AM65_ABS, "addysp", 0, N->LI);
}
CS_InsertEntry (S, X, I+3);
}
} /* If total shift == 0, just drop the old code. */
/* Delete the old code */ /* Delete the old code */
CS_DelEntries (S, I, 2); CS_DelEntries (S, I, 2);

32
test/val/bug2748.c Normal file
View File

@@ -0,0 +1,32 @@
#include "unittest.h"
int func(int expr)
{
{
int i = 5;
return i;
}
}
static size_t c_sp_before, c_sp_after;
TEST
{
int a = 11;
int b;
__asm__("lda c_sp");
__asm__("ldx c_sp+1");
c_sp_before = __AX__;
b = func(a);
__asm__("lda c_sp");
__asm__("ldx c_sp+1");
c_sp_after = __AX__;
ASSERT_IsTrue(c_sp_before == c_sp_after, "Unexpected stack pointer");
ASSERT_IsTrue(b == 5, "Wrong value for b");
ASSERT_IsTrue(a == 11, "Wrong value for a");
}
ENDTEST