diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 5508d2bee..57cb394e6 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -1112,7 +1112,7 @@ static unsigned OptDecouple (CodeSeg* S) /*****************************************************************************/ - + #if 0 static unsigned OptSize1 (CodeSeg* S) /* Do size optimization by calling special subroutines that preload registers. @@ -1369,7 +1369,8 @@ static OptFunc DOptDupLoads = { OptDupLoads, "OptDupLoads", 0, 0, 0, static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 0, 0, 0, 0, 0 }; static OptFunc DOptJumpTarget = { OptJumpTarget, "OptJumpTarget", 0, 0, 0, 0, 0 }; static OptFunc DOptRTS = { OptRTS, "OptRTS", 0, 0, 0, 0, 0 }; -static OptFunc DOptRTSJumps = { OptRTSJumps, "OptRTSJumps", 0, 0, 0, 0, 0 }; +static OptFunc DOptRTSJumps1 = { OptRTSJumps1, "OptRTSJumps1", 0, 0, 0, 0, 0 }; +static OptFunc DOptRTSJumps2 = { OptRTSJumps2, "OptRTSJumps2", 0, 0, 0, 0, 0 }; static OptFunc DOptNegA1 = { OptNegA1, "OptNegA1", 0, 0, 0, 0, 0 }; static OptFunc DOptNegA2 = { OptNegA2, "OptNegA2", 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX1 = { OptNegAX1, "OptNegAX1", 0, 0, 0, 0, 0 }; @@ -1434,7 +1435,8 @@ static OptFunc* OptFuncs[] = { &DOptPtrStore1, &DOptPtrStore2, &DOptRTS, - &DOptRTSJumps, + &DOptRTSJumps1, + &DOptRTSJumps2, &DOptShift1, &DOptShift2, /*&DOptSize1,*/ @@ -1726,7 +1728,7 @@ static void RunOptGroup3 (CodeSeg* S) Changes += RunOptFunc (S, &DOptDeadCode, 1); Changes += RunOptFunc (S, &DOptJumpTarget, 1); Changes += RunOptFunc (S, &DOptCondBranches, 1); - Changes += RunOptFunc (S, &DOptRTSJumps, 1); + Changes += RunOptFunc (S, &DOptRTSJumps1, 1); Changes += RunOptFunc (S, &DOptBoolTrans, 1); Changes += RunOptFunc (S, &DOptCmp1, 1); Changes += RunOptFunc (S, &DOptCmp2, 1); @@ -1762,8 +1764,15 @@ static void RunOptGroup4 (CodeSeg* S) */ RunOptFunc (S, &DOptJumpTarget, 5); - /* Finally, adjust branch distances */ + /* Adjust branch distances */ RunOptFunc (S, &DOptBranchDist, 3); + + /* Replace conditional branches to RTS. If we had changes, we must run dead + * code elimination again, since the change may have introduced dead code. + */ + if (RunOptFunc (S, &DOptRTSJumps2, 1)) { + RunOptFunc (S, &DOptDeadCode, 1); + } } diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 67ab7b6c5..c36e5a397 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -43,12 +43,12 @@ /*****************************************************************************/ -/* Replace jumps to RTS by RTS */ +/* Replace jumps to RTS by RTS */ /*****************************************************************************/ -unsigned OptRTSJumps (CodeSeg* S) +unsigned OptRTSJumps1 (CodeSeg* S) /* Replace jumps to RTS by RTS */ { unsigned Changes = 0; @@ -88,6 +88,64 @@ unsigned OptRTSJumps (CodeSeg* S) +unsigned OptRTSJumps2 (CodeSeg* S) +/* Replace long conditional jumps to RTS */ +{ + unsigned Changes = 0; + + /* Walk over all entries minus the last one */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* N; + + /* Get the next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if it's an unconditional branch to a local target */ + if ((E->Info & OF_CBRA) != 0 && /* Conditional branch */ + (E->Info & OF_LBRA) != 0 && /* Long branch */ + E->JumpTo != 0 && /* Local label */ + E->JumpTo->Owner->OPC == OP65_RTS && /* Target is an RTS */ + (N = CS_GetNextEntry (S, I)) != 0) { /* There is a next entry */ + + CodeEntry* X; + CodeLabel* LN; + opc_t NewBranch; + + /* We will create a jump around an RTS instead of the long branch */ + X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->JumpTo->Owner->LI); + CS_InsertEntry (S, X, I+1); + + /* Get the new branch opcode */ + NewBranch = MakeShortBranch (GetInverseBranch (E->OPC)); + + /* Get the label attached to N, create a new one if needed */ + LN = CS_GenLabel (S, N); + + /* Generate the branch */ + X = NewCodeEntry (NewBranch, AM65_BRA, LN->Name, LN, E->LI); + CS_InsertEntry (S, X, I+1); + + /* Delete the long branch */ + CS_DelEntry (S, I); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + /*****************************************************************************/ /* Remove dead jumps */ /*****************************************************************************/ diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index bb61f81ce..44fe8f1ce 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -49,9 +49,12 @@ -unsigned OptRTSJumps (CodeSeg* S); +unsigned OptRTSJumps1 (CodeSeg* S); /* Replace jumps to RTS by RTS */ +unsigned OptRTSJumps2 (CodeSeg* S); +/* Replace long conditional jumps to RTS */ + unsigned OptDeadJumps (CodeSeg* S); /* Remove dead jumps (jumps to the next instruction) */