From 4c2cc24e77b0f1ff375c9838564310c191dc603b Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 27 Jul 2025 00:01:47 +0200 Subject: [PATCH 1/4] Optimize jsr ldax0sp/incsp2 --- src/cc65/codeopt.c | 4 ++++ src/cc65/coptmisc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ src/cc65/coptmisc.h | 3 +++ 3 files changed, 58 insertions(+) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 0ba8a90d6..728e76d88 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -217,6 +217,7 @@ static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, static OptFunc DOptSub3 = { OptSub3, "OptSub3", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptTest1 = { OptTest1, "OptTest1", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptTest2 = { OptTest2, "OptTest2", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptTosLoadPop = { OptTosLoadPop, "OptTosLoadPop", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers1 = { OptTransfers1, "OptTransfers1", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers2 = { OptTransfers2, "OptTransfers2", 60, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers3 = { OptTransfers3, "OptTransfers3", 65, 0, 0, 0, 0, 0 }; @@ -347,6 +348,7 @@ static OptFunc* OptFuncs[] = { &DOptTransfers2, &DOptTransfers3, &DOptTransfers4, + &DOptTosLoadPop, &DOptUnusedLoads, &DOptUnusedStores, /* END SORTED_CODEOPT.SH */ @@ -635,6 +637,7 @@ static unsigned RunOptGroup1 (CodeSeg* S) Changes += RunOptFunc (S, &DOptGotoSPAdj, 1); Changes += RunOptFunc (S, &DOptStackPtrOps, 5); + Changes += RunOptFunc (S, &DOptTosLoadPop, 5); Changes += RunOptFunc (S, &DOptAXOps, 5); Changes += RunOptFunc (S, &DOptAdd3, 1); /* Before OptPtrLoad5! */ Changes += RunOptFunc (S, &DOptPtrStore1, 1); @@ -920,6 +923,7 @@ static unsigned RunOptGroup7 (CodeSeg* S) C += RunOptFunc (S, &DOptStackPtrOps, 5); /* Re-optimize JSR/RTS that may now be grouped */ C += RunOptFunc (S, &DOptRTS, 1); + C += RunOptFunc (S, &DOptTosLoadPop, 5); Changes += C; /* If we had changes, we must run dead code elimination again, diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index f52999285..0110dae4e 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -557,6 +557,57 @@ unsigned OptAXLoad (CodeSeg* S) +unsigned OptTosLoadPop (CodeSeg* S) +/* Merge jsr ldax0sp / jsr|jmp incsp2 into jsr|jmp popax */ +{ + unsigned Changes = 0; + unsigned I; + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + const CodeEntry* N; + + /* Get the next entry */ + const CodeEntry* E = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (E->OPC == OP65_JSR && + strncmp (E->Arg, "ldax0sp", 5) == 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && + strcmp (N->Arg, "incsp2") == 0 && + !CE_HasLabel (N)) { + + CodeEntry* X; + + X = NewCodeEntry (N->OPC, AM65_ABS, "popax", 0, N->LI); + CS_InsertEntry (S, X, I+2); + + /* 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 OptAXLoad2 (CodeSeg* S) /* Merge ldy/jsr incaxy/jsr ldaxi into ldy/jsr ldaxidx */ { diff --git a/src/cc65/coptmisc.h b/src/cc65/coptmisc.h index df76e84f4..ea678ea67 100644 --- a/src/cc65/coptmisc.h +++ b/src/cc65/coptmisc.h @@ -131,6 +131,9 @@ unsigned OptBinOps2 (CodeSeg* S); ** by something simpler. */ +unsigned OptTosLoadPop (CodeSeg* S); +/* Merge jsr ldax0sp / jsr|jmp incsp2 into jsr|jmp popax */ + /* End of coptmisc.h */ From 0647cb11120381e3ec892f199a77f9524aebcef2 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 20 Jul 2025 12:54:09 +0200 Subject: [PATCH 2/4] Merge jsr pushax/j?? popax into nothing or RTS --- src/cc65/codeopt.c | 5 ++++- src/cc65/coptmisc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ src/cc65/coptmisc.h | 3 ++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 728e76d88..326fe8d48 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -218,6 +218,7 @@ static OptFunc DOptSub3 = { OptSub3, "OptSub3", 100, 0, static OptFunc DOptTest1 = { OptTest1, "OptTest1", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptTest2 = { OptTest2, "OptTest2", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptTosLoadPop = { OptTosLoadPop, "OptTosLoadPop", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptTosPushPop = { OptTosPushPop, "OptTosPushPop", 33, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers1 = { OptTransfers1, "OptTransfers1", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers2 = { OptTransfers2, "OptTransfers2", 60, 0, 0, 0, 0, 0 }; static OptFunc DOptTransfers3 = { OptTransfers3, "OptTransfers3", 65, 0, 0, 0, 0, 0 }; @@ -344,11 +345,12 @@ static OptFunc* OptFuncs[] = { &DOptSub3, &DOptTest1, &DOptTest2, + &DOptTosLoadPop, + &DOptTosPushPop, &DOptTransfers1, &DOptTransfers2, &DOptTransfers3, &DOptTransfers4, - &DOptTosLoadPop, &DOptUnusedLoads, &DOptUnusedStores, /* END SORTED_CODEOPT.SH */ @@ -924,6 +926,7 @@ static unsigned RunOptGroup7 (CodeSeg* S) /* Re-optimize JSR/RTS that may now be grouped */ C += RunOptFunc (S, &DOptRTS, 1); C += RunOptFunc (S, &DOptTosLoadPop, 5); + C += RunOptFunc (S, &DOptTosPushPop, 5); Changes += C; /* If we had changes, we must run dead code elimination again, diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index 0110dae4e..0e3dd0d56 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -1201,3 +1201,54 @@ unsigned OptBinOps2 (CodeSeg* S) /* Return the number of changes made */ return Changes; } + + +unsigned OptTosPushPop(CodeSeg *S) +/* Merge jsr pushax/j?? popax */ +{ + unsigned Changes = 0; + unsigned I; + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + const CodeEntry* N; + + /* Get the next entry */ + const CodeEntry* E = CS_GetEntry (S, I); + + /* Check for decspn, incspn, subysp or addysp */ + if (E->OPC == OP65_JSR && + strcmp(E->Arg, "pushax") == 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && + strcmp(N->Arg, "popax") == 0 && + !CE_HasLabel (N)) { + + /* Delete the old code */ + CS_DelEntries (S, I, 2); + + /* Insert an rts if jmp popax */ + if (N->OPC == OP65_JMP) { + CodeEntry* X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->LI); + CS_InsertEntry (S, X, I); + } + + /* Regenerate register info */ + CS_GenRegInfo (S); + + /* Remember we had changes */ + ++Changes; + + } else { + + /* Next entry */ + ++I; + } + + } + + /* Return the number of changes made */ + return Changes; +} diff --git a/src/cc65/coptmisc.h b/src/cc65/coptmisc.h index ea678ea67..64c310d20 100644 --- a/src/cc65/coptmisc.h +++ b/src/cc65/coptmisc.h @@ -134,7 +134,8 @@ unsigned OptBinOps2 (CodeSeg* S); unsigned OptTosLoadPop (CodeSeg* S); /* Merge jsr ldax0sp / jsr|jmp incsp2 into jsr|jmp popax */ - +unsigned OptTosPushPop(CodeSeg *S); +/* Merge jsr pushax/j?? popax */ /* End of coptmisc.h */ From a0b705fd4194875f839d9f249723ddde4634c925 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 20 Jul 2025 15:22:59 +0200 Subject: [PATCH 3/4] Remove code after inserting new one --- src/cc65/coptmisc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index 0e3dd0d56..e21234cd1 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -1226,15 +1226,15 @@ unsigned OptTosPushPop(CodeSeg *S) strcmp(N->Arg, "popax") == 0 && !CE_HasLabel (N)) { - /* Delete the old code */ - CS_DelEntries (S, I, 2); - /* Insert an rts if jmp popax */ if (N->OPC == OP65_JMP) { CodeEntry* X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I); } + /* Delete the old code */ + CS_DelEntries (S, I+1, 2); + /* Regenerate register info */ CS_GenRegInfo (S); From 1f6cca2140eb3005e502a8bc38d083b27b8422f7 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 20 Jul 2025 16:06:34 +0200 Subject: [PATCH 4/4] Coding style --- src/cc65/codeent.h | 6 ++++++ src/cc65/coptmisc.c | 28 +++++++++------------------- src/cc65/coptmisc.h | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/cc65/codeent.h b/src/cc65/codeent.h index 3b2c1aa2d..b1b6f3365 100644 --- a/src/cc65/codeent.h +++ b/src/cc65/codeent.h @@ -244,6 +244,12 @@ static inline int CE_IsCallTo (const CodeEntry* E, const char* Name) return (E->OPC == OP65_JSR && strcmp (E->Arg, Name) == 0); } +static inline int CE_IsJumpTo (const CodeEntry* E, const char* Name) +/* Check if this is a jump to the given function */ +{ + return (E->OPC == OP65_JMP && strcmp (E->Arg, Name) == 0); +} + int CE_UseLoadFlags (CodeEntry* E); /* Return true if the instruction uses any flags that are set by a load of ** a register (N and Z). diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index e21234cd1..deca3fbe5 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -486,14 +486,14 @@ static unsigned OptIncDecOps (CodeSeg* S, const char* dec, const char* inc, cons unsigned OptStackPtrOps (CodeSeg* S) { - return OptIncDecOps(S, "decsp", "incsp", "subysp", "addysp"); + return OptIncDecOps (S, "decsp", "incsp", "subysp", "addysp"); } unsigned OptAXOps (CodeSeg* S) { - return OptIncDecOps(S, "decax", "incax", "decaxy", "incaxy"); + return OptIncDecOps (S, "decax", "incax", "decaxy", "incaxy"); } @@ -573,11 +573,9 @@ unsigned OptTosLoadPop (CodeSeg* S) const CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ - if (E->OPC == OP65_JSR && - strncmp (E->Arg, "ldax0sp", 5) == 0 && - (N = CS_GetNextEntry (S, I)) != 0 && - (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && - strcmp (N->Arg, "incsp2") == 0 && + if (CE_IsCallTo (E, "ldax0sp") && + (N = CS_GetNextEntry (S, I)) != 0 && + (CE_IsCallTo (N, "incsp2") || CE_IsJumpTo (N, "incsp2")) && !CE_HasLabel (N)) { CodeEntry* X; @@ -588,9 +586,6 @@ unsigned OptTosLoadPop (CodeSeg* S) /* Delete the old code */ CS_DelEntries (S, I, 2); - /* Regenerate register info */ - CS_GenRegInfo (S); - /* Remember we had changes */ ++Changes; @@ -1203,7 +1198,7 @@ unsigned OptBinOps2 (CodeSeg* S) } -unsigned OptTosPushPop(CodeSeg *S) +unsigned OptTosPushPop (CodeSeg* S) /* Merge jsr pushax/j?? popax */ { unsigned Changes = 0; @@ -1219,11 +1214,9 @@ unsigned OptTosPushPop(CodeSeg *S) const CodeEntry* E = CS_GetEntry (S, I); /* Check for decspn, incspn, subysp or addysp */ - if (E->OPC == OP65_JSR && - strcmp(E->Arg, "pushax") == 0 && - (N = CS_GetNextEntry (S, I)) != 0 && - (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && - strcmp(N->Arg, "popax") == 0 && + if (CE_IsCallTo (E, "pushax") && + (N = CS_GetNextEntry (S, I)) != 0 && + (CE_IsCallTo (N, "popax") || CE_IsJumpTo (N, "popax")) && !CE_HasLabel (N)) { /* Insert an rts if jmp popax */ @@ -1235,9 +1228,6 @@ unsigned OptTosPushPop(CodeSeg *S) /* Delete the old code */ CS_DelEntries (S, I+1, 2); - /* Regenerate register info */ - CS_GenRegInfo (S); - /* Remember we had changes */ ++Changes; diff --git a/src/cc65/coptmisc.h b/src/cc65/coptmisc.h index 64c310d20..7297fb5a0 100644 --- a/src/cc65/coptmisc.h +++ b/src/cc65/coptmisc.h @@ -134,7 +134,7 @@ unsigned OptBinOps2 (CodeSeg* S); unsigned OptTosLoadPop (CodeSeg* S); /* Merge jsr ldax0sp / jsr|jmp incsp2 into jsr|jmp popax */ -unsigned OptTosPushPop(CodeSeg *S); +unsigned OptTosPushPop (CodeSeg* S); /* Merge jsr pushax/j?? popax */ /* End of coptmisc.h */