diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index cc223c55b..0ba8a90d6 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -108,6 +108,7 @@ static OptFunc DOpt65C02BitOps = { Opt65C02BitOps, "Opt65C02BitOps", 66, 0, static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 100, 0, 0, 0, 0, 0 }; static OptFunc DOpt65C02Stores = { Opt65C02Stores, "Opt65C02Stores", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptAXLoad = { OptAXLoad, "OptAXLoad", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptAXLoad2 = { OptAXLoad2, "OptAXLoad2", 66, 0, 0, 0, 0, 0 }; static OptFunc DOptAXOps = { OptAXOps, "OptAXOps", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 125, 0, 0, 0, 0, 0 }; static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 200, 0, 0, 0, 0, 0 }; @@ -233,6 +234,7 @@ static OptFunc* OptFuncs[] = { &DOpt65C02Ind, &DOpt65C02Stores, &DOptAXLoad, + &DOptAXLoad2, &DOptAXOps, &DOptAdd1, &DOptAdd2, @@ -877,6 +879,7 @@ static unsigned RunOptGroup7 (CodeSeg* S) */ Changes += RunOptFunc (S, &DOptUnusedLoads, 1); Changes += RunOptFunc (S, &DOptAXLoad, 5); + Changes += RunOptFunc (S, &DOptAXLoad2, 5); Changes += RunOptFunc (S, &DOptUnusedStores, 1); Changes += RunOptFunc (S, &DOptJumpTarget1, 5); Changes += RunOptFunc (S, &DOptStore5, 1); diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index 0ba447562..f52999285 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -434,7 +434,7 @@ static unsigned OptIncDecOps (CodeSeg* S, const char* dec, const char* inc, cons (N = CS_GetNextEntry (S, I)) != 0 && (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && (Val2 = IsShift (N, dec, inc, sub, add)) != 0 && - abs(Val1 += Val2) <= 255 && + abs (Val1 += Val2) <= 255 && !CE_HasLabel (N)) { CodeEntry* X; @@ -442,14 +442,14 @@ static unsigned OptIncDecOps (CodeSeg* S, const char* dec, const char* inc, cons if (Val1 != 0) { /* We can combine the two */ - if (abs(Val1) <= 8) { + if (abs (Val1) <= 8) { /* Insert a call to inc/dec using the last OPC */ - xsprintf (Buf, sizeof (Buf), "%s%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); CS_InsertEntry (S, X, I+2); } else { /* 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); CS_InsertEntry (S, X, I+2); if (Val1 < 0) { @@ -499,7 +499,7 @@ unsigned OptAXOps (CodeSeg* S) unsigned OptAXLoad (CodeSeg* S) -/* Merge jsr incax/jsr ldaxi into ldy/jsr ldaxidx */ +/* Merge jsr incax[1-8]/jsr ldaxi into ldy/jsr ldaxidx */ { unsigned Changes = 0; unsigned I; @@ -514,9 +514,11 @@ unsigned OptAXLoad (CodeSeg* S) /* Get the next entry */ const CodeEntry* E = CS_GetEntry (S, I); - /* Check for incax followed by jsr/jmp ldaxi */ + /* Check for incax[1-8] followed by jsr/jmp ldaxi */ if (E->OPC == OP65_JSR && strncmp (E->Arg, "incax", 5) == 0 && + E->Arg[5] >= '1' && E->Arg[5] <= '8' && + E->Arg[6] == '\0' && (N = CS_GetNextEntry (S, I)) != 0 && (N->OPC == OP65_JSR || N->OPC == OP65_JMP) && strcmp (N->Arg, "ldaxi") == 0 && @@ -555,6 +557,63 @@ unsigned OptAXLoad (CodeSeg* S) +unsigned OptAXLoad2 (CodeSeg* S) +/* Merge ldy/jsr incaxy/jsr ldaxi into ldy/jsr ldaxidx */ +{ + unsigned Changes = 0; + unsigned I; + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + signed Val; + CodeEntry* E[3]; + CodeEntry* X; + + /* Get the next entry */ + E[0] = CS_GetEntry (S, I); + + /* Check for ldy followed by incaxy followed by jsr/jmp ldaxi */ + if (E[0]->OPC == OP65_LDY && + CE_IsConstImm (E[0]) && + CS_GetEntries (S, E+1, I+1, 2) && + E[1]->OPC == OP65_JSR && + strcmp (E[1]->Arg, "incaxy") == 0 && + (E[2]->OPC == OP65_JSR || E[2]->OPC == OP65_JMP) && + strcmp (E[2]->Arg, "ldaxi") == 0 && + !CS_RangeHasLabel (S, I, 3)) { + + /* Replace with ldy (y+1) / jsr ldaxidx */ + Val = E[0]->Num + 1; + + X = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Val), 0, E[0]->LI); + CS_InsertEntry (S, X, I+3); + X = NewCodeEntry (E[2]->OPC, AM65_ABS, "ldaxidx", 0, E[0]->LI); + CS_InsertEntry (S, X, I+4); + + CS_DelEntries (S, I, 3); + + /* 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) /* Optimize SP adjustment for forward 'goto' */ { diff --git a/src/cc65/coptmisc.h b/src/cc65/coptmisc.h index cc6d1c519..df76e84f4 100644 --- a/src/cc65/coptmisc.h +++ b/src/cc65/coptmisc.h @@ -102,7 +102,10 @@ unsigned OptAXOps (CodeSeg* S); */ unsigned OptAXLoad (CodeSeg* S); -/* Merge adjacent calls to incax/ldaxi into ldy/ldaxidx */ +/* Merge jsr incax[1-8]/jsr ldaxi into ldy/jsr ldaxidx */ + +unsigned OptAXLoad2 (CodeSeg* S); +/* Merge ldy/jsr incaxy/jsr ldaxi into ldy/jsr ldaxidx */ unsigned OptGotoSPAdj (CodeSeg* S); /* Optimize SP adjustment for forward 'goto' */ diff --git a/test/val/bug2205.c b/test/val/bug2205.c index 1b5458249..0ca78e9b1 100644 --- a/test/val/bug2205.c +++ b/test/val/bug2205.c @@ -3,18 +3,23 @@ struct Object { int a; - int data[10]; + int data[20]; }; struct Object object_data = { 0x0102, {0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F10, 0x1112, - 0x1314, 0x1516}}; + 0x1314, 0x1516, 0x1718, + 0x1920, 0x2122, 0x2324, + 0x2526, 0x2728, 0x2930, + 0x3132, 0x3334, 0x3536}}; 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]"); + ASSERT_IsTrue(o->data[8] == 0x1314, "Wrong value for data[8]"); + ASSERT_IsTrue(o->data[19] == 0x3536, "Wrong value for data[19]"); } ENDTEST