diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index c8d7d2ce9..19acfde74 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -119,7 +119,8 @@ static OptFunc DOptBNegAX1 = { OptBNegAX1, "OptBNegAX1", 100, 0, static OptFunc DOptBNegAX2 = { OptBNegAX2, "OptBNegAX2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBNegAX3 = { OptBNegAX3, "OptBNegAX3", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBNegAX4 = { OptBNegAX4, "OptBNegAX4", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptBinOps = { OptBinOps, "OptBinOps", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptBinOps1 = { OptBinOps1, "OptBinOps1", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptBinOps2 = { OptBinOps2, "OptBinOps2", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptBoolCmp = { OptBoolCmp, "OptBoolCmp", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBoolTrans = { OptBoolTrans, "OptBoolTrans", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptBoolUnary1 = { OptBoolUnary1, "OptBoolUnary1", 40, 0, 0, 0, 0, 0 }; @@ -154,6 +155,8 @@ static OptFunc DOptJumpTarget3 = { OptJumpTarget3, "OptJumpTarget3", 100, 0, static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad2 = { OptLoad2, "OptLoad2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad3 = { OptLoad3, "OptLoad3", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptLoadStore1 = { OptLoadStore1, "OptLoadStore1", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptLoadStore2 = { OptLoadStore2, "OptLoadStore2", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptLoadStoreLoad= { OptLoadStoreLoad,"OptLoadStoreLoad", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptLongAssign = { OptLongAssign, "OptLongAssign", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptLongCopy = { OptLongCopy, "OptLongCopy", 100, 0, 0, 0, 0, 0 }; @@ -238,7 +241,8 @@ static OptFunc* OptFuncs[] = { &DOptBNegAX2, &DOptBNegAX3, &DOptBNegAX4, - &DOptBinOps, + &DOptBinOps1, + &DOptBinOps2, &DOptBoolCmp, &DOptBoolTrans, &DOptBoolUnary1, @@ -273,6 +277,8 @@ static OptFunc* OptFuncs[] = { &DOptLoad1, &DOptLoad2, &DOptLoad3, + &DOptLoadStore1, + &DOptLoadStore2, &DOptLoadStoreLoad, &DOptLongAssign, &DOptLongCopy, @@ -649,6 +655,7 @@ static unsigned RunOptGroup1 (CodeSeg* S) Changes += RunOptFunc (S, &DOptSub1, 1); Changes += RunOptFunc (S, &DOptSub3, 1); Changes += RunOptFunc (S, &DOptLongAssign, 1); + Changes += RunOptFunc (S, &DOptLoadStore2, 1); Changes += RunOptFunc (S, &DOptStore4, 1); Changes += RunOptFunc (S, &DOptStore5, 1); Changes += RunOptFunc (S, &DOptShift1, 1); @@ -741,9 +748,10 @@ static unsigned RunOptGroup3 (CodeSeg* S) C += RunOptFunc (S, &DOptJumpTarget3, 1); /* After OptCondBranches2 */ C += RunOptFunc (S, &DOptUnusedLoads, 1); C += RunOptFunc (S, &DOptUnusedStores, 1); - C += RunOptFunc (S, &DOptDupLoads, 1); C += RunOptFunc (S, &DOptStoreLoad, 1); C += RunOptFunc (S, &DOptLoadStoreLoad, 1); + C += RunOptFunc (S, &DOptDupLoads, 1); + C += RunOptFunc (S, &DOptLoadStore1, 1); C += RunOptFunc (S, &DOptTransfers1, 1); C += RunOptFunc (S, &DOptTransfers3, 1); C += RunOptFunc (S, &DOptTransfers4, 1); @@ -755,7 +763,8 @@ static unsigned RunOptGroup3 (CodeSeg* S) C += RunOptFunc (S, &DOptPrecalc, 1); C += RunOptFunc (S, &DOptShiftBack, 1); C += RunOptFunc (S, &DOptSignExtended, 1); - C += RunOptFunc (S, &DOptBinOps, 1); + C += RunOptFunc (S, &DOptBinOps1, 1); + C += RunOptFunc (S, &DOptBinOps2, 1); Changes += C; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 52c47481e..99fc101a9 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -590,6 +590,49 @@ unsigned OptStoreLoad (CodeSeg* S) +unsigned OptLoadStore1 (CodeSeg* S) +/* Remove an 8 bit load followed by a store into the same location. */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* N; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if it is a load instruction followed by a store into the + ** same address. + */ + if ((E->Info & OF_LOAD) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + !CE_HasLabel (N) && + E->AM == N->AM && + ((E->OPC == OP65_LDA && N->OPC == OP65_STA) || + (E->OPC == OP65_LDX && N->OPC == OP65_STX) || + (E->OPC == OP65_LDY && N->OPC == OP65_STY)) && + strcmp (E->Arg, N->Arg) == 0) { + + /* Memory cell has already the correct value, remove the store */ + CS_DelEntry (S, I+1); + + /* Remember, we had changes */ + ++Changes; + } + + /* Next entry */ + ++I; + } + + /* Return the number of changes made */ + return Changes; +} + + + unsigned OptLoadStoreLoad (CodeSeg* S) /* Search for the sequence ** @@ -626,7 +669,7 @@ unsigned OptLoadStoreLoad (CodeSeg* S) strcmp (L[0]->Arg, L[2]->Arg) == 0) { /* Remove the second load */ - CS_DelEntries (S, I+2, 1); + CS_DelEntry (S, I+2); /* Remember, we had changes */ ++Changes; diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index 3493543a4..e54ba37d2 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -66,6 +66,9 @@ unsigned OptDupLoads (CodeSeg* S); unsigned OptStoreLoad (CodeSeg* S); /* Remove a store followed by a load from the same location. */ +unsigned OptLoadStore1 (CodeSeg* S); +/* Remove an 8 bit load followed by a store into the same location. */ + unsigned OptLoadStoreLoad (CodeSeg* S); /* Remove a load, store followed by a reload of the same location. */ diff --git a/src/cc65/coptmisc.c b/src/cc65/coptmisc.c index e48d469a1..b23ee6e0a 100644 --- a/src/cc65/coptmisc.c +++ b/src/cc65/coptmisc.c @@ -582,11 +582,57 @@ unsigned OptGotoSPAdj (CodeSeg* S) /*****************************************************************************/ -/* Optimize stack load ops */ +/* Optimize stack load/store ops */ /*****************************************************************************/ +unsigned OptLoadStore2 (CodeSeg* S) +/* Remove 16 bit stack loads followed by a store into the same location. */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* N; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if this is a 16 bit load followed by a store into the same + ** address. + */ + if (CE_IsCallTo (E, "ldaxysp") && /* Stack load ... */ + RegValIsKnown (E->RI->In.RegY) && /* ... with known offs */ + (N = CS_GetNextEntry (S, I)) != 0 && /* Next insn ... */ + !CE_HasLabel (N) && /* ... without label ... */ + N->OPC == OP65_LDY && /* ... is LDY */ + CE_IsKnownImm (N, E->RI->In.RegY-1) && /* Same offset as load */ + (N = CS_GetNextEntry (S, I+1)) != 0 && /* Next insn ... */ + !CE_HasLabel (N) && /* ... without label ... */ + CE_IsCallTo (N, "staxysp")) { /* ... is store */ + + /* Found - remove it. Leave the load in place. If it's unused, it + ** will get removed by later steps. + */ + CS_DelEntries (S, I+1, 2); + + /* Remember, we had changes */ + ++Changes; + } + + /* Next entry */ + ++I; + } + + /* Return the number of changes made */ + return Changes; +} + + + unsigned OptLoad1 (CodeSeg* S) /* Search for a call to ldaxysp where X is not used later and replace it by ** a load of just the A register. @@ -736,7 +782,7 @@ unsigned OptLoad2 (CodeSeg* S) -unsigned OptBinOps (CodeSeg* S) +unsigned OptBinOps1 (CodeSeg* S) /* Search for an AND/EOR/ORA where the value of A or the operand is known and ** replace it by something simpler. */ @@ -902,3 +948,59 @@ unsigned OptBinOps (CodeSeg* S) /* Return the number of changes made */ return Changes; } + + + +unsigned OptBinOps2 (CodeSeg* S) +/* Search for an AND/EOR/ORA for identical memory locations and replace it +** by something simpler. +*/ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* N; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if this is an 8 bit load followed by a bit operation with the + ** same memory cell. + */ + if (E->OPC == OP65_LDA && + (N = CS_GetNextEntry (S, I)) != 0 && /* Next insn ... */ + !CE_HasLabel (N) && /* ... without label ... */ + (N->OPC == OP65_AND || /* ... is AND/EOR/ORA ... */ + N->OPC == OP65_EOR || + N->OPC == OP65_ORA) && + E->AM == N->AM && /* ... with same addr mode ... */ + strcmp (E->Arg, N->Arg) == 0) { /* ... and same argument */ + + /* For an EOR, the result is zero. For the other instructions, the + ** result doesn't change so they can be removed. + */ + if (N->OPC == OP65_EOR) { + /* Simply insert a load of the now known value. The flags will + ** be correct because of the load and the preceeding + ** instructions will be removed by later steps. + */ + CodeEntry* X = NewCodeEntry (OP65_LDA, AM65_IMM, "$00", 0, N->LI); + CS_InsertEntry (S, X, I+2); + } else { + CS_DelEntry (S, I+1); + } + + /* Remember, we had changes */ + ++Changes; + } + + /* Next entry */ + ++I; + } + + /* Return the number of changes made */ + return Changes; +} diff --git a/src/cc65/coptmisc.h b/src/cc65/coptmisc.h index 418b61e94..aceaa55d3 100644 --- a/src/cc65/coptmisc.h +++ b/src/cc65/coptmisc.h @@ -99,6 +99,9 @@ unsigned OptStackPtrOps (CodeSeg* S); unsigned OptGotoSPAdj (CodeSeg* S); /* Optimize SP adjustment for forward 'goto' */ +unsigned OptLoadStore2 (CodeSeg* S); +/* Remove 16 bit stack loads followed by a store into the same location. */ + unsigned OptLoad1 (CodeSeg* S); /* Search for a call to ldaxysp where X is not used later and replace it by ** a load of just the A register. @@ -107,11 +110,16 @@ unsigned OptLoad1 (CodeSeg* S); unsigned OptLoad2 (CodeSeg* S); /* Replace calls to ldaxysp by inline code */ -unsigned OptBinOps (CodeSeg* S); +unsigned OptBinOps1 (CodeSeg* S); /* Search for an AND/EOR/ORA where the value of A or the operand is known and ** replace it by something simpler. */ +unsigned OptBinOps2 (CodeSeg* S); +/* Search for an AND/EOR/ORA for identical memory locations and replace it +** by something simpler. +*/ + /* End of coptmisc.h */