]> git.sur5r.net Git - cc65/blobdiff - src/cc65/coptind.c
Since we have now builtin search paths, we need to be able to forget them,
[cc65] / src / cc65 / coptind.c
index 076e8fb73958e2b17d1de895a450d4c660d70c60..2dd0aaa546b63eeec117eae47c3938a280cdeacd 100644 (file)
 
 
 
-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.
- */
+static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const CodeEntry* N)
+/* Checks a range of code entries if there are any memory accesses to N->Arg */
 {
+    /* Get the length of the argument */
+    unsigned NLen = strlen (N->Arg);
+
+    /* What to check for? */
+    enum {
+        None    = 0x00,
+        Base    = 0x01,         /* Check for location without "+1" */
+        Word    = 0x02,         /* Check for location with "+1" added */
+    } What = None;
+
+
+    /* If the argument of N is a zero page location that ends with "+1", we
+     * must also check for word accesses to the location without +1.
+     */
+    if (N->AM == AM65_ZP && NLen > 2 && strcmp (N->Arg + NLen - 2, "+1") == 0) {
+        What |= Base;
+    }
+
+    /* If the argument is zero page indirect, we must also check for accesses
+     * to "arg+1"
+     */
+    if (N->AM == AM65_ZP_INDY || N->AM == AM65_ZPX_IND || N->AM == AM65_ZP_IND) {
+        What |= Word;
+    }
+
     /* 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.
+        /* Check if there is an argument and if this argument equals Arg in
+         * some variants.
          */
-        if (E->Arg && strcmp (E->Arg, Arg) == 0) {
-            /* Found an access */
-            return 1;
+        if (E->Arg[0] != '\0') {
+
+            unsigned ELen;
+
+            if (strcmp (E->Arg, N->Arg) == 0) {
+                /* Found an access */
+                return 1;
+            }
+
+            ELen = strlen (E->Arg);
+            if ((What & Base) != 0) {
+                if (ELen == NLen - 2 && strncmp (E->Arg, N->Arg, NLen-2) == 0) {
+                    /* Found an access */
+                    return 1;
+                }
+            }
+
+            if ((What & Word) != 0) {
+                if (ELen == NLen + 2 && strncmp (E->Arg, N->Arg, NLen) == 0 &&
+                    E->Arg[NLen] == '+' && E->Arg[NLen+1] == '1') {
+                    /* Found an access */
+                    return 1;
+                }
+            }
         }
 
         /* Next entry */
@@ -564,12 +604,13 @@ unsigned OptJumpTarget1 (CodeSeg* S)
        /* Get next entry */
                E2 = CS_GetNextEntry (S, I);
 
-       /* Check if we have a jump or branch, and a matching label, which
-        * is not attached to the jump itself
+       /* Check if we have a jump or branch without a label attached, and
+         * a jump target, which is not attached to the jump itself
         */
-               if (E2 != 0                     &&
+               if (E2 != 0                     &&
            (E2->Info & OF_UBRA) != 0   &&
-           E2->JumpTo                  &&
+            !CE_HasLabel (E2)           &&
+           E2->JumpTo                  &&
            E2->JumpTo->Owner != E2) {
 
            /* Get the entry preceeding the branch target */
@@ -579,6 +620,13 @@ unsigned OptJumpTarget1 (CodeSeg* S)
                goto NextEntry;
            }
 
+            /* The entry preceeding the branch target may not be the branch
+             * insn.
+             */
+            if (T1 == E2) {
+                goto NextEntry;
+            }
+
            /* Get the entry preceeding the jump */
            E1 = CS_GetEntry (S, I);
 
@@ -1472,7 +1520,7 @@ unsigned OptTransfers3 (CodeSeg* S)
                      StoreEntry->AM == AM65_ZP)                                 &&
                     (StoreEntry->AM != AM65_ZP ||
                      (StoreEntry->Chg & UsedRegs) == 0)                         &&
-                    !MemAccess (S, Xfer+1, Store-1, StoreEntry->Arg)) {
+                    !MemAccess (S, Xfer+1, Store-1, StoreEntry)) {
 
                     /* Generate the replacement store insn */
                     CodeEntry* X = 0;
@@ -1637,7 +1685,7 @@ unsigned OptTransfers4 (CodeSeg* S)
                     (LoadEntry->AM == AM65_ABS          ||
                      LoadEntry->AM == AM65_ZP           ||
                      LoadEntry->AM == AM65_IMM)                                 &&
-                    !MemAccess (S, Load+1, Xfer-1, LoadEntry->Arg)) {
+                    !MemAccess (S, Load+1, Xfer-1, LoadEntry)) {
 
                     /* Generate the replacement load insn */
                     CodeEntry* X = 0;
@@ -1717,6 +1765,7 @@ unsigned OptPushPop (CodeSeg* S)
     unsigned Changes = 0;
     unsigned Push    = 0;       /* Index of push insn */
     unsigned Pop     = 0;       /* Index of pop insn */
+    unsigned ChgA    = 0;       /* Flag for A changed */
     enum {
         Searching,
         FoundPush,
@@ -1746,6 +1795,7 @@ unsigned OptPushPop (CodeSeg* S)
                 if (E->OPC == OP65_PHA) {
                     /* Found start of sequence */
                     Push  = I;
+                    ChgA  = 0;
                     State = FoundPush;
                 }
                 break;
@@ -1754,6 +1804,7 @@ unsigned OptPushPop (CodeSeg* S)
                 if (E->OPC == OP65_PHA) {
                     /* Inner push/pop, restart */
                     Push = I;
+                    ChgA = 0;
                 } else if (E->OPC == OP65_PLA) {
                     /* Found a matching pop */
                     Pop = I;
@@ -1766,6 +1817,8 @@ unsigned OptPushPop (CodeSeg* S)
                         /* Go into searching mode again */
                         State = Searching;
                     }
+                } else if (E->Chg & REG_A) {
+                    ChgA = 1;
                 }
                 break;
 
@@ -1776,11 +1829,12 @@ unsigned OptPushPop (CodeSeg* S)
                  *     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.
+                 *     is either unused later, or not changed by the code
+                 *     between push and pop, we may remove PHA and PLA.
                  */
                 if (E->OPC == OP65_STA                  &&
                     !RegAUsed (S, I+1)                  &&
-                    !MemAccess (S, Push+1, Pop-1, E->Arg)) {
+                    !MemAccess (S, Push+1, Pop-1, E)) {
 
                     /* Insert a STA after the PHA */
                     X = NewCodeEntry (E->OPC, E->AM, E->Arg, E->JumpTo, E->LI);
@@ -1799,7 +1853,7 @@ unsigned OptPushPop (CodeSeg* S)
                     ++Changes;
 
                 } else if ((E->Info & OF_CBRA) == 0     &&
-                           !RegAUsed (S, I)) {
+                           (!RegAUsed (S, I) || !ChgA)) {
 
                     /* We can remove the PHA and PLA instructions */
                     CS_DelEntry (S, Pop);