* fixed GCC 4.4.0 mingw compilation:
[fw/sdcc] / src / SDCCpeeph.c
index c38627dc2a7e76bfb81779ad823aead57d3c2198..5a7447fff503ce66a2099c3a4ccd4d7da8c5a905 100644 (file)
@@ -24,6 +24,7 @@
 -------------------------------------------------------------------------*/
 
 #include "common.h"
+#include "dbuf_string.h"
 
 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
 #define ISCHARSPACE(c) isspace((unsigned char)c)
@@ -33,14 +34,8 @@ 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
 {
@@ -50,11 +45,11 @@ 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, \
+#define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
         lineNode *head, char *cmdLine)
 
 #if !OPT_DISABLE_PIC
@@ -66,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;
@@ -79,16 +105,19 @@ 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)
@@ -103,16 +132,6 @@ pcDistance (lineNode * cpos, char *lbl, bool back)
   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                      */
 /*-----------------------------------------------------------------*/
@@ -138,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)
+  if (!lbl)
     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;
+  do
+    {
+      /* Don't optimize jumps in a jump table; a more generic test */
+      if (currPl->ic && currPl->ic->op == JUMPTABLE)
+        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;
+      /* 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.                                                   */
@@ -226,7 +259,6 @@ FBYNAME (labelJTInRange)
   return TRUE;
 }
 
-
 /*-----------------------------------------------------------------*/
 /* labelIsReturnOnly - Check if label %5 is followed by RET        */
 /*-----------------------------------------------------------------*/
@@ -243,37 +275,126 @@ FBYNAME (labelIsReturnOnly)
     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     || !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 */
-                }
+  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 */
+    }
+  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 && 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      */
@@ -310,6 +431,41 @@ FBYNAME (okToRemoveSLOC)
   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                 */
@@ -421,7 +577,6 @@ FBYNAME (operandsNotSame6)
     return TRUE;
 }
 
-
 /*-----------------------------------------------------------------*/
 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
 /*-----------------------------------------------------------------*/
@@ -508,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:
 
@@ -522,30 +705,14 @@ FBYNAME (labelRefCount)
   int varNumber, expectedRefCount;
   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)
     {
       char *label = hTabItemWithKey (vars, varNumber);
 
       if (label)
         {
-          labelHashEntry *entry;
-
-          entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
+          labelHashEntry *entry = getLabelRef (label, head);
 
-          while (entry)
-            {
-              if (!strcmp (label, entry->name))
-                {
-                  break;
-                }
-              entry = hTabNextItemWK (labelHash);
-            }
           if (entry)
             {
 #if 0
@@ -580,7 +747,6 @@ FBYNAME (labelRefCount)
   return rc;
 }
 
-
 /* labelRefCountChange:
  * takes two parameters: a variable (bound to a label name)
  * and a signed int for changing the reference count.
@@ -657,7 +823,6 @@ FBYNAME (labelRefCountChange)
   return rc;
 }
 
-
 /* Within the context of the lines currPl through endPl, determine
 ** if the variable var contains a symbol that is volatile. Returns
 ** TRUE only if it is certain that this was not volatile (the symbol
@@ -722,22 +887,52 @@ 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;
+              }
           }
       }
   }
@@ -836,7 +1031,6 @@ FBYNAME (notVolatile)
 
   return TRUE;
 
-
 error:
   fprintf (stderr,
            "*** internal error: notVolatile peephole restriction"
@@ -844,7 +1038,6 @@ error:
   return FALSE;
 }
 
-
 /*------------------------------------------------------------------*/
 /* setFromConditionArgs - parse a peephole condition's arguments    */
 /* to produce a set of strings, one per argument. Variables %x will */
@@ -920,14 +1113,16 @@ operandBaseName (const char *op)
         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 of the condition's operands are */
+/* operandsNotRelated - returns true if the condition's operands are */
 /* not related (taking into account register name aliases). N-way    */
 /* comparison performed between all operands.                        */
 /*-------------------------------------------------------------------*/
@@ -966,7 +1161,6 @@ FBYNAME (operandsNotRelated)
   return TRUE;
 }
 
-
 /*-------------------------------------------------------------------*/
 /* operandsLiteral - returns true of the condition's operands are    */
 /* literals.                                                         */
@@ -999,97 +1193,93 @@ FBYNAME (operandsLiteral)
   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       */
 /*-----------------------------------------------------------------*/
-int
+static int
 callFuncByName (char *fname,
                 hTab * vars,
-                lineNode * currPl,
-                lineNode * endPl,
+                lineNode * currPl, /* first source line matched */
+                lineNode * endPl,  /* last source line matched */
                 lineNode * head)
 {
-  struct ftab
-  {
-    char *fname;
-    int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
-  }
-  ftab[] =
-  {
-    {
-      "labelInRange", labelInRange
-    }
-    ,
-    {
-      "labelJTInRange", labelJTInRange
-    }
-    ,
-    {
-      "operandsNotSame", operandsNotSame
-    }
-    ,
-    {
-      "operandsNotSame3", operandsNotSame3
-    }
-    ,
-    {
-      "operandsNotSame4", operandsNotSame4
-    }
-    ,
-    {
-      "operandsNotSame5", operandsNotSame5
-    }
-    ,
-    {
-      "operandsNotSame6", operandsNotSame6
-    }
-    ,
-    {
-      "operandsNotSame7", operandsNotSame7
-    }
-    ,
-    {
-      "operandsNotSame8", operandsNotSame8
-    }
-    ,
-    {
-      "24bitMode", flat24bitMode
-    }
-    ,
-    {
-      "xramMovcOption", xramMovcOption
-    }
-    ,
-    {
-      "labelRefCount", labelRefCount
-    }
-    ,
-    {
-      "portIsDS390", portIsDS390
-    },
-    {
-      "labelIsReturnOnly", labelIsReturnOnly
-    },
-    {
-      "okToRemoveSLOC", okToRemoveSLOC
-    },
-    {
-      "24bitModeAndPortDS390", flat24bitModeAndPortDS390
-    },
-    {
-      "notVolatile", notVolatile
-    },
-    {
-      "operandsNotRelated", operandsNotRelated
-    },
-    {
-      "operandsLiteral", operandsLiteral
-    },
-    {
-      "labelRefCountChange", labelRefCountChange
-    }
-  };
   int   i;
   char  *cmdCopy, *funcName, *funcArgs, *cmdTerm;
   char  c;
@@ -1122,9 +1312,18 @@ callFuncByName (char *fname,
       /* and there can be no additional conditions.             */
       if (c == '(')
         {
-          cmdTerm = funcArgs;
-          while ((c = *cmdTerm) && c != ')')
-            cmdTerm++;
+
+          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 == ')')
             {
@@ -1148,8 +1347,7 @@ callFuncByName (char *fname,
         {
           if (strcmp (ftab[i].fname, funcName) == 0)
             {
-              rc = (*ftab[i].func) (vars, currPl, endPl, head,
-                                    funcArgs);
+              rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
               break;
             }
         }
@@ -1177,14 +1375,11 @@ callFuncByName (char *fname,
 /* printLine - prints a line chain into a given file               */
 /*-----------------------------------------------------------------*/
 void
-printLine (lineNode * head, FILE * of)
+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)
     {
       if (head->ic!=last_ic)
@@ -1193,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, ";");
+          dbuf_append_char (oBuf, ';');
         }
-        fprintf (of, "\t%s\n", head->line);
+        dbuf_printf (oBuf, "\t%s\n", head->line);
       }
       head = head->next;
     }
@@ -1219,7 +1413,7 @@ 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,
@@ -1254,7 +1448,7 @@ newPeepRule (lineNode * match,
 /* newLineNode - creates a new peep line                           */
 /*-----------------------------------------------------------------*/
 lineNode *
-newLineNode (char *line)
+newLineNode (const char *line)
 {
   lineNode *pl;
 
@@ -1338,11 +1532,16 @@ getPeepLine (lineNode ** head, char **bpp)
 
       if (!isComment || (isComment && !options.noPeepComments))
         {
+          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);
         }
 
     }
@@ -1446,18 +1645,18 @@ top:
       newPeepRule (match, replace, lines, restart);
     }
   else
-    {  
+    {
       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)))
