X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcoptind.c;h=b14b27ed941b4566d1497e60d7c4acf4ea68cd15;hb=f7dfcbcc3daf8426770842b5e6ed3634e0d50c82;hp=22aae197b6b361829eb9b063e07cd629c132c384;hpb=99de22ffe2657ed49896df13d13e472a3c7f762c;p=cc65 diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 22aae197b..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); @@ -504,7 +530,7 @@ unsigned OptJumpTarget (CodeSeg* S) * is not attached to the jump itself */ if (E2 != 0 && - (E2->Info & OF_UBRA) != 0 && + (E2->Info & OF_UBRA) != 0 && E2->JumpTo && E2->JumpTo->Owner != E2) { @@ -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,9 +899,9 @@ 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->RegX == RegVal (E->Chg, In)) { /* Value identical */ + In->RegY == RegVal (E->Chg, In)) { /* Value identical */ Delete = 1; @@ -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)) { @@ -1057,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 @@ -1074,16 +1100,16 @@ unsigned OptTransfers (CodeSeg* S) 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; } } @@ -1099,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 */ /*****************************************************************************/