Applied patch #2762516
[fw/sdcc] / src / SDCCpeeph.c
index c5534bc2ed69466b94901c1971551695d90bb7bd..5a7447fff503ce66a2099c3a4ccd4d7da8c5a905 100644 (file)
 -------------------------------------------------------------------------*/
 
 #include "common.h"
+#include "dbuf_string.h"
+
+#define ISCHARDIGIT(c) isdigit((unsigned char)c)
+#define ISCHARSPACE(c) isspace((unsigned char)c)
+#define ISCHARALNUM(c) isalnum((unsigned char)c)
 
 static peepRule *rootRules = NULL;
 static peepRule *currRule = NULL;
 
 #define HTAB_SIZE 53
-typedef struct
-  {
-    char name[SDCC_NAME_MAX + 1];
-    int refCount;
-  }
-labelHashEntry;
 
-static hTab *labelHash = NULL;
+hTab *labelHash = NULL;
 
 static struct
 {
@@ -46,12 +45,12 @@ static struct
 
 static int hashSymbolName (const char *name);
 static void buildLabelRefCountHash (lineNode * head);
+static void bindVar (int key, char **s, hTab ** vtab);
 
 static bool matchLine (char *, char *, hTab **);
-bool isLabelDefinition (const char *line, const char **start, int *len);
 
-#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
-       lineNode *head, const char *cmdLine)
+#define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
+        lineNode *head, char *cmdLine)
 
 #if !OPT_DISABLE_PIC
 void peepRules2pCode(peepRule *);
@@ -62,10 +61,41 @@ void pic16_peepRules2pCode(peepRule *);
 #endif
 
 /*-----------------------------------------------------------------*/
-/* pcDistance - afinds a label back ward or forward                */
+/* getPatternVar - finds a pattern variable                        */
+/*-----------------------------------------------------------------*/
+
+static char*
+getPatternVar (hTab *vars, char **cmdLine)
+{
+  int varNumber;
+  char *digitend;
+
+  if (!cmdLine || !*cmdLine || !**cmdLine)
+    return NULL; /* no parameters given */
+
+  while (**cmdLine && ISCHARSPACE(**cmdLine))
+    (*cmdLine)++; /* skip whitespace */
+
+  if (**cmdLine != '%')
+    goto error;
+  (*cmdLine)++;
+  if (!ISCHARDIGIT (**cmdLine))
+    goto error;
+  varNumber = strtol (*cmdLine, &digitend, 10);
+  *cmdLine = digitend;
+  return hTabItemWithKey (vars, varNumber);
+
+error:
+  fprintf (stderr,
+           "*** internal error: peephole restriction malformed: %s\n", *cmdLine);
+  return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* pcDistance - finds a label backward or forward                  */
 /*-----------------------------------------------------------------*/
 
-int 
+static int
 pcDistance (lineNode * cpos, char *lbl, bool back)
 {
   lineNode *pl = cpos;
@@ -75,47 +105,40 @@ pcDistance (lineNode * cpos, char *lbl, bool back)
   SNPRINTF (buff, sizeof(buff), "%s:", lbl);
   while (pl)
     {
-
       if (pl->line &&
-         *pl->line != ';' &&
-         pl->line[strlen (pl->line) - 1] != ':' &&
-         !pl->isDebug) {
-               if (port->peep.getSize) {
-                       dist += port->peep.getSize(pl);
-               } else {
-                       dist += 3;
-               }
-       }
+          !pl->isComment &&
+          !pl->isLabel &&
+          !pl->isDebug)
+        {
+          if (port->peep.getSize)
+            {
+              dist += port->peep.getSize(pl);
+            }
+          else
+            {
+              dist += 3;
+            }
+        }
 
       if (strncmp (pl->line, buff, strlen (buff)) == 0)
-       return dist;
+        return dist;
 
       if (back)
-       pl = pl->prev;
+        pl = pl->prev;
       else
-       pl = pl->next;
+        pl = pl->next;
 
     }
   return 0;
 }
 
 /*-----------------------------------------------------------------*/
-/* flat24bitModeAndPortDS390 -                                            */
-/*-----------------------------------------------------------------*/
-FBYNAME (flat24bitModeAndPortDS390)
-{
-    return (((strcmp(port->target,"ds390") == 0) ||
-            (strcmp(port->target,"ds400") == 0)) && 
-           (options.model == MODEL_FLAT24));
-}
-
-/*-----------------------------------------------------------------*/
-/* portIsDS390 - return true if port is DS390                             */
+/* portIsDS390 - return true if port is DS390                      */
 /*-----------------------------------------------------------------*/
 FBYNAME (portIsDS390)
 {
     return ((strcmp(port->target,"ds390") == 0) ||
-           (strcmp(port->target,"ds400") == 0));
+            (strcmp(port->target,"ds400") == 0));
 }
 
 /*-----------------------------------------------------------------*/
@@ -134,51 +157,65 @@ FBYNAME (xramMovcOption)
   return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
 }
 
-
-
-
-
+/*-----------------------------------------------------------------*/
+/* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
+/*-----------------------------------------------------------------*/
+FBYNAME (useAcallAjmp)
+{
+  return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
+}
 
 /*-----------------------------------------------------------------*/
-/* labelInRange - will check to see if label %5 is within range    */
+/* labelInRange - will check to see if label is within range       */
 /*-----------------------------------------------------------------*/
 FBYNAME (labelInRange)
 {
-  /* assumes that %5 pattern variable has the label name */
-  char *lbl = hTabItemWithKey (vars, 5);
   int dist = 0;
+  char *lbl = getPatternVar (vars, &cmdLine);
 
   if (!lbl)
-    return FALSE;
+    {
+      /* If no parameters given, assume that %5 pattern variable
+         has the label name for backward compatibility */
+      lbl = hTabItemWithKey (vars, 5);
+    }
 
-  /* Don't optimize jumps in a jump table; a more generic test */
-  if (currPl->ic && currPl->ic->op == JUMPTABLE)
-    return FALSE;
-    
-  /* if the previous two instructions are "ljmp"s then don't
-     do it since it can be part of a jump table */
-  if (currPl->prev && currPl->prev->prev &&
-      strstr (currPl->prev->line, "ljmp") &&
-      strstr (currPl->prev->prev->line, "ljmp"))
+  if (!lbl)
     return FALSE;
 
-  /* calculate the label distance : the jump for reladdr can be
-     +/- 127 bytes, here Iam assuming that an average 8051
-     instruction is 2 bytes long, so if the label is more than
-     63 intructions away, the label is considered out of range
-     for a relative jump. we could get more precise this will
-     suffice for now since it catches > 90% cases */
-  dist = (pcDistance (currPl, lbl, TRUE) +
-         pcDistance (currPl, lbl, FALSE));
-
-/*    changed to 127, now that pcDistance return actual number of bytes */
-  if (!dist || dist > 127)
-    return FALSE;
+  do
+    {
+      /* Don't optimize jumps in a jump table; a more generic test */
+      if (currPl->ic && currPl->ic->op == JUMPTABLE)
+        return FALSE;
+
+      /* if the previous two instructions are "ljmp"s then don't
+         do it since it can be part of a jump table */
+      if (currPl->prev && currPl->prev->prev &&
+          strstr (currPl->prev->line, "ljmp") &&
+          strstr (currPl->prev->prev->line, "ljmp"))
+        return FALSE;
+
+      /* calculate the label distance : the jump for reladdr can be
+         +/- 127 bytes, here I am assuming that an average 8051
+         instruction is 2 bytes long, so if the label is more than
+         63 intructions away, the label is considered out of range
+         for a relative jump. we could get more precise this will
+         suffice for now since it catches > 90% cases */
+      dist = (pcDistance (currPl, lbl, TRUE) +
+              pcDistance (currPl, lbl, FALSE));
+
+      /* changed to 127, now that pcDistance return actual number of bytes */
+      if (!dist || dist > 127)
+        return FALSE;
+
+      lbl = getPatternVar (vars, &cmdLine);
+    }
+  while (lbl);
 
   return TRUE;
 }
 
-
 /*-----------------------------------------------------------------*/
 /* labelJTInRange - will check to see if label %5 and up are       */
 /* within range.                                                   */
@@ -192,13 +229,13 @@ FBYNAME (labelJTInRange)
 
   if (!getenv("SDCC_SJMP_JUMPTABLE"))
     return FALSE;
