PIC16 - Applied patch from Vangelis Rokas. Many fixes for the PIC16 port.
[fw/sdcc] / src / SDCCpeeph.c
index 070d902338c5dbcb5ac69baa2ca1199393f6d63f..9e7d672e09f1cb376d034e18c0f5bc2002ab671d 100644 (file)
@@ -49,16 +49,125 @@ static void buildLabelRefCountHash (lineNode * head);
 
 static bool matchLine (char *, char *, hTab **);
 
-#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head, \
-        const char *cmdLine)
+#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
+       lineNode *head, const char *cmdLine)
 
-#if !OPT_DISABLE_PIC
+#if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
 void  peepRules2pCode(peepRule *);
 #endif
 
 /*-----------------------------------------------------------------*/
 /* pcDistance - afinds a label back ward or forward                */
 /*-----------------------------------------------------------------*/
+int
+mcs51_instruction_size(const char *inst)
+{
+       char *op, op1[256], op2[256];
+       int opsize;
+       const char *p;
+
+       while (*inst && isspace(*inst)) inst++;
+
+       #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
+       if (ISINST("lcall")) return 3;
+       if (ISINST("ret")) return 1;
+       if (ISINST("ljmp")) return 3;
+       if (ISINST("sjmp")) return 2;
+       if (ISINST("rlc")) return 1;
+       if (ISINST("rrc")) return 1;
+       if (ISINST("rl")) return 1;
+       if (ISINST("rr")) return 1;
+       if (ISINST("swap")) return 1;
+       if (ISINST("movx")) return 1;
+       if (ISINST("movc")) return 1;
+       if (ISINST("push")) return 2;
+       if (ISINST("pop")) return 2;
+       if (ISINST("jc")) return 2;
+       if (ISINST("jnc")) return 2;
+       if (ISINST("jb")) return 3;
+       if (ISINST("jnb")) return 3;
+       if (ISINST("jbc")) return 3;
+       if (ISINST("jmp")) return 1;    // always jmp @a+dptr
+       if (ISINST("jz")) return 2;
+       if (ISINST("jnz")) return 2;
+       if (ISINST("cjne")) return 3;
+       if (ISINST("mul")) return 1;
+       if (ISINST("div")) return 1;
+       if (ISINST("da")) return 1;
+       if (ISINST("xchd")) return 1;
+       if (ISINST("reti")) return 1;
+       if (ISINST("nop")) return 1;
+       if (ISINST("acall")) return 1;
+       if (ISINST("ajmp")) return 2;
+
+       p = inst;
+       while (*p && isalnum(*p)) p++;
+       for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
+               if (!isspace(*p)) *op++ = *p, opsize++;
+       }
+       *op = '\0';
+       if (*p == ',') p++;
+       for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
+               if (!isspace(*p)) *op++ = *p, opsize++;
+       }
+       *op = '\0';
+
+       #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
+       #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
+       #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
+       #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
+
+       if (ISINST("mov")) {
+               if (IS_C(op1) || IS_C(op2)) return 2;
+               if (IS_A(op1)) {
+                       if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+                       return 2;
+               }
+               if (IS_Rn(op1) || IS_atRi(op1)) {
+                       if (IS_A(op2)) return 1;
+                       return 2;
+               }
+               if (strcmp(op1, "dptr") == 0) return 3;
+               if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
+               return 3;
+       }
+       if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
+               if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+               return 2;
+       }
+       if (ISINST("inc") || ISINST("dec")) {
+               if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
+               if (strcmp(op1, "dptr") == 0) return 1;
+               return 2;
+       }
+       if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
+               if (IS_C(op1)) return 2;
+               if (IS_A(op1)) {
+                       if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+                       return 2;
+               } else {
+                       if (IS_A(op2)) return 2;
+                       return 3;
+               }
+       }
+       if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
+               if (IS_A(op1) || IS_C(op1)) return 1;
+               return 2;
+       }
+       if (ISINST("djnz")) {
+               if (IS_Rn(op1)) return 2;
+               return 3;
+       }
+
+       if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
+               /* ignore ar0 = 0x00 type definitions */
+               return 0;
+       }
+
+       fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
+       return 3;
+}
+
 int 
 pcDistance (lineNode * cpos, char *lbl, bool back)
 {
@@ -66,16 +175,20 @@ pcDistance (lineNode * cpos, char *lbl, bool back)
   char buff[MAX_PATTERN_LEN];
   int dist = 0;
 
-  sprintf (buff, "%s:", lbl);
+  SNPRINTF (buff, sizeof(buff), "%s:", lbl);
   while (pl)
     {
 
       if (pl->line &&
          *pl->line != ';' &&
          pl->line[strlen (pl->line) - 1] != ':' &&
-         !pl->isDebug)
-
-       dist++;
+         !pl->isDebug) {
+               if (strcmp(port->target,"mcs51") == 0) {
+                       dist += mcs51_instruction_size(pl->line);
+               } else {
+                       dist += 3;
+               }
+       }
 
       if (strncmp (pl->line, buff, strlen (buff)) == 0)
        return dist;
@@ -122,6 +235,11 @@ FBYNAME (xramMovcOption)
   return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
 }
 
