unsigned OptRTSJumps2 (CodeSeg* S)
-/* Replace long conditional jumps to RTS */
+/* Replace long conditional jumps to RTS or to a final target */
{
unsigned Changes = 0;
/* Walk over all entries minus the last one */
unsigned I = 0;
- while (I < CS_GetEntryCount (S)) {
-
- CodeEntry* N;
+ while (I < CS_GetEntryCount (S) - 1) {
/* Get the next entry */
CodeEntry* E = CS_GetEntry (S, I);
- /* Check if it's an unconditional branch to a local target */
+ /* Check if it's an conditional 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 */
+ E->JumpTo != 0) { /* Local label */
- 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 jump target and the next entry. There's always a next
+ * entry, because we don't cover the last entry in the loop.
+ */
+ CodeEntry* X = 0;
+ CodeEntry* T = E->JumpTo->Owner;
+ CodeEntry* N = CS_GetNextEntry (S, I);
- /* Get the new branch opcode */
- NewBranch = MakeShortBranch (GetInverseBranch (E->OPC));
+ /* Check if it's a jump to an RTS insn */
+ if (T->OPC == OP65_RTS) {
- /* Get the label attached to N, create a new one if needed */
- LN = CS_GenLabel (S, N);
+ /* It's a jump to RTS. Create a conditional branch around an
+ * RTS insn.
+ */
+ X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, T->LI);
- /* Generate the branch */
- X = NewCodeEntry (NewBranch, AM65_BRA, LN->Name, LN, E->LI);
- CS_InsertEntry (S, X, I+1);
+ } else if (T->OPC == OP65_JMP && T->JumpTo == 0) {
- /* Delete the long branch */
- CS_DelEntry (S, I);
+ /* It's a jump to a label outside the function. Create a
+ * conditional branch around a jump to the external label.
+ */
+ X = NewCodeEntry (OP65_JMP, AM65_ABS, T->Arg, T->JumpTo, T->LI);
- /* Remember, we had changes */
- ++Changes;
+ }
+
+ /* If we have a replacement insn, insert it */
+ if (X) {
+
+ CodeLabel* LN;
+ opc_t NewBranch;
+
+ /* Insert the new insn */
+ CS_InsertEntry (S, X, I+1);
+ /* Create a conditional branch with the inverse condition
+ * around the replacement insn
+ */
+
+ /* 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 */
/* Get this entry */
CodeEntry* E = CS_GetEntry (S, I);
- /* Check if it's a branch, if it has a jump label, if this jump
- * label is not attached to the instruction itself, and if the
- * target instruction is itself a branch.
+ /* Check:
+ * - if it's a branch,
+ * - if it has a jump label,
+ * - if this jump label is not attached to the instruction itself,
+ * - if the target instruction is itself a branch,
+ * - if either the first branch is unconditional or the target of
+ * the second branch is internal to the function.
+ * The latter condition will avoid conditional branches to targets
+ * outside of the function (usually incspx), which won't simplify the
+ * code, since conditional far branches are emulated by a short branch
+ * around a jump.
*/
- if ((E->Info & OF_BRA) != 0 &&
- (OldLabel = E->JumpTo) != 0 &&
- (N = OldLabel->Owner) != E &&
- (N->Info & OF_BRA) != 0) {
+ if ((E->Info & OF_BRA) != 0 &&
+ (OldLabel = E->JumpTo) != 0 &&
+ (N = OldLabel->Owner) != E &&
+ (N->Info & OF_BRA) != 0 &&
+ ((E->Info & OF_CBRA) == 0 ||
+ N->JumpTo != 0)) {
/* Check if we can use the final target label. This is the case,
* if the target branch is an absolut branch, or if it is a
I = 0;
while (I < CS_GetEntryCount (S)) {
- unsigned J, K;
CodeEntry* N;
- /* New jump label */
- CodeLabel* LN = 0;
-
/* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
+ CodeEntry* E = CS_GetEntry (S, I);
- /* Check if this is a load insn with a label */
+ /* Check if this is a load insn with a label and the next insn is not
+ * a conditional branch that needs the flags from the load.
+ */
if ((E->Info & OF_LOAD) != 0 &&
CE_IsConstImm (E) &&
CE_HasLabel (E) &&
- (N = CS_GetNextEntry (S, I)) != 0) {
+ (N = CS_GetNextEntry (S, I)) != 0 &&
+ !CE_UseLoadFlags (N)) {
+
+ unsigned J;
+ int K;
+
+ /* New jump label */
+ CodeLabel* LN = 0;
/* Walk over all insn that jump here */
for (J = 0; J < CE_GetLabelCount (E); ++J) {
/* Get the label */
CodeLabel* L = CE_GetLabel (E, J);
- for (K = 0; K < CL_GetRefCount (L); ++K) {
+
+ /* Loop over all insn that reference this label. Since we may
+ * eventually remove a reference in the loop, we must loop
+ * from end down to start.
+ */
+ for (K = CL_GetRefCount (L) - 1; K >= 0; --K) {
/* Get the entry that jumps here */
CodeEntry* Jump = CL_GetRef (L, K);
/* Get the register info from this insn */
short Val = RegVal (E->Chg, &Jump->RI->Out2);
- /* Check if the outgoing value is the one thatr's loaded */
+ /* Check if the outgoing value is the one thats's loaded */
if (Val == (unsigned char) E->Num) {
- /* Ok, skip the insn. First, generate a label */
+ /* Ok, skip the insn. First, generate a label for the
+ * next insn after E.
+ */
if (LN == 0) {
LN = CS_GenLabel (S, N);
}
case FoundPop:
/* We're at the instruction after the PLA.
* Check for the following conditions:
- * - If this instruction is a store of A, and A is not used
- * later, we may replace the PHA by the store and remove
- * pla if several other conditions are met.
+ * - If this instruction is a store of A, does not have a
+ * label, and A is not used later, we may replace the PHA
+ * by the store and remove pla if several other conditions
+ * are met.
* - If this instruction is not a conditional branch, and A
* is either unused later, or not changed by the code
* between push and pop, we may remove PHA and PLA.
*/
if (E->OPC == OP65_STA &&
+ !CE_HasLabel (E) &&
!RegAUsed (S, I+1) &&
!MemAccess (S, Push+1, Pop-1, E)) {