-  
+
   /* Only optimize within a jump table */
   if (currPl->ic && currPl->ic->op != JUMPTABLE)
     return FALSE;
-  
+
   count = elementsInSet( IC_JTLABELS (currPl->ic) );
-  
+
   /* check all labels (this is needed if the case statements are unsorted) */
   for (i=0; i<count; i++)
     {
@@ -206,14 +243,14 @@ FBYNAME (labelJTInRange)
       lbl = hTabItemWithKey (vars, 5+i);
       if (!lbl)
         return FALSE;
-    
+
       dist = pcDistance (currPl, lbl, FALSE);
 
       /* three terms used to calculate allowable distance */
 // printf("\nlabel %s %i dist %i cdist 0x%02x 0x%02x\n", lbl, i, dist, dist -(count-i-1)-(7+3*i), 127+(count-i-1)+(7+3*i) - dist);
       if (!dist ||
           dist > 127+           /* range of sjmp */
-                 (7+3*i)+       /* offset between this jump and currPl, 
+                 (7+3*i)+       /* offset between this jump and currPl,
                                    should use pcDistance instead? */
                  (count-i-1)    /* if peephole applies distance is shortened */
          )
@@ -222,7 +259,6 @@ FBYNAME (labelJTInRange)
   return TRUE;
 }
 
-
 /*-----------------------------------------------------------------*/
 /* labelIsReturnOnly - Check if label %5 is followed by RET        */
 /*-----------------------------------------------------------------*/
@@ -234,38 +270,131 @@ FBYNAME (labelIsReturnOnly)
   int len;
   char * retInst;
 
+  /* Don't optimize jumps in a jump table; a more generic test */
+  if (currPl->ic && currPl->ic->op == JUMPTABLE)
+    return FALSE;
+
   label = hTabItemWithKey (vars, 5);
-  if (!label) return FALSE;
+  if (!label)
+    return FALSE;
   len = strlen(label);
 
-  for(pl = currPl; pl; pl = pl->next) {
-       if (pl->line && !pl->isDebug && !pl->isComment &&
-         pl->line[strlen(pl->line)-1] == ':') {
-               if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
-               if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
-                 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
-                 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
-                 *(pl->line+5) != '$') {
-                       return FALSE; /* non-local label encountered */
-               }
-       }
-  }
-  if (!pl) return FALSE; /* did not find the label */
+  for(pl = currPl; pl; pl = pl->next)
+    {
+      if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
+        {
+          if (strncmp(pl->line, label, len) == 0)
+            break; /* Found Label */
+          if (strlen(pl->line) != 7       || !ISCHARDIGIT(*(pl->line))   ||
+              !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
+              !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
+              *(pl->line+5) != '$')
+            {
+              return FALSE; /* non-local label encountered */
+            }
+        }
+    }
+  if (!pl)
+    return FALSE; /* did not find the label */
   pl = pl->next;
   while (pl && (pl->isDebug || pl->isComment))
     pl = pl->next;
-  if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
+  if (!pl || !pl->line || pl->isDebug)
+    return FALSE; /* next line not valid */
   p = pl->line;
-  for (p = pl->line; *p && isspace(*p); p++)
-         ;
-  
+  for (p = pl->line; *p && ISCHARSPACE(*p); p++)
+    ;
+
   retInst = "ret";
   if (TARGET_IS_HC08)
     retInst = "rts";
-  if (strcmp(p, retInst) == 0) return TRUE;
+  if (strcmp(p, retInst) == 0)
+    return TRUE;
   return FALSE;
 }
 
+/*-----------------------------------------------------------------*/
+/* labelIsUncondJump - Check if label %5 is followed by an         */
+/* unconditional jump and put the destination of that jump in %6   */
+/*-----------------------------------------------------------------*/
+FBYNAME (labelIsUncondJump)
+{
+  /* assumes that %5 pattern variable has the label name */
+  const char *label;
+  char *p, *q;
+  const lineNode *pl;
+  int len;
+  char * jpInst = NULL;
+
+  /* Don't optimize jumps in a jump table; a more generic test */
+  if (currPl->ic && currPl->ic->op == JUMPTABLE)
+    return FALSE;
+
+  label = hTabItemWithKey (vars, 5);
+  if (!label)
+    return FALSE;
+  len = strlen(label);
+
+  for (pl = currPl; pl; pl = pl->next)
+    {
+      if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
+        {
+          if (strncmp(pl->line, label, len) == 0)
+            break; /* Found Label */
+          if (strlen(pl->line) != 7       || !ISCHARDIGIT(*(pl->line))   ||
+              !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
+              !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
+              *(pl->line+5) != '$')
+            {
+              return FALSE; /* non-local label encountered */
+            }
+        }
+    }
+  if (!pl)
+    return FALSE; /* did not find the label */
+  pl = pl->next;
+  while (pl && (pl->isDebug || pl->isComment))
+    pl = pl->next;
+  if (!pl || !pl->line)
+    return FALSE; /* next line not valid */
+  p = pl->line;
+  while (*p && ISCHARSPACE(*p))
+    p++;
+
+  if (TARGET_MCS51_LIKE)
+    jpInst = "ljmp";
+  if (TARGET_IS_HC08)
+    jpInst = "jmp";
+  if (TARGET_Z80_LIKE)
+    jpInst = "jp";
+  len = strlen(jpInst);
+  if (strncmp(p, jpInst, len) != 0)
+    return FALSE; /* next line is no jump */
+  p += len;
+  while (*p && ISCHARSPACE(*p))
+    p++;
+
+  q = p;
+  while (*q && *q!=';')
+    q++;
+  while (q>p && ISCHARSPACE(*q))
+    q--;
+  len = q-p;
+  if (len == 0)
+    return FALSE; /* no destination? */
+  if (TARGET_Z80_LIKE)
+    {
+      while (q>p && *q!=',')
+        q--;
+      if (*q==',')
+        return FALSE; /* conditional jump */
+    }
+  if (strcmp(p, q) == 0)
+    return FALSE; /* labels are equal */
+  /* now put the destination in %6 */
+  bindVar (6, &p, &vars);
+  return TRUE;
+}
 
 /*-----------------------------------------------------------------*/
 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other      */
@@ -289,19 +418,54 @@ FBYNAME (okToRemoveSLOC)
 
   /* Look for any occurance of this SLOC before the peephole match */
   for (pl = currPl->prev; pl; pl = pl->prev) {
-       if (pl->line && !pl->isDebug && !pl->isComment
-         && *pl->line != ';' && strstr(pl->line, sloc))
-               return FALSE;
+        if (pl->line && !pl->isDebug && !pl->isComment
+          && *pl->line != ';' && strstr(pl->line, sloc))
+                return FALSE;
   }
   /* Look for any occurance of this SLOC after the peephole match */
   for (pl = endPl->next; pl; pl = pl->next) {
-       if (pl->line && !pl->isDebug && !pl->isComment
-         && *pl->line != ';' && strstr(pl->line, sloc))
-               return FALSE;
+        if (pl->line && !pl->isDebug && !pl->isComment
+          && *pl->line != ';' && strstr(pl->line, sloc))
+                return FALSE;
   }
   return TRUE; /* safe for a peephole to remove it :) */
 }
 
+/*-----------------------------------------------------------------*/
+/* deadMove - Check, if a pop/push pair can be removed             */
+/*-----------------------------------------------------------------*/
+FBYNAME (deadMove)
+{
+  const char *reg = hTabItemWithKey (vars, 1);
+
+  if (port->peep.deadMove)
+    return port->peep.deadMove (reg, currPl, head);
+
+  fprintf (stderr, "Function deadMove not initialized in port structure\n");
+  return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* notUsed - Check, if value in register is not read again         */
+/*-----------------------------------------------------------------*/
+FBYNAME (notUsed)
+{
+  const char *what;
+
+  if(cmdLine[0] != '\'')
+    what = hTabItemWithKey (vars, 1);
+  else
+  {
+    cmdLine[strlen(cmdLine) - 1] = 0;
+    what = cmdLine + 1;
+  }
+
+  if (port->peep.notUsed)
+    return port->peep.notUsed (what, endPl, head);
+
+  fprintf (stderr, "Function notUsed not initialized in port structure\n");
+  return FALSE;
+}
 
 /*-----------------------------------------------------------------*/
 /* operandsNotSame - check if %1 & %2 are the same                 */
@@ -413,7 +577,6 @@ FBYNAME (operandsNotSame6)
     return TRUE;
 }
 