+
+
+
+
+
 /*-----------------------------------------------------------------*/
 /* labelInRange - will check to see if label %5 is within range    */
 /*-----------------------------------------------------------------*/
@@ -150,17 +268,86 @@ FBYNAME (labelInRange)
   dist = (pcDistance (currPl, lbl, TRUE) +
          pcDistance (currPl, lbl, FALSE));
 
-/*    if (!dist || dist > 45) has produced wrong sjmp */
-  /* 07-Sep-2000 Michael Schmitt */
-  /* FIX for Peephole 132 */
-  /* switch with lots of case can lead to a sjmp with a distance */
-  /* out of the range for sjmp */
-  if (!dist || dist > 43)
+/*    changed to 127, now that pcDistance return actual number of bytes */
+  if (!dist || dist > 127)
     return FALSE;
 
   return TRUE;
 }
 
+/*-----------------------------------------------------------------*/
+/* labelIsReturnOnly - Check if label %5 is followed by RET        */
+/*-----------------------------------------------------------------*/
+FBYNAME (labelIsReturnOnly)
+{
+  /* assumes that %5 pattern variable has the label name */
+  const char *label, *p;
+  const lineNode *pl;
+  int len;
+
+  label = hTabItemWithKey (vars, 5);
+  if (!label) return FALSE;
+  len = strlen(label);
+
+  for(pl = currPl; pl; pl = pl->next) {
+       if (pl->line && !pl->isDebug &&
+         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 */
+  pl = pl->next;
+  if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
+  p = pl->line;
+  for (p = pl->line; *p && isspace(*p); p++)
+         ;
+  if (strcmp(p, "ret") == 0) return TRUE;
+  return FALSE;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* okToRemoveSLOC - Check if label %1 is a SLOC and not other      */
+/* usage of it in the code depends on a value from this section    */
+/*-----------------------------------------------------------------*/
+FBYNAME (okToRemoveSLOC)
+{
+  const lineNode *pl;
+  const char *sloc, *p;
+  int dummy1, dummy2, dummy3;
+
+  /* assumes that %1 as the SLOC name */
+  sloc = hTabItemWithKey (vars, 1);
+  if (sloc == NULL) return FALSE;
+  p = strstr(sloc, "sloc");
+  if (p == NULL) return FALSE;
+  p += 4;
+  if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
+  /*TODO: ultra-paranoid: get funtion name from "head" and check that */
+  /* the sloc name begins with that.  Probably not really necessary */
+
+  /* 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;
+  }
+  /* 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;
+  }
+  return TRUE; /* safe for a peephole to remove it :) */
+}
+
+
 /*-----------------------------------------------------------------*/
 /* operandsNotSame - check if %1 & %2 are the same                 */
 /*-----------------------------------------------------------------*/
@@ -175,6 +362,190 @@ FBYNAME (operandsNotSame)
     return TRUE;
 }
 
+/*-----------------------------------------------------------------*/
+/* operandsNotSame3- check if any pair of %1,%2,%3 are the same    */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame3)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op2, op3) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame4)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+  char *op4 = hTabItemWithKey (vars, 4);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op1, op4) == 0) ||
+       (strcmp (op2, op3) == 0) ||
+       (strcmp (op2, op4) == 0) ||
+       (strcmp (op3, op4) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame5)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+  char *op4 = hTabItemWithKey (vars, 4);
+  char *op5 = hTabItemWithKey (vars, 5);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op1, op4) == 0) ||
+       (strcmp (op1, op5) == 0) ||
+       (strcmp (op2, op3) == 0) ||
+       (strcmp (op2, op4) == 0) ||
+       (strcmp (op2, op5) == 0) ||
+       (strcmp (op3, op4) == 0) ||
+       (strcmp (op3, op5) == 0) ||
+       (strcmp (op4, op5) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame6)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+  char *op4 = hTabItemWithKey (vars, 4);
+  char *op5 = hTabItemWithKey (vars, 5);
+  char *op6 = hTabItemWithKey (vars, 6);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op1, op4) == 0) ||
+       (strcmp (op1, op5) == 0) ||
+       (strcmp (op1, op6) == 0) ||
+       (strcmp (op2, op3) == 0) ||
+       (strcmp (op2, op4) == 0) ||
+       (strcmp (op2, op5) == 0) ||
+       (strcmp (op2, op6) == 0) ||
+       (strcmp (op3, op4) == 0) ||
+       (strcmp (op3, op5) == 0) ||
+       (strcmp (op3, op6) == 0) ||
+       (strcmp (op4, op5) == 0) ||
+       (strcmp (op4, op6) == 0) ||
+       (strcmp (op5, op6) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame7)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+  char *op4 = hTabItemWithKey (vars, 4);
+  char *op5 = hTabItemWithKey (vars, 5);
+  char *op6 = hTabItemWithKey (vars, 6);
+  char *op7 = hTabItemWithKey (vars, 7);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op1, op4) == 0) ||
+       (strcmp (op1, op5) == 0) ||
+       (strcmp (op1, op6) == 0) ||
+       (strcmp (op1, op7) == 0) ||
+       (strcmp (op2, op3) == 0) ||
+       (strcmp (op2, op4) == 0) ||
+       (strcmp (op2, op5) == 0) ||
+       (strcmp (op2, op6) == 0) ||
+       (strcmp (op2, op7) == 0) ||
+       (strcmp (op3, op4) == 0) ||
+       (strcmp (op3, op5) == 0) ||
+       (strcmp (op3, op6) == 0) ||
+       (strcmp (op3, op7) == 0) ||
+       (strcmp (op4, op5) == 0) ||
+       (strcmp (op4, op6) == 0) ||
+       (strcmp (op4, op7) == 0) ||
+       (strcmp (op5, op6) == 0) ||
+       (strcmp (op5, op7) == 0) ||
+       (strcmp (op6, op7) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
+/*-----------------------------------------------------------------*/
+FBYNAME (operandsNotSame8)
+{
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
+  char *op3 = hTabItemWithKey (vars, 3);
+  char *op4 = hTabItemWithKey (vars, 4);
+  char *op5 = hTabItemWithKey (vars, 5);
+  char *op6 = hTabItemWithKey (vars, 6);
+  char *op7 = hTabItemWithKey (vars, 7);
+  char *op8 = hTabItemWithKey (vars, 8);
+
+  if ( (strcmp (op1, op2) == 0) ||
+       (strcmp (op1, op3) == 0) ||
+       (strcmp (op1, op4) == 0) ||
+       (strcmp (op1, op5) == 0) ||
+       (strcmp (op1, op6) == 0) ||
+       (strcmp (op1, op7) == 0) ||
+       (strcmp (op1, op8) == 0) ||
+       (strcmp (op2, op3) == 0) ||
+       (strcmp (op2, op4) == 0) ||
+       (strcmp (op2, op5) == 0) ||
+       (strcmp (op2, op6) == 0) ||
+       (strcmp (op2, op7) == 0) ||
+       (strcmp (op2, op8) == 0) ||
+       (strcmp (op3, op4) == 0) ||
+       (strcmp (op3, op5) == 0) ||
+       (strcmp (op3, op6) == 0) ||
+       (strcmp (op3, op7) == 0) ||
+       (strcmp (op3, op8) == 0) ||
+       (strcmp (op4, op5) == 0) ||
+       (strcmp (op4, op6) == 0) ||
+       (strcmp (op4, op7) == 0) ||
+       (strcmp (op4, op8) == 0) ||
+       (strcmp (op5, op6) == 0) ||
+       (strcmp (op5, op7) == 0) ||
+       (strcmp (op5, op8) == 0) ||
+       (strcmp (op6, op7) == 0) ||
+       (strcmp (op6, op8) == 0) ||
+       (strcmp (op7, op8) == 0) )
+    return FALSE;
+  else
+    return TRUE;
+}
+
+
 /* labelRefCount:
 
  * takes two parameters: a variable (bound to a label name)
@@ -253,12 +624,13 @@ int
 callFuncByName (char *fname,
                hTab * vars,
                lineNode * currPl,
+               lineNode * endPl,
                lineNode * head)
 {
   struct ftab
   {
     char *fname;
-    int (*func) (hTab *, lineNode *, lineNode *, const char *);
+    int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
   }
   ftab[] =
   {
@@ -270,6 +642,30 @@ callFuncByName (char *fname,
       "operandsNotSame", operandsNotSame
     }
     ,
+    {
+      "operandsNotSame3", operandsNotSame3
+    }
+    ,
+    {
+      "operandsNotSame4", operandsNotSame4
+    }
+    ,
+    {
+      "operandsNotSame5", operandsNotSame5
+    }
+    ,
+    {
+      "operandsNotSame6", operandsNotSame6
+    }
+    ,
+    {
+      "operandsNotSame7", operandsNotSame7
+    }
+    ,
+    {
+      "operandsNotSame8", operandsNotSame8
+    }
+    ,    
     {
       "24bitMode", flat24bitMode
     }
@@ -285,20 +681,50 @@ callFuncByName (char *fname,
     {
       "portIsDS390", portIsDS390
     },
+    {
+      "labelIsReturnOnly", labelIsReturnOnly
+    },
+    {
+      "okToRemoveSLOC", okToRemoveSLOC
+    },
     {
       "24bitModeAndPortDS390", flat24bitModeAndPortDS390
     }
   };
-  int i;
+  int  i;
+  char  *cmdCopy, *funcName, *funcArgs;
+  int  rc = -1;
+    
+  /* 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, "");
 
-  for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
-    if (strncmp (ftab[i].fname, fname, strlen (ftab[i].fname)) == 0)
-      {
-       return (*ftab[i].func) (vars, currPl, head,
-                               fname + strlen (ftab[i].fname));
-      }
-  fprintf (stderr, "could not find named function in function table\n");
-  return TRUE;
+    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);
+       }
+    }
+    
+    Safe_free(cmdCopy);
+    
+    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;
+    }
+    
+  return rc;
 }
 
 /*-----------------------------------------------------------------*/
@@ -346,8 +772,7 @@ newPeepRule (lineNode * match,
 
   if (cond && *cond)
     {
-      pr->cond = Safe_alloc ( strlen (cond) + 1);
-      strcpy (pr->cond, cond);
+      pr->cond = Safe_strdup (cond);
     }
   else
     pr->cond = NULL;
@@ -372,8 +797,7 @@ newLineNode (char *line)
   lineNode *pl;
 
   pl = Safe_alloc ( sizeof (lineNode));
-  pl->line = Safe_alloc ( strlen (line) + 1);
-  strcpy (pl->line, line);
+  pl->line = Safe_strdup (line);
   return pl;
 }
 
@@ -609,8 +1033,7 @@ bindVar (int key, char **s, hTab ** vtab)
   *s = vvx;
   *vv = '\0';
   /* got value */
-  vvx = traceAlloc (&_G.values, Safe_alloc(strlen (vval) + 1));
-  strcpy (vvx, vval);
+  vvx = traceAlloc (&_G.values, Safe_strdup(vval));
 
   hTabAddItem (vtab, key, vvx);
 }
