X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptind.c;h=b14b27ed941b4566d1497e60d7c4acf4ea68cd15;hb=f7dfcbcc3daf8426770842b5e6ed3634e0d50c82;hp=2e5aed66e53f496125aca2d91231bb19bd0b02a1;hpb=21111ba235f184c962985fd79c4782eaa5990c83;p=cc65 diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 2e5aed66e..b14b27ed9 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2001 Ullrich von Bassewitz */ +/* (C) 2001-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@cc65.org */ @@ -33,7 +33,8 @@ -#include +/* common */ +#include "cpu.h" /* cc65 */ #include "codeent.h" @@ -45,12 +46,80 @@ /*****************************************************************************/ -/* Replace jumps to RTS by RTS */ +/* Helper functions */ /*****************************************************************************/ -unsigned OptRTSJumps (CodeSeg* S) +static int GetBranchDist (CodeSeg* S, unsigned From, CodeEntry* To) +/* Get the branch distance between the two entries and return it. The distance + * will be negative for backward jumps and positive for forward jumps. + */ +{ + /* Get the index of the branch target */ + unsigned TI = CS_GetEntryIndex (S, To); + + /* Determine the branch distance */ + int Distance = 0; + if (TI >= From) { + /* Forward branch, do not count the current insn */ + unsigned J = From+1; + while (J < TI) { + CodeEntry* N = CS_GetEntry (S, J++); + Distance += N->Size; + } + } else { + /* Backward branch */ + unsigned J = TI; + while (J < From) { + CodeEntry* N = CS_GetEntry (S, J++); + Distance -= N->Size; + } + } + + /* Return the calculated distance */ + return Distance; +} + + + +static int IsShortDist (int Distance) +/* Return true if the given distance is a short branch distance */ +{ + return (Distance >= -125 && Distance <= 125); +} + + + +static short RegVal (unsigned short Use, const RegContents* RC) +/* Return the contents of the given register */ +{ + if ((Use & REG_A) != 0) { + return RC->RegA; + } else if ((Use & REG_X) != 0) { + return RC->RegX; + } else if ((Use & REG_Y) != 0) { + return RC->RegY; + } else if ((Use & REG_TMP1) != 0) { + return RC->Tmp1; + } else if ((Use & REG_SREG_LO) != 0) { + return RC->SRegLo; + } else if ((Use & REG_SREG_HI) != 0) { + return RC->SRegHi; + } else { + return UNKNOWN_REGVAL; + } +} + + + +/*****************************************************************************/ +/* Replace jumps to RTS by RTS */ +/*****************************************************************************/ + + + +unsigned OptRTSJumps1 (CodeSeg* S) /* Replace jumps to RTS by RTS */ { unsigned Changes = 0; @@ -90,6 +159,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 */ /*****************************************************************************/ @@ -100,33 +227,24 @@ unsigned OptDeadJumps (CodeSeg* S) /* Remove dead jumps (jumps to the next instruction) */ { unsigned Changes = 0; - CodeEntry* E; - unsigned I; - - /* Get the number of entries, bail out if we have less than two entries */ - unsigned Count = CS_GetEntryCount (S); - if (Count < 2) { - return 0; - } /* Walk over all entries minus the last one */ - I = 0; - while (I < Count-1) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { /* Get the next entry */ - E = CS_GetEntry (S, I); + CodeEntry* E = CS_GetEntry (S, I); /* Check if it's a branch, if it has a local target, and if the target * is the next instruction. */ - if (E->AM == AM65_BRA && E->JumpTo && E->JumpTo->Owner == CS_GetEntry (S, I+1)) { + if (E->AM == AM65_BRA && + E->JumpTo && + E->JumpTo->Owner == CS_GetNextEntry (S, I)) { /* Delete the dead jump */ CS_DelEntry (S, I); - /* Keep the number of entries updated */ - --Count; - /* Remember, we had changes */ ++Changes; @@ -145,7 +263,7 @@ unsigned OptDeadJumps (CodeSeg* S) /*****************************************************************************/ -/* Remove dead code */ +/* Remove dead code */ /*****************************************************************************/ @@ -156,36 +274,32 @@ unsigned OptDeadCode (CodeSeg* S) */ { unsigned Changes = 0; - unsigned I; - - /* Get the number of entries, bail out if we have less than two entries */ - unsigned Count = CS_GetEntryCount (S); - if (Count < 2) { - return 0; - } /* Walk over all entries */ - I = 0; - while (I < Count) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { CodeEntry* N; + CodeLabel* LN; /* Get this entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if it's an unconditional branch, and if the next entry has - * no labels attached + * no labels attached, or if the label is just used so that the insn + * can jump to itself. */ - if ((E->Info & OF_DEAD) != 0 && - (N = CS_GetNextEntry (S, I)) != 0 && - !CE_HasLabel (N)) { + if ((E->Info & OF_DEAD) != 0 && /* Dead code follows */ + (N = CS_GetNextEntry (S, I)) != 0 && /* Has next entry */ + (!CE_HasLabel (N) || /* Don't has a label */ + ((N->Info & OF_UBRA) != 0 && /* Uncond branch */ + (LN = N->JumpTo) != 0 && /* Jumps to known label */ + LN->Owner == N && /* Attached to insn */ + CL_GetRefCount (LN) == 1))) { /* Only reference */ /* Delete the next entry */ CS_DelEntry (S, I+1); - /* Keep the number of entries updated */ - --Count; - /* Remember, we had changes */ ++Changes; @@ -246,10 +360,28 @@ unsigned OptJumpCascades (CodeSeg* S) ((E->Info & OF_CBRA) != 0 && GetBranchCond (E->OPC) == GetBranchCond (N->OPC))) { - /* This is a jump cascade and we may jump to the final target. - * Insert a new instruction, then remove the old one + /* This is a jump cascade and we may jump to the final target, + * provided that the other insn does not jump to itself. If + * this is the case, we can also jump to ourselves, otherwise + * insert a jump to the new instruction and remove the old one. */ - CodeEntry* X = NewCodeEntry (E->OPC, E->AM, N->Arg, N->JumpTo, E->LI); + CodeEntry* X; + CodeLabel* LN = N->JumpTo; + + if (LN != 0 && LN->Owner == N) { + + /* We found a jump to a jump to itself. Replace our jump + * by a jump to itself. + */ + CodeLabel* LE = CS_GenLabel (S, E); + X = NewCodeEntry (E->OPC, E->AM, LE->Name, LE, E->LI); + + } else { + + /* Jump to the final jump target */ + X = NewCodeEntry (E->OPC, E->AM, N->Arg, N->JumpTo, E->LI); + + } /* Insert it behind E */ CS_InsertEntry (S, X, I+1); @@ -333,17 +465,10 @@ unsigned OptRTS (CodeSeg* S) */ { unsigned Changes = 0; - unsigned I; - - /* Get the number of entries, bail out if we have less than 2 entries */ - unsigned Count = CS_GetEntryCount (S); - if (Count < 2) { - return 0; - } /* Walk over all entries minus the last one */ - I = 0; - while (I < Count-1) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { CodeEntry* N; @@ -392,37 +517,29 @@ unsigned OptJumpTarget (CodeSeg* S) CodeEntry* E1; /* Entry 1 */ CodeEntry* E2; /* Entry 2 */ CodeEntry* T1; /* Jump target entry 1 */ - CodeEntry* T2; /* Jump target entry 2 */ CodeLabel* TL1; /* Target label 1 */ - unsigned TI; /* Target index */ - unsigned I; - - /* Get the number of entries, bail out if we have not enough */ - unsigned Count = CS_GetEntryCount (S); - if (Count < 3) { - return 0; - } /* Walk over the entries */ - I = 0; - while (I < Count-1) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { /* Get next entry */ - E2 = CS_GetEntry (S, I+1); - - /* Check if we have a jump or branch, and a matching label */ - if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) { + E2 = CS_GetNextEntry (S, I); - /* Get the target instruction for the label */ - T2 = E2->JumpTo->Owner; - - /* Get the entry preceeding this one (if possible) */ - TI = CS_GetEntryIndex (S, T2); - if (TI == 0) { - /* There is no entry before this one */ + /* Check if we have a jump or branch, and a matching label, which + * is not attached to the jump itself + */ + if (E2 != 0 && + (E2->Info & OF_UBRA) != 0 && + E2->JumpTo && + E2->JumpTo->Owner != E2) { + + /* Get the entry preceeding the branch target */ + T1 = CS_GetPrevEntry (S, CS_GetEntryIndex (S, E2->JumpTo->Owner)); + if (T1 == 0) { + /* There is no such entry */ goto NextEntry; } - T1 = CS_GetEntry (S, TI-1); /* Get the entry preceeding the jump */ E1 = CS_GetEntry (S, I); @@ -451,7 +568,6 @@ unsigned OptJumpTarget (CodeSeg* S) /* Remove the entry preceeding the jump */ CS_DelEntry (S, I); - --Count; /* Remember, we had changes */ ++Changes; @@ -490,17 +606,10 @@ unsigned OptCondBranches (CodeSeg* S) */ { unsigned Changes = 0; - unsigned I; - - /* Get the number of entries, bail out if we have not enough */ - unsigned Count = CS_GetEntryCount (S); - if (Count < 2) { - return 0; - } /* Walk over the entries */ - I = 0; - while (I < Count-1) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { CodeEntry* N; CodeLabel* L; @@ -527,7 +636,6 @@ unsigned OptCondBranches (CodeSeg* S) /* Remove the conditional branch */ CS_DelEntry (S, I+1); - --Count; /* Remember, we had changes */ ++Changes; @@ -560,7 +668,6 @@ unsigned OptCondBranches (CodeSeg* S) /* Remove the conditional branch */ CS_DelEntry (S, I); - --Count; /* Remember, we had changes */ ++Changes; @@ -579,7 +686,7 @@ unsigned OptCondBranches (CodeSeg* S) /*****************************************************************************/ -/* Remove unused loads and stores */ +/* Remove unused loads and stores */ /*****************************************************************************/ @@ -599,24 +706,24 @@ unsigned OptUnusedLoads (CodeSeg* S) CodeEntry* E = CS_GetEntry (S, I); /* Check if it's a register load or transfer insn */ - if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 && - (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_FBRA) == 0) { + if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + !CE_UseLoadFlags (N)) { /* Check which sort of load or transfer it is */ unsigned R; switch (E->OPC) { - case OP65_DEA: - case OP65_INA: - case OP65_LDA: + case OP65_DEA: + case OP65_INA: + case OP65_LDA: case OP65_TXA: case OP65_TYA: R = REG_A; break; - case OP65_DEX: - case OP65_INX: - case OP65_LDX: + case OP65_DEX: + case OP65_INX: + case OP65_LDX: case OP65_TAX: R = REG_X; break; - case OP65_DEY: - case OP65_INY: + case OP65_DEY: + case OP65_INY: case OP65_LDY: case OP65_TAY: R = REG_Y; break; default: goto NextEntry; /* OOPS */ @@ -672,10 +779,10 @@ unsigned OptUnusedStores (CodeSeg* S) if ((GetRegInfo (S, I+1, R) & R) == 0) { /* Register value is not used, remove the load */ - CS_DelEntry (S, I); + CS_DelEntry (S, I); - /* Remember, we had changes */ - ++Changes; + /* Remember, we had changes */ + ++Changes; } } @@ -719,31 +826,31 @@ unsigned OptDupLoads (CodeSeg* S) switch (E->OPC) { case OP65_LDA: - if (In->RegA >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegA) && /* Value of A is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegA == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ - (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + !CE_UseLoadFlags (N)) { /* Which does not use the flags */ Delete = 1; } break; case OP65_LDX: - if (In->RegX >= 0 && /* Value of X is known */ + if (RegValIsKnown (In->RegX) && /* Value of X is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegX == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ - (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + !CE_UseLoadFlags (N)) { /* Which does not use the flags */ Delete = 1; } break; case OP65_LDY: - if (In->RegY >= 0 && /* Value of Y is known */ + if (RegValIsKnown (In->RegY) && /* Value of Y is known */ CE_KnownImm (E) && /* Value to be loaded is known */ In->RegY == (long) E->Num && /* Both are equal */ (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */ - (N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */ + !CE_UseLoadFlags (N)) { /* Which does not use the flags */ Delete = 1; } break; @@ -753,12 +860,10 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegA >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegA) && /* Value of A is known */ E->AM == AM65_ZP && /* Store into zp */ - (((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */ - In->RegA == In->SRegLo) || /* Value identical */ - ((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */ - In->RegA == In->SRegHi))) { /* Value identical */ + In->RegA == RegVal (E->Chg, In)) { /* Value identical */ + Delete = 1; } break; @@ -768,12 +873,10 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegX >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegX) && /* Value of A is known */ E->AM == AM65_ZP && /* Store into zp */ - (((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */ - In->RegX == In->SRegLo) || /* Value identical */ - ((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */ - In->RegX == In->SRegHi))) { /* Value identical */ + In->RegX == RegVal (E->Chg, In)) { /* Value identical */ + Delete = 1; /* If the value in the X register is known and the same as @@ -782,7 +885,7 @@ unsigned OptDupLoads (CodeSeg* S) * later. STX does support the zeropage,y addressing mode, * so be sure to check for that. */ - } else if (In->RegX >= 0 && + } else if (RegValIsKnown (In->RegX) && In->RegX == In->RegA && E->AM != AM65_ABSY && E->AM != AM65_ZPY) { @@ -796,66 +899,77 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegX >= 0 && /* Value of A is known */ + if (RegValIsKnown (In->RegY) && /* Value of Y is known */ E->AM == AM65_ZP && /* Store into zp */ - (((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */ - In->RegX == In->SRegLo) || /* Value identical */ - ((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */ - In->RegX == In->SRegHi))) { /* Value identical */ + In->RegY == RegVal (E->Chg, In)) { /* Value identical */ + Delete = 1; + /* If the value in the Y register is known and the same as * that in the A register, replace the store by a STA. The * optimizer will then remove the load instruction for Y * later. If replacement by A is not possible try a - * replacement by X, but check for invalid addressing modes + * replacement by X, but check for invalid addressing modes * in this case. */ - } else if (In->RegY >= 0) { + } else if (RegValIsKnown (In->RegY)) { if (In->RegY == In->RegA) { - CE_ReplaceOPC (E, OP65_STA); + CE_ReplaceOPC (E, OP65_STA); } else if (In->RegY == In->RegX && - E->AM != AM65_ABSX && - E->AM != AM65_ZPX) { + E->AM != AM65_ABSX && + E->AM != AM65_ZPX) { CE_ReplaceOPC (E, OP65_STX); } } break; + case OP65_STZ: + /* If we store into a known zero page location, and this + * location does already contain the value to be stored, + * remove the store. + */ + if (CPU >= CPU_65C02 && E->AM == AM65_ZP) { + if (RegVal (E->Chg, In) == 0) { + Delete = 1; + } + } + break; + case OP65_TAX: - if (In->RegA >= 0 && + if (RegValIsKnown (In->RegA) && In->RegA == In->RegX && (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_FBRA) == 0) { + !CE_UseLoadFlags (N)) { /* Value is identical and not followed by a branch */ Delete = 1; } break; case OP65_TAY: - if (In->RegA >= 0 && - In->RegA == In->RegY && + if (RegValIsKnown (In->RegA) && + In->RegA == In->RegY && (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_FBRA) == 0) { + !CE_UseLoadFlags (N)) { /* Value is identical and not followed by a branch */ Delete = 1; } break; case OP65_TXA: - if (In->RegX >= 0 && - In->RegX == In->RegA && + if (RegValIsKnown (In->RegX) && + In->RegX == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_FBRA) == 0) { + !CE_UseLoadFlags (N)) { /* Value is identical and not followed by a branch */ Delete = 1; } break; case OP65_TYA: - if (In->RegY >= 0 && - In->RegY == In->RegA && + if (RegValIsKnown (In->RegY) && + In->RegY == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_FBRA) == 0) { + !CE_UseLoadFlags (N)) { /* Value is identical and not followed by a branch */ Delete = 1; } @@ -911,15 +1025,18 @@ unsigned OptStoreLoad (CodeSeg* S) /* Check if it is a store instruction followed by a load from the * same address which is itself not followed by a conditional branch. */ - if ((E->Info & OF_STORE) != 0 && - (N = CS_GetNextEntry (S, I)) != 0 && - !CE_HasLabel (N) && - (N->Info & OF_LOAD) != 0 && - strcmp (E->Arg, N->Arg) == 0 && - (X = CS_GetNextEntry (S, I+1)) != 0 && - (X->Info & OF_FBRA) == 0) { - - /* Register value is not used, remove the load */ + if ((E->Info & OF_STORE) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + !CE_HasLabel (N) && + E->AM == N->AM && + ((E->OPC == OP65_STA && N->OPC == OP65_LDA) || + (E->OPC == OP65_STX && N->OPC == OP65_LDX) || + (E->OPC == OP65_STY && N->OPC == OP65_LDY)) && + strcmp (E->Arg, N->Arg) == 0 && + (X = CS_GetNextEntry (S, I+1)) != 0 && + !CE_UseLoadFlags (X)) { + + /* Register has already the correct value, remove the load */ CS_DelEntry (S, I+1); /* Remember, we had changes */ @@ -966,7 +1083,7 @@ unsigned OptTransfers (CodeSeg* S) if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) || (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) || (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) || - (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+1))) { + (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+2))) { /* If the next insn is a conditional branch, check if the insn * preceeding the first xfr will set the flags right, otherwise we @@ -975,24 +1092,24 @@ unsigned OptTransfers (CodeSeg* S) if ((X = CS_GetNextEntry (S, I+1)) == 0) { goto NextEntry; } - if ((X->Info & OF_FBRA) != 0) { - if (I == 0) { + if (CE_UseLoadFlags (X)) { + if (I == 0) { /* No preceeding entry */ goto NextEntry; } P = CS_GetEntry (S, I-1); if ((P->Info & OF_SETF) == 0) { /* Does not set the flags */ - goto NextEntry; - } - } + goto NextEntry; + } + } - /* Remove both transfers */ - CS_DelEntry (S, I+1); - CS_DelEntry (S, I); + /* Remove both transfers */ + CS_DelEntry (S, I+1); + CS_DelEntry (S, I); - /* Remember, we had changes */ - ++Changes; + /* Remember, we had changes */ + ++Changes; } } @@ -1008,6 +1125,87 @@ NextEntry: +unsigned OptPushPop (CodeSeg* S) +/* Remove a PHA/PLA sequence were A is not used later */ +{ + unsigned Changes = 0; + unsigned Push = 0; /* Index of push insn */ + unsigned Pop = 0; /* Index of pop insn */ + enum { + Searching, + FoundPush, + FoundPop + } State = Searching; + + /* Walk over the entries. Look for a push instruction that is followed by + * a pop later, where the pop is not followed by an conditional branch, + * and where the value of the A register is not used later on. + * Look out for the following problems: + * + * - There may be another PHA/PLA inside the sequence: Restart it. + * - If the PLA has a label, all jumps to this label must be inside + * the sequence, otherwise we cannot remove the PHA/PLA. + */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + switch (State) { + + case Searching: + if (E->OPC == OP65_PHA) { + /* Found start of sequence */ + Push = I; + State = FoundPush; + } + break; + + case FoundPush: + if (E->OPC == OP65_PHA) { + /* Inner push/pop, restart */ + Push = I; + } else if (E->OPC == OP65_PLA) { + /* Found a matching pop */ + Pop = I; + State = FoundPop; + } + break; + + case FoundPop: + /* Next insn, just check if it is no conditional branch and + * that A is not used later. Check also that the range we have + * found now is a basic block, which means that the PHA is the + * only entrance and the PLA the only exit. + */ + if ((E->Info & OF_CBRA) == 0 && + !RegAUsed (S, I) && + CS_IsBasicBlock (S, Push, Pop)) { + /* We can remove the PHA and PLA instructions */ + CS_DelEntry (S, Pop); + CS_DelEntry (S, Push); + /* Correct I so we continue with the next insn */ + I -= 2; + /* Remember we had changes */ + ++Changes; + } + /* Go into search mode again */ + State = Searching; + break; + + } + + /* Next entry */ + ++I; + } + + /* Return the number of changes made */ + return Changes; +} + + + /*****************************************************************************/ /* Optimize branch types */ /*****************************************************************************/ @@ -1018,51 +1216,29 @@ unsigned OptBranchDist (CodeSeg* S) /* Change branches for the distance needed. */ { unsigned Changes = 0; - unsigned I; - - /* Get the number of entries, bail out if we have not enough */ - unsigned Count = CS_GetEntryCount (S); /* Walk over the entries */ - I = 0; - while (I < Count) { + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if it's a conditional branch to a local label. */ - if ((E->Info & OF_CBRA) != 0) { + if (E->Info & OF_CBRA) { /* Is this a branch to a local symbol? */ if (E->JumpTo != 0) { - /* Get the index of the branch target */ - unsigned TI = CS_GetEntryIndex (S, E->JumpTo->Owner); - - /* Determine the branch distance */ - int Distance = 0; - if (TI >= I) { - /* Forward branch */ - unsigned J = I; - while (J < TI) { - CodeEntry* N = CS_GetEntry (S, J++); - Distance += N->Size; - } - } else { - /* Backward branch */ - unsigned J = TI; - while (J < I) { - CodeEntry* N = CS_GetEntry (S, J++); - Distance += N->Size; - } - } + /* Check if the branch distance is short */ + int IsShort = IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner)); /* Make the branch short/long according to distance */ - if ((E->Info & OF_LBRA) == 0 && Distance > 120) { + if ((E->Info & OF_LBRA) == 0 && !IsShort) { /* Short branch but long distance */ CE_ReplaceOPC (E, MakeLongBranch (E->OPC)); ++Changes; - } else if ((E->Info & OF_LBRA) != 0 && Distance < 120) { + } else if ((E->Info & OF_LBRA) != 0 && IsShort) { /* Long branch but short distance */ CE_ReplaceOPC (E, MakeShortBranch (E->OPC)); ++Changes; @@ -1075,6 +1251,15 @@ unsigned OptBranchDist (CodeSeg* S) ++Changes; } + + } else if (CPU == CPU_65C02 && + (E->Info & OF_UBRA) != 0 && + E->JumpTo != 0 && + IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner))) { + + /* The jump is short and may be replaced by a BRA on the 65C02 CPU */ + CE_ReplaceOPC (E, OP65_BRA); + ++Changes; } /* Next entry */