-
 /*-----------------------------------------------------------------*/
 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
 /*-----------------------------------------------------------------*/
@@ -500,6 +663,34 @@ FBYNAME (operandsNotSame8)
     return TRUE;
 }
 
+/*-----------------------------------------------------------------*/
+/* labelHashEntry- searches for a label in the list labelHash      */
+/* Builds labelHash, if it does not yet exist.                     */
+/* Returns the labelHashEntry or NULL                              */
+/*-----------------------------------------------------------------*/
+labelHashEntry *
+getLabelRef (const char *label, lineNode *head)
+{
+  labelHashEntry *entry;
+
+  /* If we don't have the label hash table yet, build it. */
+  if (!labelHash)
+    {
+      buildLabelRefCountHash (head);
+    }
+
+  entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
+
+  while (entry)
+    {
+      if (!strcmp (label, entry->name))
+        {
+          break;
+        }
+      entry = hTabNextItemWK (labelHash);
+    }
+  return entry;
+}
 
 /* labelRefCount:
 
@@ -514,60 +705,120 @@ FBYNAME (labelRefCount)
   int varNumber, expectedRefCount;
   bool rc = FALSE;
 
+  if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
+    {
+      char *label = hTabItemWithKey (vars, varNumber);
+
+      if (label)
+        {
+          labelHashEntry *entry = getLabelRef (label, head);
+
+          if (entry)
+            {
+#if 0
+              /* debug spew. */
+              fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
+                       label, entry->refCount, expectedRefCount);
+#endif
+
+              rc = (expectedRefCount == entry->refCount);
+            }
+          else
+            {
+              fprintf (stderr, "*** internal error: no label has entry for"
+                       " %s in labelRefCount peephole.\n",
+                       label);
+            }
+        }
+      else
+        {
+          fprintf (stderr, "*** internal error: var %d not bound"
+                   " in peephole labelRefCount rule.\n",
+                   varNumber);
+        }
+
+    }
+  else
+    {
+      fprintf (stderr,
+               "*** internal error: labelRefCount peephole restriction"
+               " malformed: %s\n", cmdLine);
+    }
+  return rc;
+}
+
+/* labelRefCountChange:
+ * takes two parameters: a variable (bound to a label name)
+ * and a signed int for changing the reference count.
+ *
+ * Please note, this function is not a conditional. It unconditionally
+ * changes the label. It should be passed as the 'last' function
+ * so it only is applied if all other conditions have been met.
+ *
+ * should always return TRUE
+ */
+FBYNAME (labelRefCountChange)
+{
+  int varNumber, RefCountDelta;
+  bool rc = FALSE;
+
   /* If we don't have the label hash table yet, build it. */
   if (!labelHash)
     {
       buildLabelRefCountHash (head);
     }
 
-  if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
+  if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
     {
       char *label = hTabItemWithKey (vars, varNumber);
 
       if (label)
-       {
-         labelHashEntry *entry;
-
-         entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
-
-         while (entry)
-           {
-             if (!strcmp (label, entry->name))
-               {
-                 break;
-               }
-             entry = hTabNextItemWK (labelHash);
-           }
-         if (entry)
-           {
-#if 0
-             /* debug spew. */
-             fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
-                      label, entry->refCount, expectedRefCount);
-#endif
+        {
+          labelHashEntry *entry;
 
-             rc = (expectedRefCount == entry->refCount);
-           }
-         else
-           {
-             fprintf (stderr, "*** internal error: no label has entry for"
-                      " %s in labelRefCount peephole.\n",
-                      label);
-           }
-       }
-      else
-       {
-         fprintf (stderr, "*** internal error: var %d not bound"
-                  " in peephole labelRefCount rule.\n",
-                  varNumber);
-       }
+          entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
 
+          while (entry)
+            {
+              if (!strcmp (label, entry->name))
+                {
+                  break;
+                }
+              entry = hTabNextItemWK (labelHash);
+            }
+          if (entry)
+            {
+              if (0 <= entry->refCount + RefCountDelta)
+                {
+                  entry->refCount += RefCountDelta;
+                  rc = TRUE;
+                }
+              else
+                {
+                  fprintf (stderr, "*** internal error: label %s may not get"
+                          " negative refCount in %s peephole.\n",
+                           label, __FUNCTION__);
+                }
+            }
+            else
+            {
+              fprintf (stderr, "*** internal error: no label has entry for"
+                       " %s in %s peephole.\n",
+                       label, __FUNCTION__);
+            }
+        }
+      else
+        {
+          fprintf (stderr, "*** internal error: var %d not bound"
+                   " in peephole %s rule.\n",
+                   varNumber, __FUNCTION__);
+        }
     }
   else
     {
       fprintf (stderr,
-              "*** internal error: labelRefCount peephole restriction"
-              " malformed: %s\n", cmdLine);
+               "*** internal error: labelRefCount peephole restriction"
+               " malformed: %s\n", cmdLine);
     }
   return rc;
 }
@@ -614,7 +865,7 @@ notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
   /* Extract a symbol name from the variable */
   while (*vp && (*vp!='_'))
     vp++;
-  while (*vp && (isalnum(*vp) || *vp=='_'))
+  while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
     *p++ = *vp++;
   *p='\0';
 
@@ -636,26 +887,56 @@ notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
           {
           case IFX:
             op = IC_COND (cl->ic);
-            if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
-              return !op->isvolatile;
+            if (IS_SYMOP (op) &&
+                ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
+                  (OP_SYMBOL (op)->isspilt &&
+                   SPIL_LOC (op) &&
+                   !strcmp(SPIL_LOC (op)->rname, symname)) ))
+              {
+                return !op->isvolatile;
+              }
           case JUMPTABLE:
             op = IC_JTCOND (cl->ic);
-            if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
-              return !op->isvolatile;
+            if (IS_SYMOP (op) &&
+                ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
+                  (OP_SYMBOL (op)->isspilt &&
+                   SPIL_LOC (op) &&
+                   !strcmp(SPIL_LOC (op)->rname, symname)) ))
+              {
+                return !op->isvolatile;
+              }
           default:
             op = IC_LEFT (cl->ic);
-            if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
-              return !op->isvolatile;
+            if (IS_SYMOP (op) &&
+                ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
+                  (OP_SYMBOL (op)->isspilt &&
+                   SPIL_LOC (op) &&
+                   !strcmp(SPIL_LOC (op)->rname, symname)) ))
+              {
+                return !op->isvolatile;
+              }
             op = IC_RIGHT (cl->ic);
-            if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
-              return !op->isvolatile;
+            if (IS_SYMOP (op) &&
+                ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
+                  (OP_SYMBOL (op)->isspilt &&
+                   SPIL_LOC (op) &&
+                   !strcmp(SPIL_LOC (op)->rname, symname)) ))
+              {
+                return !op->isvolatile;
+              }
             op = IC_RESULT (cl->ic);
-            if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
-              return !op->isvolatile;
+            if (IS_SYMOP (op) &&
+                ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
+                  (OP_SYMBOL (op)->isspilt &&
+                   SPIL_LOC (op) &&
+                   !strcmp(SPIL_LOC (op)->rname, symname)) ))
+              {
+                return !op->isvolatile;
+              }
           }
       }
   }
-  
+
   /* Couldn't find the symbol for some reason. Assume volatile. */
   return FALSE;
 }
@@ -717,18 +998,18 @@ FBYNAME (notVolatile)
     }
 
   /* There were parameters; check the volatility of each */
-  while (*cmdLine && isspace(*cmdLine))
+  while (*cmdLine && ISCHARSPACE(*cmdLine))
     cmdLine++;
   while (*cmdLine)
     {
       if (*cmdLine!='%')
         goto error;
       cmdLine++;
-      if (!isdigit(*cmdLine))
+      if (!ISCHARDIGIT(*cmdLine))
         goto error;
       varNumber = strtol(cmdLine, &digitend, 10);
       cmdLine = digitend;
-      while (*cmdLine && isspace(*cmdLine))
+      while (*cmdLine && ISCHARSPACE(*cmdLine))
         cmdLine++;
 
       var = hTabItemWithKey (vars, varNumber);
@@ -740,153 +1021,364 @@ FBYNAME (notVolatile)
             return FALSE;
         }
       else