@@ -733,7 +1156,7 @@ matchRule (lineNode * pl,
       /* if this rule has additional conditions */
       if (pr->cond)
        {
-         if (callFuncByName (pr->cond, pr->vars, pl, head))
+         if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
            {
              *mtail = spl;
              return TRUE;
@@ -836,8 +1259,7 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
       (*shead)->prev->next = lhead;
       lhead->prev = (*shead)->prev;
     }
-  else
-    *shead = lhead;
+  *shead = lhead;
   /* now for the tail */
   if (stail && stail->next)
     {
@@ -1011,9 +1433,9 @@ peepHole (lineNode ** pls)
   lineNode *mtail = NULL;
   bool restart;
 
-#if !OPT_DISABLE_PIC
+#if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
   /* The PIC port uses a different peep hole optimizer based on "pCode" */
-  if (TARGET_IS_PIC)
+  if (TARGET_IS_PIC || TARGET_IS_PIC16)
     return;
 #endif
 
@@ -1105,12 +1527,11 @@ readFileIntoBuffer (char *fname)
          if (rs)
            {
              rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
-             strcat (rs, lb);
+             strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
            }
          else
            {
-             rs = Safe_alloc ( strlen (lb) + 1);
-             strcpy (rs, lb);
+             rs = Safe_strdup (lb);
            }
          nch = 0;
        }
@@ -1124,12 +1545,11 @@ readFileIntoBuffer (char *fname)
       if (rs)
        {
          rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
-         strcat (rs, lb);
+         strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
        }
       else
        {
-         rs = Safe_alloc ( strlen (lb) + 1);
-         strcpy (rs, lb);
+         rs = Safe_strdup (lb);
        }
     }
   return rs;
@@ -1154,11 +1574,11 @@ initPeepHole ()
     }
 
 
-#if !OPT_DISABLE_PIC
+#if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
   /* Convert the peep rules into pcode.
      NOTE: this is only support in the PIC port (at the moment)
   */
-  if (TARGET_IS_PIC) {
+  if (TARGET_IS_PIC || TARGET_IS_PIC16) {
     peepRules2pCode(rootRules);
   }
 #endif