@@ -1472,7 +1671,7 @@ top:
           return;
         }
       newPeepRule (match, replace, NULL, restart);
-    }    
+    }
   goto top;
 
 }
@@ -1547,13 +1746,11 @@ bindVar (int key, char **s, hTab ** vtab)
 static bool
 matchLine (char *s, char *d, hTab ** vars)
 {
-
   if (!s || !(*s))
     return FALSE;
 
   while (*s && *d)
     {
-
       /* skip white space in both */
       while (ISCHARSPACE (*s))
         s++;
@@ -1573,8 +1770,7 @@ matchLine (char *s, char *d, hTab ** vars)
                   return FALSE;
             }
           else
-            /* variable not bound we need to
-               bind it */
+            /* variable not bound we need to bind it */
             bindVar (keyForVar (d + 1), &s, vars);
 
           /* in either case go past the variable */
@@ -1820,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;
@@ -1931,6 +2124,7 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
       else
         lhead = cl = newLineNode (lb);
       cl->isComment = pl->isComment;
+      cl->isLabel   = pl->isLabel;
     }
 
   /* add the comments if any to the head of list */
@@ -1983,7 +2177,8 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
  * and len will be it's length.
  */
 bool
-isLabelDefinition (const char *line, const char **start, int *len)
+isLabelDefinition (const char *line, const char **start, int *len,
+                   bool isPeepRule)
 {
   const char *cp = line;
 
@@ -2004,7 +2199,8 @@ isLabelDefinition (const char *line, const char **start, int *len)
 
   *start = cp;
 
-  while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_'))
+  while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
+         (isPeepRule && (*cp == '%')))
     {
       cp++;
     }
@@ -2053,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)
+      if (line->isLabel  ||
+          line->isInline)
         {
-          labelHashEntry *entry;
+          /* 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)));
+              entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
 
-          memcpy (entry->name, label, labelLen);
-          entry->name[labelLen] = 0;
-          entry->refCount = -1;
+              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++;
+              /* 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);
+              hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
+            }
         }
-      line = line->next;
     }
 
 
@@ -2145,7 +2346,7 @@ 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" */
@@ -2162,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;
@@ -2180,10 +2383,15 @@ peepHole (lineNode ** pls)
               /* 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);
 
@@ -2256,7 +2464,7 @@ readFileIntoBuffer (char *fname)
         }
     }
 
-  /* if some charaters left over */
+  /* if some characters left over */
   if (nch)
     {
       lb[nch] = '\0';