-       {
-         fprintf (stderr, "*** internal error: var %d not bound"
-                  " in peephole notVolatile rule.\n",
-                  varNumber);
-         return FALSE;
-       }
+        {
+          fprintf (stderr, "*** internal error: var %d not bound"
+                   " in peephole notVolatile rule.\n",
+                   varNumber);
+          return FALSE;
+        }
     }
 
   return TRUE;
-    
-    
+
 error:
   fprintf (stderr,
            "*** internal error: notVolatile peephole restriction"
            " malformed: %s\n", cmdLine);
   return FALSE;
 }
-    
 
-/*-----------------------------------------------------------------*/
-/* callFuncByName - calls a function as defined in the table       */
-/*-----------------------------------------------------------------*/
-int 
-callFuncByName (char *fname,
-               hTab * vars,
-               lineNode * currPl,
-               lineNode * endPl,
-               lineNode * head)
+/*------------------------------------------------------------------*/
+/* setFromConditionArgs - parse a peephole condition's arguments    */
+/* to produce a set of strings, one per argument. Variables %x will */
+/* be replaced with their values. String literals (in single quotes)*/
+/* are accepted and return in unquoted form.                         */
+/*------------------------------------------------------------------*/
+static set *
+setFromConditionArgs (char *cmdLine, hTab * vars)
 {
-  struct ftab
-  {
-    char *fname;
-    int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
-  }
-  ftab[] =
-  {
-    {
-      "labelInRange", labelInRange
-    }
-    ,
-    {
-      "labelJTInRange", labelJTInRange
-    }
-    ,
-    {
-      "operandsNotSame", operandsNotSame
-    }
-    ,
-    {
-      "operandsNotSame3", operandsNotSame3
-    }
-    ,
-    {
-      "operandsNotSame4", operandsNotSame4
-    }
-    ,
-    {
-      "operandsNotSame5", operandsNotSame5
-    }
-    ,
-    {
-      "operandsNotSame6", operandsNotSame6
-    }
-    ,
+  int varNumber;
+  char *var;
+  char *digitend;
+  set *operands = NULL;
+
+  if (!cmdLine)
+    return NULL;
+
+  while (*cmdLine && ISCHARSPACE(*cmdLine))
+    cmdLine++;
+
+  while (*cmdLine)
     {
-      "operandsNotSame7", operandsNotSame7
+      if (*cmdLine == '%')
+        {
+          cmdLine++;
+          if (!ISCHARDIGIT(*cmdLine))
+            goto error;
+          varNumber = strtol(cmdLine, &digitend, 10);
+          cmdLine = digitend;
+
+          var = hTabItemWithKey (vars, varNumber);
+
+          if (var)
+            {
+              addSetHead (&operands, var);
+            }
+          else
+            goto error;
+        }
+      else if (*cmdLine == '\'' )
+        {
+          char quote = *cmdLine;
+
+          var = ++cmdLine;
+          while (*cmdLine && *cmdLine != quote)
+            cmdLine++;
+          if (*cmdLine == quote)
+            *cmdLine++ = '\0';
+          else
+            goto error;
+          addSetHead (&operands, var);
+        }
+      else
+        goto error;
+
+      while (*cmdLine && ISCHARSPACE(*cmdLine))
+        cmdLine++;
     }
-    ,
+
+  return operands;
+
+error:
+  deleteSet (&operands);
+  return NULL;
+}
+
+static const char *
+operandBaseName (const char *op)
+{
+  if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
     {
-      "operandsNotSame8", operandsNotSame8
+      if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
+        return "a";
+      if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
+        return op+1;
+      // bug 1739475, temp fix
+      if (op[0] == '@')
+        return operandBaseName(op+1);
     }
-    ,    
+
+  return op;
+}
+
+/*-------------------------------------------------------------------*/
+/* operandsNotRelated - returns true if the condition's operands are */
+/* not related (taking into account register name aliases). N-way    */
+/* comparison performed between all operands.                        */
+/*-------------------------------------------------------------------*/
+FBYNAME (operandsNotRelated)
+{
+  set *operands;
+  const char *op1, *op2;
+
+  operands = setFromConditionArgs (cmdLine, vars);
+
+  if (!operands)
     {
-      "24bitMode", flat24bitMode
+      fprintf (stderr,
+               "*** internal error: operandsNotRelated peephole restriction"
+               " malformed: %s\n", cmdLine);
+      return FALSE;
     }
-    ,
+
+  while ((op1 = setFirstItem (operands)))
     {
-      "xramMovcOption", xramMovcOption
+      deleteSetItem (&operands, (void*)op1);
+      op1 = operandBaseName (op1);
+
+      for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
+        {
+          op2 = operandBaseName (op2);
+          if (strcmp (op1, op2) == 0)
+            {
+              deleteSet (&operands);
+              return FALSE;
+            }
+        }
     }
-    ,
+
+  deleteSet (&operands);
+  return TRUE;
+}
+
+/*-------------------------------------------------------------------*/
+/* operandsLiteral - returns true of the condition's operands are    */
+/* literals.                                                         */
+/*-------------------------------------------------------------------*/
+FBYNAME (operandsLiteral)
+{
+  set *operands;
+  const char *op;
+
+  operands = setFromConditionArgs (cmdLine, vars);
+
+  if (!operands)
     {
-      "labelRefCount", labelRefCount
+      fprintf (stderr,
+               "*** internal error: operandsLiteral peephole restriction"
+               " malformed: %s\n", cmdLine);
+      return FALSE;
     }
-    ,
-    {
-      "portIsDS390", portIsDS390
-    },
-    {
-      "labelIsReturnOnly", labelIsReturnOnly
-    },
-    {
-      "okToRemoveSLOC", okToRemoveSLOC
-    },
-    {
-      "24bitModeAndPortDS390", flat24bitModeAndPortDS390
-    },
+
+  for (op = setFirstItem (operands); op; op = setNextItem (operands))
     {
-      "notVolatile", notVolatile
+      if (!isdigit(*op))
+        {
+          deleteSet (&operands);
+          return FALSE;
+        }
     }
-  };
-  int  i;
-  char  *cmdCopy, *funcName, *funcArgs;
-  int  rc = -1;
-    
-  /* Isolate the function name part (we are passed the full condition 
-   * string including arguments) 
+
+  deleteSet (&operands);
+  return TRUE;
+}
+
+static const struct ftab
+{
+  char *fname;
+  int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
+}
+ftab[] =                                // sorted on the number of times used
+{                                       // in the peephole rules on 2007-10-29
+  {
+    "labelRefCount", labelRefCount                  //105
+  },
+  {
+    "notVolatile", notVolatile                      //85
+  },
+  {
+    "labelRefCountChange", labelRefCountChange      //74
+  },
+  {
+    "labelInRange", labelInRange                    //37
+  },
+  {
+    "labelJTInRange", labelJTInRange                //13
+  },
+  {
+    "operandsNotRelated", operandsNotRelated        //9
+  },
+  {
+    "24bitMode", flat24bitMode                      //9
+  },
+  {
+    "operandsNotSame", operandsNotSame              //8
+  },
+  {
+    "operandsNotSame3", operandsNotSame3
+  },
+  {
+    "operandsNotSame4", operandsNotSame4
+  },
+  {
+    "operandsNotSame5", operandsNotSame5
+  },
+  {
+    "operandsNotSame6", operandsNotSame6
+  },
+  {
+    "operandsNotSame7", operandsNotSame7
+  },
+  {
+    "operandsNotSame8", operandsNotSame8
+  },
+  {
+    "xramMovcOption", xramMovcOption
+  },
+  {
+    "portIsDS390", portIsDS390
+  },
+  {
+    "labelIsReturnOnly", labelIsReturnOnly
+  },
+  {
+    "labelIsUncondJump", labelIsUncondJump
+  },
+  {
+    "okToRemoveSLOC", okToRemoveSLOC
+  },
+  {
+    "deadMove", deadMove
+  },
+  {
+    "operandsLiteral", operandsLiteral
+  },
+  {
+    "useAcallAjmp", useAcallAjmp
+  },
+  {
+    "notUsed", notUsed
+  }
+};
+/*-----------------------------------------------------------------*/
+/* callFuncByName - calls a function as defined in the table       */
+/*-----------------------------------------------------------------*/
+static int
+callFuncByName (char *fname,
+                hTab * vars,
+                lineNode * currPl, /* first source line matched */
+                lineNode * endPl,  /* last source line matched */
+                lineNode * head)
+{
+  int   i;
+  char  *cmdCopy, *funcName, *funcArgs, *cmdTerm;
+  char  c;
+  int   rc;
+
+  /* Isolate the function name part (we are passed the full condition
+   * string including arguments)
    */
-  cmdCopy = Safe_strdup(fname);
-  funcName = strtok(cmdCopy, " \t");
-  funcArgs = strtok(NULL, "");
+  cmdTerm = cmdCopy = Safe_strdup(fname);
 
-    for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
-    {
-       if (strcmp (ftab[i].fname, funcName) == 0)
-       {
-           rc = (*ftab[i].func) (vars, currPl, endPl, head,
-                                 funcArgs);
-       }
-    }
-    
-    if (rc == -1)
+  do
     {
-       fprintf (stderr, 
-                "could not find named function \"%s\" in "
-                "peephole function table\n",
-                funcName);
-        // If the function couldn't be found, let's assume it's
-       // a bad rule and refuse it.
-       rc = FALSE;
+      funcArgs = funcName = cmdTerm;
+      while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
+        funcArgs++;
+      *funcArgs = '\0';  /* terminate the function name */
+      if (c)
+        funcArgs++;
+
+      /* Find the start of the arguments */
+      if (c == ' ' || c == '\t')
+        while ((c = *funcArgs) && (c == ' ' || c == '\t'))
+          funcArgs++;
+
+      /* If the arguments started with an opening parenthesis,  */
+      /* use the closing parenthesis for the end of the         */
+      /* arguments and look for the start of another condition  */
+      /* that can optionally follow. If there was no opening    */
+      /* parethesis, then everything that follows are arguments */
+      /* and there can be no additional conditions.             */
+      if (c == '(')
+        {
+
+          int num_parenthesis = 0;
+          cmdTerm = funcArgs;          
+
+          while ((c = *cmdTerm) && (c != ')' || num_parenthesis))
+            {
+              if (c == '(')
+                num_parenthesis++;
+              else if (c == ')')
+                num_parenthesis--;
+              cmdTerm++;
+            }
+          *cmdTerm = '\0';  /* terminate the arguments */
+          if (c == ')')
+            {
+              cmdTerm++;
+              while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
+                cmdTerm++;
+              if (!*cmdTerm)
+                cmdTerm = NULL;
+            }
+          else
+            cmdTerm = NULL; /* closing parenthesis missing */
+        }
+      else
+        cmdTerm = NULL;
+
+      if (!*funcArgs)
+        funcArgs = NULL;
+
+      rc = -1;
+      for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
+        {
+          if (strcmp (ftab[i].fname, funcName) == 0)
+            {
+              rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
+              break;
+            }
+        }
+
+      if (rc == -1)
+        {
+          fprintf (stderr,
+                   "could not find named function \"%s\" in "
+                   "peephole function table\n",
+                   funcName);
+          // If the function couldn't be found, let's assume it's
+          // a bad rule and refuse it.
+          rc = FALSE;
+          break;
+        }
     }
+  while (rc && cmdTerm);
+
+  Safe_free(cmdCopy);
 
-    Safe_free(cmdCopy);
-    
   return rc;
 }
 
 /*-----------------------------------------------------------------*/
 /* printLine - prints a line chain into a given file               */
 /*-----------------------------------------------------------------*/
-void 
-printLine (lineNode * head, FILE * of)
+void
+printLine (lineNode * head, struct dbuf_s * oBuf)
 {
   iCode *last_ic = NULL;
   bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
-  
-  if (!of)
-    of = stdout;
 
   while (head)
     {
@@ -896,24 +1388,23 @@ printLine (lineNode * head, FILE * of)
           if (debug_iCode_tracking)
             {
               if (head->ic)
-                fprintf (of, "; block = %d, seq = %d\n",
+                dbuf_printf (oBuf, "; block = %d, seq = %d\n",
                          head->ic->block, head->ic->seq);
               else
-                fprintf (of, "; iCode lost\n");
+                dbuf_append_str (oBuf, "; iCode lost\n");
             }
         }
-        
+
       /* don't indent comments & labels */
       if (head->line &&
-         (*head->line == ';' ||
-          head->line[strlen (head->line) - 1] == ':')) {
-       fprintf (of, "%s\n", head->line);
+          (head->isComment || head->isLabel)) {
+        dbuf_printf (oBuf, "%s\n", head->line);
       } else {
-       if (head->isInline && *head->line=='#') {
-         // comment out preprocessor directives in inline asm
-         fprintf (of, ";");
-       }
-       fprintf (of, "\t%s\n", head->line);
+        if (head->isInline && *head->line=='#') {
+          // comment out preprocessor directives in inline asm
+          dbuf_append_char (oBuf, ';');
+        }
+        dbuf_printf (oBuf, "\t%s\n", head->line);
       }
       head = head->next;
     }
@@ -922,11 +1413,11 @@ printLine (lineNode * head, FILE * of)
 /*-----------------------------------------------------------------*/
 /* newPeepRule - creates a new peeprule and attach it to the root  */
 /*-----------------------------------------------------------------*/
-peepRule *
+static peepRule *
 newPeepRule (lineNode * match,
-            lineNode * replace,
-            char *cond,
-            int restart)
+             lineNode * replace,
+             char *cond,
+             int restart)
 {
   peepRule *pr;
 
@@ -957,7 +1448,7 @@ newPeepRule (lineNode * match,
 /* newLineNode - creates a new peep line                           */
 /*-----------------------------------------------------------------*/
 lineNode *
-newLineNode (char *line)
+newLineNode (const char *line)
 {
   lineNode *pl;
 
@@ -985,7 +1476,7 @@ connectLine (lineNode * pl1, lineNode * pl2)
   return pl2;
 }
 
-#define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
+#define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
                          if (!*x) { fprintf(stderr,y); return ; } }
 
 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
@@ -996,7 +1487,7 @@ connectLine (lineNode * pl1, lineNode * pl2)
 /*-----------------------------------------------------------------*/
 /* getPeepLine - parses the peep lines                             */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 getPeepLine (lineNode ** head, char **bpp)
 {
   char lines[MAX_PATTERN_LEN];
@@ -1009,44 +1500,49 @@ getPeepLine (lineNode ** head, char **bpp)
     {
 
       if (!*bp)
-       {
-         fprintf (stderr, "unexpected end of match pattern\n");
-         return;
-       }
+        {
+          fprintf (stderr, "unexpected end of match pattern\n");
+          return;
+        }
 
       if (*bp == '\n')
-       {
-         bp++;
-         while (isspace (*bp) ||
-                *bp == '\n')
-           bp++;
-       }
+        {
+          bp++;
+          while (ISCHARSPACE (*bp) ||
+                 *bp == '\n')
+            bp++;
+        }
 
       if (*bp == '}')
-       {
-         bp++;
-         break;
-       }
+        {
+          bp++;
+          break;
+        }
 
       /* read till end of line */
       lp = lines;
       while ((*bp != '\n' && *bp != '}') && *bp)
-       *lp++ = *bp++;
+        *lp++ = *bp++;
       *lp = '\0';
-      
+
       lp = lines;
-      while (*lp && isspace(*lp))
+      while (*lp && ISCHARSPACE(*lp))
         lp++;
       isComment = (*lp == ';');
-        
+
       if (!isComment || (isComment && !options.noPeepComments))
-       {
-         if (!currL)
-           *head = currL = newLineNode (lines);
-         else
-           currL = connectLine (currL, newLineNode (lines));
-         currL->isComment = isComment;
-       }
+        {
+          const char *dummy1;
+          int dummy2;
+
+          if (!currL)
+            *head = currL = newLineNode (lines);
+          else
+            currL = connectLine (currL, newLineNode (lines));
+          currL->isComment = isComment;
+          currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
+                                              TRUE);
+        }
 
     }
 
@@ -1056,12 +1552,12 @@ getPeepLine (lineNode ** head, char **bpp)
 /*-----------------------------------------------------------------*/
 /* readRules - reads the rules from a string buffer                */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 readRules (char *bp)
 {
   char restart = 0;
   char lines[MAX_PATTERN_LEN];
-  char *lp;
+  char *lp, *rp;
   lineNode *match;
   lineNode *replace;
   lineNode *currL = NULL;
@@ -1081,7 +1577,7 @@ top:
 
   /* then look for either "restart" or '{' */
   while (strncmp (bp, "restart", 7) &&
-        *bp != '{' && bp)
+         *bp != '{' && bp)
     bp++;
 
   /* not found */
@@ -1095,7 +1591,7 @@ top:
   if (*bp == '{')
     bp++;
   else
-    {                          /* must be restart */
+    {                           /* must be restart */
       restart++;
       bp += strlen ("restart");
       /* look for '{' */
@@ -1117,36 +1613,65 @@ top:
   EXPECT_CHR (bp, '{', "expected '{'\n");
   bp++;
 
+  /* save char position (needed for generating error msg) */
+  rp = bp;
+
   SKIP_SPACE (bp, "unexpected end of rule\n");
   getPeepLine (&replace, &bp);
 
   /* look for a 'if' */
-  while ((isspace (*bp) || *bp == '\n') && *bp)
+  while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
     bp++;
 
   if (strncmp (bp, "if", 2) == 0)
     {
       bp += 2;
-      while ((isspace (*bp) || *bp == '\n') && *bp)
-       bp++;
+      while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
+        bp++;
       if (!*bp)
-       {
-         fprintf (stderr, "expected condition name\n");
-         return;
-       }
+        {
+          fprintf (stderr, "expected condition name\n");
+          return;
+        }
 
       /* look for the condition */
       lp = lines;
       while (*bp && (*bp != '\n'))
-       {
-         *lp++ = *bp++;
-       }
+        {
+          *lp++ = *bp++;
+        }
       *lp = '\0';
 
       newPeepRule (match, replace, lines, restart);
     }
   else
-    newPeepRule (match, replace, NULL, restart);
+    {
+      if (*bp && strncmp (bp, "replace", 7))
+        {
+          /* not the start of a new peeprule, so "if" should be here */
+
+          char strbuff[1000];
+          char *cp;
+
+          /* go to the start of the line following "{" of the "by" token */
+          while (*rp && (*rp == '\n'))
+            rp++;
+
+          /* copy text of rule starting with line after "by {" */
+          cp = strbuff;
+          while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
+              *cp++ = *rp++;
+
+          /* and now the rest of the line */
+          while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
+            *cp++ = *rp++;
+
+          *cp = '\0';
+          fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
+          return;
+        }
+      newPeepRule (match, replace, NULL, restart);
+    }
   goto top;
 
 }
@@ -1154,12 +1679,12 @@ top:
 /*-----------------------------------------------------------------*/
 /* keyForVar - returns the numeric key for a var                   */
 /*-----------------------------------------------------------------*/
-static int 
+static int
 keyForVar (char *d)
 {
   int i = 0;
 
-  while (isdigit (*d))
+  while (ISCHARDIGIT (*d))
     {
       i *= 10;
       i += (*d++ - '0');
@@ -1171,7 +1696,7 @@ keyForVar (char *d)
 /*-----------------------------------------------------------------*/
 /* bindVar - binds a value to a variable in the given hashtable    */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 bindVar (int key, char **s, hTab ** vtab)
 {
   char vval[MAX_PATTERN_LEN];
@@ -1182,30 +1707,30 @@ bindVar (int key, char **s, hTab ** vtab)
   vvx = *s;
   /* the value is ended by a ',' or space or newline or null or ) */
   while (*vvx &&
-        *vvx != ',' &&
-        !isspace (*vvx) &&
-        *vvx != '\n' &&
-        *vvx != ':' &&
-        *vvx != ')')
+         *vvx != ',' &&
+         !ISCHARSPACE (*vvx) &&
+         *vvx != '\n' &&
+         *vvx != ':' &&
+         *vvx != ')')
     {
       char ubb = 0;
       /* if we find a '(' then we need to balance it */
       if (*vvx == '(')
-       {
-         ubb++;
-         while (ubb)
-           {
-             *vv++ = *vvx++;
-             if (*vvx == '(')
-               ubb++;
-             if (*vvx == ')')
-               ubb--;
-           }
-         // include the trailing ')'
-         *vv++ = *vvx++;
-       }
+        {
+          ubb++;
+          while (ubb)
+            {
+              *vv++ = *vvx++;
+              if (*vvx == '(')
+                ubb++;
+              if (*vvx == ')')
+                ubb--;
+            }
+          // include the trailing ')'
+          *vv++ = *vvx++;
+        }
       else
-       *vv++ = *vvx++;
+        *vv++ = *vvx++;
     }
   *s = vvx;
   *vv = '\0';
@@ -1218,67 +1743,64 @@ bindVar (int key, char **s, hTab ** vtab)
 /*-----------------------------------------------------------------*/
 /* matchLine - matches one line                                    */
 /*-----------------------------------------------------------------*/
-static bool 
+static bool
 matchLine (char *s, char *d, hTab ** vars)
 {
-
   if (!s || !(*s))
     return FALSE;
 
   while (*s && *d)
     {
-
       /* skip white space in both */
-      while (isspace (*s))
-       s++;
-      while (isspace (*d))
-       d++;
+      while (ISCHARSPACE (*s))
+        s++;
+      while (ISCHARSPACE (*d))
+        d++;
 
       /* if the destination is a var */
-      if (*d == '%' && isdigit (*(d + 1)) && vars)
-       {
-         char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
-         /* if the variable is already bound
-            then it MUST match with dest */
-         if (v)
-           {
-             while (*v)
-               if (*v++ != *s++)
-                 return FALSE;
-           }
-         else
-           /* variable not bound we need to
-              bind it */
-           bindVar (keyForVar (d + 1), &s, vars);
-
-         /* in either case go past the variable */
-         d++;
-         while (isdigit (*d))
-           d++;
-
-         while (isspace (*s))
-           s++;
-         while (isspace (*d))
-           d++;
-       }
+      if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
+        {
+          char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
+          /* if the variable is already bound
+             then it MUST match with dest */
+          if (v)
+            {
+              while (*v)
+                if (*v++ != *s++)
+                  return FALSE;
+            }
+          else
+            /* variable not bound we need to bind it */
+            bindVar (keyForVar (d + 1), &s, vars);
+
+          /* in either case go past the variable */
+          d++;
+          while (ISCHARDIGIT (*d))
+            d++;
+
+          while (ISCHARSPACE (*s))
+            s++;
+          while (ISCHARSPACE (*d))
+            d++;
+        }
 
       /* they should be an exact match other wise */
       if (*s && *d)
-       {
-         if (*s++ != *d++)
-           return FALSE;
-       }
+        {
+          if (*s++ != *d++)
+            return FALSE;
+        }
 
     }
 
   /* get rid of the trailing spaces
      in both source & destination */
   if (*s)
-    while (isspace (*s))
+    while (ISCHARSPACE (*s))
       s++;
 
   if (*d)
-    while (isspace (*d))
+    while (ISCHARSPACE (*d))
       d++;
 
   /* after all this if only one of them
@@ -1292,14 +1814,14 @@ matchLine (char *s, char *d, hTab ** vars)
 /*-----------------------------------------------------------------*/
 /* matchRule - matches a all the rule lines                        */
 /*-----------------------------------------------------------------*/
-static bool 
+static bool
 matchRule (lineNode * pl,
-          lineNode ** mtail,
-          peepRule * pr,
-          lineNode * head)
+           lineNode ** mtail,
+           peepRule * pr,
+           lineNode * head)
 {
-  lineNode *spl;               /* source pl */
-  lineNode *rpl;               /* rule peep line */
+  lineNode *spl;                /* source pl */
+  lineNode *rpl;                /* rule peep line */
 
 /*     setToNull((void *) &pr->vars);    */
 /*     pr->vars = newHashTable(100); */
@@ -1314,18 +1836,18 @@ matchRule (lineNode * pl,
          comment line don't process or the source line
          contains == . debugger information skip it */
       if (spl->line &&
-         (*spl->line == ';' || spl->isDebug))
-       {
-         spl = spl->next;
-         continue;
-       }
+          (*spl->line == ';' || spl->isDebug))
+        {
+          spl = spl->next;
+          continue;
+        }
 
       if (!matchLine (spl->line, rpl->line, &pr->vars))
-       return FALSE;
+        return FALSE;
 
       rpl = rpl->next;
       if (rpl)
-       spl = spl->next;
+        spl = spl->next;
     }
 
   /* if rules ended */
@@ -1333,20 +1855,20 @@ matchRule (lineNode * pl,
     {
       /* if this rule has additional conditions */
       if (pr->cond)
-       {
-         if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
-           {
-             *mtail = spl;
-             return TRUE;
-           }
-         else
-           return FALSE;
-       }
+        {
+          if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
+            {
+              *mtail = spl;
+              return TRUE;
+            }
+          else
+            return FALSE;
+        }
       else
-       {
-         *mtail = spl;
-         return TRUE;
-       }
+        {
+          *mtail = spl;
+          return TRUE;
+        }
     }
   else
     return FALSE;
@@ -1356,8 +1878,8 @@ static void
 reassociate_ic_down (lineNode *shead, lineNode *stail,
                      lineNode *rhead, lineNode *rtail)
 {
-  lineNode *csl;       /* current source line */
-  lineNode *crl;       /* current replacement line */
+  lineNode *csl;        /* current source line */
+  lineNode *crl;        /* current replacement line */
 
   csl = shead;
   crl = rhead;
@@ -1388,8 +1910,8 @@ static void
 reassociate_ic_up (lineNode *shead, lineNode *stail,
                    lineNode *rhead, lineNode *rtail)
 {
-  lineNode *csl;       /* current source line */
-  lineNode *crl;       /* current replacement line */
+  lineNode *csl;        /* current source line */
+  lineNode *crl;        /* current replacement line */
 
   csl = stail;
   crl = rtail;
@@ -1423,11 +1945,11 @@ static void
 reassociate_ic (lineNode *shead, lineNode *stail,
                 lineNode *rhead, lineNode *rtail)
 {
-  lineNode *csl;       /* current source line */
-  lineNode *crl;       /* current replacement line */
+  lineNode *csl;        /* current source line */
+  lineNode *crl;        /* current replacement line */
   bool single_iCode;
   iCode *ic;
-  
+
   /* Check to see if all the source lines (excluding comments) came
   ** for the same iCode
   */
@@ -1453,11 +1975,11 @@ reassociate_ic (lineNode *shead, lineNode *stail,
               crl->ic = ic;
             return;
           }
-            
+
         single_iCode = FALSE;
         break;
       }
-  
+
   /* If all of the source lines came from the same iCode, then so have
   ** all of the replacement lines too.
   */
@@ -1467,7 +1989,7 @@ reassociate_ic (lineNode *shead, lineNode *stail,
         crl->ic = ic;
       return;
     }
-  
+
   /* The source lines span iCodes, so we may end up with replacement
   ** lines that we don't know which iCode(s) to associate with. Do the
   ** best we can by using the following strategies:
@@ -1484,7 +2006,7 @@ reassociate_ic (lineNode *shead, lineNode *stail,
   /* Strategy #1: Start at the top and scan down for matches
   */
   reassociate_ic_down(shead,stail,rhead,rtail);
-  
+
   /* Strategy #2: Start at the bottom and scan up for matches
   */
   reassociate_ic_up(shead,stail,rhead,rtail);
@@ -1494,16 +2016,13 @@ reassociate_ic (lineNode *shead, lineNode *stail,
   csl = shead;
   while (1)
     {
-      const char *labelStart;
-      int labelLength;
-      
       /* skip over any comments */
       while (csl!=stail->next && csl->isComment)
         csl = csl->next;
       if (csl==stail->next)
         break;
 
-      if (isLabelDefinition(csl->line, &labelStart, &labelLength))
+      if (csl->isLabel)
         {
           /* found a source line label; look for it in the replacment lines */
           crl = rhead;
@@ -1524,7 +2043,7 @@ reassociate_ic (lineNode *shead, lineNode *stail,
         }
       csl = csl->next;
     }
-  
+
   /* Try to assign a meaningful iCode to any comment that is missing
      one. Since they are comments, it's ok to make mistakes; we are just
      trying to improve continuity to simplify other tests.
@@ -1538,11 +2057,11 @@ reassociate_ic (lineNode *shead, lineNode *stail,
     }
 }
 
-                  
+
 /*-----------------------------------------------------------------*/
 /* replaceRule - does replacement of a matching pattern            */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
 {
   lineNode *cl = NULL;
@@ -1557,12 +2076,12 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
   for (cl = *shead; cl != stail; cl = cl->next)
     {
       if (cl->line && (*cl->line == ';' || cl->isDebug))
-       {
-         pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
-               (comment = newLineNode (cl->line)));
-         pl->isDebug = cl->isDebug;
-         pl->isComment = cl->isComment || (*cl->line == ';');
-       }
+        {
+          pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
+                (comment = newLineNode (cl->line)));
+          pl->isDebug = cl->isDebug;
+          pl->isComment = cl->isComment || (*cl->line == ';');
+        }
     }
   cl = NULL;
 
@@ -1576,35 +2095,36 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
       l = pl->line;
 
       while (*l)
-       {
-         /* if the line contains a variable */
-         if (*l == '%' && isdigit (*(l + 1)))
-           {
-             v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
-             if (!v)
-               {
-                 fprintf (stderr, "used unbound variable in replacement\n");
-                 l++;
-                 continue;
-               }
-             while (*v) {
-               *lbp++ = *v++;
-             }
-             l++;
-             while (isdigit (*l)) {
-               l++;
-             }
-             continue;
-           }
-         *lbp++ = *l++;
-       }
+        {
+          /* if the line contains a variable */
+          if (*l == '%' && ISCHARDIGIT (*(l + 1)))
+            {
+              v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
+              if (!v)
+                {
+                  fprintf (stderr, "used unbound variable in replacement\n");
+                  l++;
+                  continue;
+                }
+              while (*v) {
+                *lbp++ = *v++;
+              }
+              l++;
+              while (ISCHARDIGIT (*l)) {
+                l++;
+              }
+              continue;
+            }
+          *lbp++ = *l++;
+        }
 
       *lbp = '\0';
       if (cl)
-       cl = connectLine (cl, newLineNode (lb));
+        cl = connectLine (cl, newLineNode (lb));
       else
-       lhead = cl = newLineNode (lb);
+        lhead = cl = newLineNode (lb);
       cl->isComment = pl->isComment;
+      cl->isLabel   = pl->isLabel;
     }
 
   /* add the comments if any to the head of list */
@@ -1612,10 +2132,10 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
     {
       lineNode *lc = comment;
       while (lc->next)
-       lc = lc->next;
+        lc = lc->next;
       lc->next = lhead;
       if (lhead)
-       lhead->prev = lc;
+        lhead->prev = lc;
       lhead = comment;
     }
 
@@ -1627,18 +2147,18 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
       /* now we need to connect / replace the original chain */
       /* if there is a prev then change it */
       if ((*shead)->prev)
-       {
-         (*shead)->prev->next = lhead;
-         lhead->prev = (*shead)->prev;
-       }
+        {
+          (*shead)->prev->next = lhead;
+          lhead->prev = (*shead)->prev;
+        }
       *shead = lhead;
       /* now for the tail */
       if (stail && stail->next)
-       {
-         stail->next->prev = cl;
-         if (cl)
-           cl->next = stail->next;
-       }
+        {
+          stail->next->prev = cl;
+          if (cl)
+            cl->next = stail->next;
+        }
     }
   else
     {
@@ -1656,8 +2176,9 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
  * If so, start will point to the start of the label name,
  * and len will be it's length.
  */
-bool 
-isLabelDefinition (const char *line, const char **start, int *len)
+bool
+isLabelDefinition (const char *line, const char **start, int *len,
+                   bool isPeepRule)
 {
   const char *cp = line;
 
@@ -1666,7 +2187,7 @@ isLabelDefinition (const char *line, const char **start, int *len)
    * (alnum | $ | _ ) followed by a colon.
    */
 
-  while (*cp && isspace (*cp))
+  while (*cp && ISCHARSPACE (*cp))
     {
       cp++;
     }
@@ -1678,7 +2199,8 @@ isLabelDefinition (const char *line, const char **start, int *len)
 
   *start = cp;
 
-  while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
+  while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
+         (isPeepRule && (*cp == '%')))
     {
       cp++;
     }
@@ -1693,7 +2215,7 @@ isLabelDefinition (const char *line, const char **start, int *len)
 }
 
 /* Quick & dirty string hash function. */
-static int 
+static int
 hashSymbolName (const char *name)
 {
   int hash = 0;
@@ -1715,7 +2237,7 @@ hashSymbolName (const char *name)
 /* Build a hash of all labels in the passed set of lines
  * and how many times they are referenced.
  */
-static void 
+static void
 buildLabelRefCountHash (lineNode * head)
 {
   lineNode *line;
@@ -1727,30 +2249,35 @@ buildLabelRefCountHash (lineNode * head)
   labelHash = newHashTable (HTAB_SIZE);
 
   /* First pass: locate all the labels. */
-  line = head;
-
-  while (line)
+  for (line = head; line; line = line->next)
     {
-      if (isLabelDefinition (line->line, &label, &labelLen)
-         && labelLen <= SDCC_NAME_MAX)
-       {
-         labelHashEntry *entry;
-
-         entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
-
-         memcpy (entry->name, label, labelLen);
-         entry->name[labelLen] = 0;
-         entry->refCount = -1;
-          
-          /* Assume function entry points are referenced somewhere,   */
-          /* even if we can't find a reference (might be from outside */
-          /* the function) */
-          if (line->ic && (line->ic->op == FUNCTION))
-            entry->refCount++;
-
-         hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
-       }
-      line = line->next;
+      if (line->isLabel  ||
+          line->isInline)
+        {
+          /* run isLabelDefinition to:
+             - look for labels in inline assembler
+             - calculate labelLen
+          */
+          if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
+              labelLen <= SDCC_NAME_MAX)
+            {
+              labelHashEntry *entry;
+
+              entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
+
+              memcpy (entry->name, label, labelLen);
+              entry->name[labelLen] = 0;
+              entry->refCount = -1;
+
+              /* Assume function entry points are referenced somewhere,   */
+              /* even if we can't find a reference (might be from outside */
+              /* the function) */
+              if (line->ic && (line->ic->op == FUNCTION))
+                entry->refCount++;
+
+              hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
+            }
+        }
     }
 
 
@@ -1760,20 +2287,20 @@ buildLabelRefCountHash (lineNode * head)
   while (line)
     {
       for (i = 0; i < HTAB_SIZE; i++)
-       {
-         labelHashEntry *thisEntry;
-
-         thisEntry = hTabFirstItemWK (labelHash, i);
-
-         while (thisEntry)
-           {
-             if (strstr (line->line, thisEntry->name))
-               {
-                 thisEntry->refCount++;
-               }
-             thisEntry = hTabNextItemWK (labelHash);
-           }
-       }
+        {
+          labelHashEntry *thisEntry;
+
+          thisEntry = hTabFirstItemWK (labelHash, i);
+
+          while (thisEntry)
+            {
+              if (strstr (line->line, thisEntry->name))
+                {
+                  thisEntry->refCount++;
+                }
+              thisEntry = hTabNextItemWK (labelHash);
+            }
+        }
       line = line->next;
     }
 
@@ -1786,11 +2313,11 @@ buildLabelRefCountHash (lineNode * head)
       thisEntry = hTabFirstItemWK (labelHash, i);
 
       while (thisEntry)
-       {
-         fprintf (stderr, "label: %s ref %d\n",
-                  thisEntry->name, thisEntry->refCount);
-         thisEntry = hTabNextItemWK (labelHash);
-       }
+        {
+          fprintf (stderr, "label: %s ref %d\n",
+                   thisEntry->name, thisEntry->refCount);
+          thisEntry = hTabNextItemWK (labelHash);
+        }
     }
 #endif
 }
@@ -1807,19 +2334,19 @@ buildLabelRefCountHash (lineNode * head)
      matchLine
 
   Where is stuff allocated?
-  
+
 */
 
 /*-----------------------------------------------------------------*/
 /* peepHole - matches & substitutes rules                          */
 /*-----------------------------------------------------------------*/
-void 
+void
 peepHole (lineNode ** pls)
 {
   lineNode *spl;
   peepRule *pr;
   lineNode *mtail = NULL;
-  bool restart;
+  bool restart, replaced;
 
 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
   /* The PIC port uses a different peep hole optimizer based on "pCode" */
@@ -1836,8 +2363,10 @@ peepHole (lineNode ** pls)
       /* for all rules */
       for (pr = rootRules; pr; pr = pr->next)
         {
-          for (spl = *pls; spl; spl = spl->next)
+          for (spl = *pls; spl; spl = replaced ? spl : spl->next)
             {
+              replaced = FALSE;
+
               /* if inline assembler then no peep hole */
               if (spl->isInline)
                 continue;
@@ -1846,21 +2375,26 @@ peepHole (lineNode ** pls)
               ** or comment */
               if (spl->isDebug || spl->isComment || *(spl->line)==';')
                 continue;
-              
+
               mtail = NULL;
 
               /* Tidy up any data stored in the hTab */
-              
+
               /* if it matches */
               if (matchRule (spl, &mtail, pr, *pls))
                 {
-                  
+                  /* restart at the replaced line */
+                  replaced = TRUE;
+
                   /* then replace */
                   if (spl == *pls)
-                    replaceRule (pls, mtail, pr);
+                    {
+                      replaceRule (pls, mtail, pr);
+                      spl = *pls;
+                    }
                   else
                     replaceRule (&spl, mtail, pr);
-                  
+
                   /* if restart rule type then
                      start at the top again */
                   if (pr->restart)
@@ -1868,14 +2402,14 @@ peepHole (lineNode ** pls)
                       restart = TRUE;
                     }
                 }
-              
+
               if (pr->vars)
                 {
                   hTabDeleteAll (pr->vars);
                   Safe_free (pr->vars);
                   pr->vars = NULL;
                 }
-              
+
               freeTrace (&_G.values);
             }
         }
@@ -1914,36 +2448,36 @@ readFileIntoBuffer (char *fname)
 
       /* if we maxed out our local buffer */
       if (nch >= (MAX_PATTERN_LEN - 2))
-       {
-         lb[nch] = '\0';
-         /* copy it into allocated buffer */
-         if (rs)
-           {
-             rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
-             strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
-           }
-         else
-           {
-             rs = Safe_strdup (lb);
-           }
-         nch = 0;
-       }
-    }
-
-  /* if some charaters left over */
+        {
+          lb[nch] = '\0';
+          /* copy it into allocated buffer */
+          if (rs)
+            {
+              rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
+              strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
+            }
+          else
+            {
+              rs = Safe_strdup (lb);
+            }
+          nch = 0;
+        }
+    }
+
+  /* if some characters left over */
   if (nch)
     {
       lb[nch] = '\0';
       /* copy it into allocated buffer */
       if (rs)
-       {
-         rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
-         strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
-       }
+        {
+          rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
+          strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
+        }
       else
-       {
-         rs = Safe_strdup (lb);
-       }
+        {
+          rs = Safe_strdup (lb);
+        }
     }
   return rs;
 }
@@ -1951,19 +2485,24 @@ readFileIntoBuffer (char *fname)
 /*-----------------------------------------------------------------*/
 /* initPeepHole - initialises the peep hole optimizer stuff        */
 /*-----------------------------------------------------------------*/
-void 
+void
 initPeepHole ()
 {
   char *s;
 
   /* read in the default rules */
-  readRules (port->peep.default_rules);
+  if (!options.nopeep)
+    {
+      readRules (port->peep.default_rules);
+    }
 
   /* if we have any additional file read it too */
   if (options.peep_file)
     {
       readRules (s = readFileIntoBuffer (options.peep_file));
       setToNull ((void *) &s);
+      /* override nopeep setting, default rules have not been read */
+      options.nopeep = 0;
     }
 
 
@@ -1971,8 +2510,8 @@ initPeepHole ()
   /* Convert the peep rules into pcode.
      NOTE: this is only support in the PIC port (at the moment)
   */
-       if (TARGET_IS_PIC)
-               peepRules2pCode(rootRules);
+        if (TARGET_IS_PIC)
+                peepRules2pCode(rootRules);
 #endif
 
 #if !OPT_DISABLE_PIC16
@@ -1980,8 +2519,8 @@ initPeepHole ()
      NOTE: this is only support in the PIC port (at the moment)
        and the PIC16 port (VR 030601)
   */
-       if (TARGET_IS_PIC16)
-               pic16_peepRules2pCode(rootRules);
+        if (TARGET_IS_PIC16)
+                pic16_peepRules2pCode(rootRules);
 
 #endif