diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 67fa1f7e5..e72f6c28d 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -51,6 +51,39 @@ +static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const char* Arg) +/* Checks a range of code entries if there are any memory accesses to Arg. + * Note: This function is not 100% safe, because there is more than one way + * to express a memory location ("foo" and "foo+0" comes to mind) and there + * may be other accesses through pointers. For the code generated by cc65 and + * for the purpose of the caller (OptPushPop) it is assumed to be safe enough + * however. + */ +{ + /* Walk over all code entries */ + while (From <= To) { + + /* Get the next entry */ + CodeEntry* E = CS_GetEntry (S, From); + + /* For simplicity, we just check if there is an argument and if this + * argument equals Arg. + */ + if (E->Arg && strcmp (E->Arg, Arg) == 0) { + /* Found an access */ + return 1; + } + + /* Next entry */ + ++From; + } + + /* Nothing found */ + return 0; +} + + + 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. @@ -1225,6 +1258,8 @@ unsigned OptPushPop (CodeSeg* S) unsigned I = 0; while (I < CS_GetEntryCount (S)) { + CodeEntry* X; + /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); @@ -1245,19 +1280,47 @@ unsigned OptPushPop (CodeSeg* S) } else if (E->OPC == OP65_PLA) { /* Found a matching pop */ Pop = I; - State = FoundPop; + /* Check that the block between Push and Pop is a basic + * block (one entry, one exit). Otherwise ignore it. + */ + if (CS_IsBasicBlock (S, Push, Pop)) { + State = FoundPop; + } else { + /* Go into searching mode again */ + State = Searching; + } } 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. + /* 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 not a conditional branch, and A + * is unused later, we may remove PHA and PLA. */ - if ((E->Info & OF_CBRA) == 0 && - !RegAUsed (S, I) && - CS_IsBasicBlock (S, Push, Pop)) { + if (E->OPC == OP65_STA && + !RegAUsed (S, I+1) && + !MemAccess (S, Push+1, Pop-1, E->Arg)) { + + /* Insert a STA before the PHA */ + X = NewCodeEntry (E->OPC, E->AM, E->Arg, E->JumpTo, E->LI); + CS_InsertEntry (S, X, Push); + + /* Remove the PHA instead */ + CS_DelEntry (S, Push+1); + + /* Remove the PLA/STA sequence */ + CS_DelEntries (S, Pop, 2); + + /* Remember we had changes */ + ++Changes; + + } else if ((E->Info & OF_CBRA) == 0 && + !RegAUsed (S, I)) { + /* We can remove the PHA and PLA instructions */ CS_DelEntry (S, Pop); CS_DelEntry (S, Push); @@ -1265,6 +1328,7 @@ unsigned OptPushPop (CodeSeg* S) I -= 2; /* Remember we had changes */ ++Changes; + } /* Go into search mode again */ State = Searching;