+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.
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
+ CodeEntry* X;
+
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
} 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);
I -= 2;
/* Remember we had changes */
++Changes;
+
}
/* Go into search mode again */
State = Searching;