X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptind.c;h=b14b27ed941b4566d1497e60d7c4acf4ea68cd15;hb=f7dfcbcc3daf8426770842b5e6ed3634e0d50c82;hp=aef3cd162d1e15daf8980e431a1215282c39772e;hpb=60471653255c6716f35ba0746234199432e43443;p=cc65 diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index aef3cd162..b14b27ed9 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -33,11 +33,13 @@ +/* common */ +#include "cpu.h" + /* cc65 */ #include "codeent.h" #include "codeinfo.h" #include "codeopt.h" -#include "cpu.h" #include "error.h" #include "coptind.h" @@ -105,7 +107,7 @@ static short RegVal (unsigned short Use, const RegContents* RC) } else if ((Use & REG_SREG_HI) != 0) { return RC->SRegHi; } else { - return REG_NONE; + return UNKNOWN_REGVAL; } } @@ -261,7 +263,7 @@ unsigned OptDeadJumps (CodeSeg* S) /*****************************************************************************/ -/* Remove dead code */ +/* Remove dead code */ /*****************************************************************************/ @@ -278,16 +280,22 @@ unsigned OptDeadCode (CodeSeg* S) 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); @@ -352,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); @@ -800,7 +826,7 @@ 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 */ @@ -810,7 +836,7 @@ unsigned OptDupLoads (CodeSeg* S) 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 */ @@ -820,7 +846,7 @@ unsigned OptDupLoads (CodeSeg* S) 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 */ @@ -834,7 +860,7 @@ 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 */ In->RegA == RegVal (E->Chg, In)) { /* Value identical */ @@ -847,7 +873,7 @@ 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 */ In->RegX == RegVal (E->Chg, In)) { /* Value identical */ @@ -859,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) { @@ -873,7 +899,7 @@ unsigned OptDupLoads (CodeSeg* S) * location does already contain the value to be stored, * remove the store. */ - if (In->RegY >= 0 && /* Value of Y is known */ + if (RegValIsKnown (In->RegY) && /* Value of Y is known */ E->AM == AM65_ZP && /* Store into zp */ In->RegY == RegVal (E->Chg, In)) { /* Value identical */ @@ -886,7 +912,7 @@ unsigned OptDupLoads (CodeSeg* S) * 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); } else if (In->RegY == In->RegX && @@ -910,7 +936,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TAX: - if (In->RegA >= 0 && + if (RegValIsKnown (In->RegA) && In->RegA == In->RegX && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -920,7 +946,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TAY: - if (In->RegA >= 0 && + if (RegValIsKnown (In->RegA) && In->RegA == In->RegY && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -930,7 +956,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TXA: - if (In->RegX >= 0 && + if (RegValIsKnown (In->RegX) && In->RegX == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -940,7 +966,7 @@ unsigned OptDupLoads (CodeSeg* S) break; case OP65_TYA: - if (In->RegY >= 0 && + if (RegValIsKnown (In->RegY) && In->RegY == In->RegA && (N = CS_GetNextEntry (S, I)) != 0 && !CE_UseLoadFlags (N)) { @@ -1103,59 +1129,75 @@ unsigned OptPushPop (CodeSeg* S) /* Remove a PHA/PLA sequence were A is not used later */ { unsigned Changes = 0; - - /* Walk over the entries */ + 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)) { - CodeEntry* N; - /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); - /* Check if it is a PLA instruction that does not have a label and - * where the register value is not used later and that is not followed - * by a conditional branch. - */ - if (E->OPC == OP65_PLA && - !CE_HasLabel (E) && - (N = CS_GetNextEntry (S, I)) != 0 && - (N->Info & OF_CBRA) == 0 && - !RegAUsed (S, I+1)) { - - /* Search back until we find the matching PHA instruction. If we - * find a label or another PLA somewhere in between, bail out - * since this may have side effects. - */ - unsigned J = I; - while (J-- > 0) { - - /* Get the previous entry */ - CodeEntry* P = CS_GetEntry (S, J); - - /* Check this entry */ - if (P->OPC == OP65_PHA) { - - /* Found the matching push, remove both */ - CS_DelEntry (S, I); - CS_DelEntry (S, J); - - /* Remember that we had changes and bail out */ - ++Changes; - break; - - } else if (CE_HasLabel (P) || P->OPC == OP65_PLA) { - - /* OOPS - too dangerous! */ - break; + 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 */