1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-27 00:29:31 +00:00

Improved implementation of OptPushPop

git-svn-id: svn://svn.cc65.org/cc65/trunk@1449 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2002-10-06 19:01:46 +00:00
parent 1647c6783f
commit 9a62c92489

View File

@ -1103,59 +1103,75 @@ 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 */
/* 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 */