Create REG_BANK_[0-3] areas only for 8051 like ports.
[fw/sdcc] / src / SDCCpeeph.c
index aa923fbbe1ef100bed2c1270c71e3df5527851e5..070d902338c5dbcb5ac69baa2ca1199393f6d63f 100644 (file)
@@ -1,5 +1,5 @@
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
-  SDCCpeeph.c - The peep hole optimizer: for interpreting the 
+  SDCCpeeph.c - The peep hole optimizer: for interpreting the
                 peep hole rules
 
              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
                 peep hole rules
 
              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
    under the terms of the GNU General Public License as published by the
    Free Software Foundation; either version 2, or (at your option) any
    later version.
    under the terms of the GNU General Public License as published by the
    Free Software Foundation; either version 2, or (at your option) any
    later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-   
+
    In other words, you are welcome to use, share and improve this program.
    You are forbidden to forbid anyone else to use, share and improve
    In other words, you are welcome to use, share and improve this program.
    You are forbidden to forbid anyone else to use, share and improve
-   what you give them.   Help stamp out software-hoarding!  
+   what you give them.   Help stamp out software-hoarding!
 -------------------------------------------------------------------------*/
 
 #include "common.h"
 -------------------------------------------------------------------------*/
 
 #include "common.h"
-#include "SDCCpeeph.h"
 
 
-peepRule *rootRules = NULL;
-peepRule *currRule  = NULL;
+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;
+
+static struct
+{
+  allocTrace values;
+  allocTrace labels;
+} _G;
+
+static int hashSymbolName (const char *name);
+static void buildLabelRefCountHash (lineNode * head);
 
 static bool matchLine (char *, char *, hTab **);
 
 
 static bool matchLine (char *, char *, hTab **);
 
-#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head)
+#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head, \
+        const char *cmdLine)
+
+#if !OPT_DISABLE_PIC
+void  peepRules2pCode(peepRule *);
+#endif
 
 /*-----------------------------------------------------------------*/
 /* pcDistance - afinds a label back ward or forward                */
 /*-----------------------------------------------------------------*/
 
 /*-----------------------------------------------------------------*/
 /* pcDistance - afinds a label back ward or forward                */
 /*-----------------------------------------------------------------*/
-int pcDistance (lineNode *cpos, char *lbl, bool back)
+int 
+pcDistance (lineNode * cpos, char *lbl, bool back)
 {
 {
-    lineNode *pl = cpos;
-    char buff[MAX_PATTERN_LEN];
-    int dist = 0 ;
+  lineNode *pl = cpos;
+  char buff[MAX_PATTERN_LEN];
+  int dist = 0;
 
 
-    sprintf(buff,"%s:",lbl);
-    while (pl) {
+  sprintf (buff, "%s:", lbl);
+  while (pl)
+    {
 
 
-       if (pl->line && 
-           *pl->line != ';' &&
-           pl->line[strlen(pl->line)-1] != ':' &&
-           !pl->isDebug)
-            
-           dist ++;
+      if (pl->line &&
+         *pl->line != ';' &&
+         pl->line[strlen (pl->line) - 1] != ':' &&
+         !pl->isDebug)
 
 
-       if (strncmp(pl->line,buff,strlen(buff)) == 0)
-           return dist;
+       dist++;
 
 
-       if (back)
-           pl = pl->prev;
-       else
-           pl = pl->next;
+      if (strncmp (pl->line, buff, strlen (buff)) == 0)
+       return dist;
+
+      if (back)
+       pl = pl->prev;
+      else
+       pl = pl->next;
 
     }
 
     }
-    return 0;
+  return 0;
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
-/* labelInRange - will check to see if label %5 is within range    */
+/* flat24bitModeAndPortDS390 -                                            */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-FBYNAME(labelInRange)
+FBYNAME (flat24bitModeAndPortDS390)
 {
 {
-    /* assumes that %5 pattern variable has the label name */
-    char *lbl = hTabItemWithKey(vars,5);
-    int dist = 0 ;
+    return ((strcmp(port->target,"ds390") == 0) && 
+           (options.model == MODEL_FLAT24));
+}
 
 
-    if (!lbl)
-       return FALSE;
+/*-----------------------------------------------------------------*/
+/* portIsDS390 - return true if port is DS390                             */
+/*-----------------------------------------------------------------*/
+FBYNAME (portIsDS390)
+{
+    return (strcmp(port->target,"ds390") == 0);
+}
 
 
-    /* if the previous teo 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 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)) ;
-        
-    if (!dist || dist > 45)
-       return FALSE;
+/*-----------------------------------------------------------------*/
+/* flat24bitMode - will check to see if we are in flat24 mode      */
+/*-----------------------------------------------------------------*/
+FBYNAME (flat24bitMode)
+{
+  return (options.model == MODEL_FLAT24);
+}
 
 
-    return TRUE;
+/*-----------------------------------------------------------------*/
+/* xramMovcOption - check if using movc to read xram               */
+/*-----------------------------------------------------------------*/
+FBYNAME (xramMovcOption)
+{
+  return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
+}
+
+/*-----------------------------------------------------------------*/
+/* labelInRange - will check to see if label %5 is within range    */
+/*-----------------------------------------------------------------*/
+FBYNAME (labelInRange)
+{
+  /* assumes that %5 pattern variable has the label name */
+  char *lbl = hTabItemWithKey (vars, 5);
+  int dist = 0;
+
+  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;
+
+  /* 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));
+
+/*    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)
+    return FALSE;
+
+  return TRUE;
 }
 
 /*-----------------------------------------------------------------*/
 /* operandsNotSame - check if %1 & %2 are the same                 */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* operandsNotSame - check if %1 & %2 are the same                 */
 /*-----------------------------------------------------------------*/
-FBYNAME(operandsNotSame)
+FBYNAME (operandsNotSame)
 {
 {
-    char *op1 = hTabItemWithKey(vars,1);
-    char *op2 = hTabItemWithKey(vars,2);
+  char *op1 = hTabItemWithKey (vars, 1);
+  char *op2 = hTabItemWithKey (vars, 2);
 
 
-    if (strcmp(op1,op2) == 0)
-       return FALSE;
-    else
-       return TRUE;
+  if (strcmp (op1, op2) == 0)
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/* labelRefCount:
+
+ * takes two parameters: a variable (bound to a label name)
+ * and an expected reference count.
+ *
+ * Returns TRUE if that label is defined and referenced exactly
+ * the given number of times.
+ */
+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));
+
+         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
+
+             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;
 }
 
 /*-----------------------------------------------------------------*/
 /* callFuncByName - calls a function as defined in the table       */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* callFuncByName - calls a function as defined in the table       */
 /*-----------------------------------------------------------------*/
-int callFuncByName ( char *fname, 
-                    hTab *vars, 
-                    lineNode *currPl, 
-                    lineNode *head) 
+int 
+callFuncByName (char *fname,
+               hTab * vars,
+               lineNode * currPl,
+               lineNode * head)
 {
 {
-    struct ftab {
-       char *fname ;
-       int (*func)(hTab *,lineNode *,lineNode *) ; 
-    }  ftab[] = { 
-       {"labelInRange",   labelInRange },
-       {"operandsNotSame", operandsNotSame }
-    };
-    int i;
-
-    for ( i = 0 ; i < ((sizeof (ftab))/(sizeof(struct ftab))); i++) 
-       if (strcmp(ftab[i].fname,fname) == 0)
-           return (*ftab[i].func)(vars,currPl,head);
-    fprintf(stderr,"could not find named function in function table\n");
-    return TRUE;    
+  struct ftab
+  {
+    char *fname;
+    int (*func) (hTab *, lineNode *, lineNode *, const char *);
+  }
+  ftab[] =
+  {
+    {
+      "labelInRange", labelInRange
+    }
+    ,
+    {
+      "operandsNotSame", operandsNotSame
+    }
+    ,
+    {
+      "24bitMode", flat24bitMode
+    }
+    ,
+    {
+      "xramMovcOption", xramMovcOption
+    }
+    ,
+    {
+      "labelRefCount", labelRefCount
+    }
+    ,
+    {
+      "portIsDS390", portIsDS390
+    },
+    {
+      "24bitModeAndPortDS390", flat24bitModeAndPortDS390
+    }
+  };
+  int i;
+
+  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;
 }
 
 /*-----------------------------------------------------------------*/
 /* printLine - prints a line chain into a given file               */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* printLine - prints a line chain into a given file               */
 /*-----------------------------------------------------------------*/
-void printLine (lineNode *head, FILE *of)
+void 
+printLine (lineNode * head, FILE * of)
 {
 {
-    if (!of)
-       of = stdout ;
-
-    while (head) {
-       /* don't indent comments & labels */
-       if (head->line && 
-           ( *head->line == ';' ||
-             head->line[strlen(head->line)-1] == ':'))
-           fprintf(of,"%s\n",head->line);
-       else
-           fprintf(of,"\t%s\n",head->line);
-       head = head->next;
+  if (!of)
+    of = stdout;
+
+  while (head)
+    {
+      /* don't indent comments & labels */
+      if (head->line &&
+         (*head->line == ';' ||
+          head->line[strlen (head->line) - 1] == ':')) {
+       fprintf (of, "%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);
+      }
+      head = head->next;
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* newPeepRule - creates a new peeprule and attach it to the root  */
 /*-----------------------------------------------------------------*/
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* newPeepRule - creates a new peeprule and attach it to the root  */
 /*-----------------------------------------------------------------*/
-peepRule *newPeepRule (lineNode *match  , 
-                      lineNode *replace, 
-                      char *cond       ,
-                      int restart)
+peepRule *
+newPeepRule (lineNode * match,
+            lineNode * replace,
+            char *cond,
+            int restart)
 {
 {
-    peepRule *pr ;
-
-    ALLOC(pr,sizeof(peepRule));
-    pr->match = match;
-    pr->replace= replace;
-    pr->restart = restart;   
-    
-    if (cond && *cond) {
-       ALLOC_ATOMIC(pr->cond,strlen(cond)+1);
-       strcpy(pr->cond,cond);
-    } else
-       pr->cond = NULL ;
-
-    pr->vars = newHashTable(100);
-
-    /* if root is empty */
-    if (!rootRules) 
-       rootRules = currRule = pr;
-    else
-       currRule = currRule->next = pr;
-
-    return pr;
+  peepRule *pr;
+
+  pr = Safe_alloc ( sizeof (peepRule));
+  pr->match = match;
+  pr->replace = replace;
+  pr->restart = restart;
+
+  if (cond && *cond)
+    {
+      pr->cond = Safe_alloc ( strlen (cond) + 1);
+      strcpy (pr->cond, cond);
+    }
+  else
+    pr->cond = NULL;
+
+  pr->vars = newHashTable (100);
+
+  /* if root is empty */
+  if (!rootRules)
+    rootRules = currRule = pr;
+  else
+    currRule = currRule->next = pr;
+
+  return pr;
 }
 
 /*-----------------------------------------------------------------*/
 /* newLineNode - creates a new peep line                           */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* newLineNode - creates a new peep line                           */
 /*-----------------------------------------------------------------*/
-lineNode *newLineNode (char *line)
+lineNode *
+newLineNode (char *line)
 {
 {
-    lineNode *pl;
+  lineNode *pl;
 
 
-    ALLOC(pl,sizeof(lineNode));
-    ALLOC_ATOMIC(pl->line,strlen(line)+1);
-    strcpy(pl->line,line);   
-    return pl;
+  pl = Safe_alloc ( sizeof (lineNode));
+  pl->line = Safe_alloc ( strlen (line) + 1);
+  strcpy (pl->line, line);
+  return pl;
 }
 
 /*-----------------------------------------------------------------*/
 /* connectLine - connects two lines                                */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* connectLine - connects two lines                                */
 /*-----------------------------------------------------------------*/
-lineNode *connectLine (lineNode *pl1, lineNode *pl2)
+lineNode *
+connectLine (lineNode * pl1, lineNode * pl2)
 {
 {
-    if (!pl1 || !pl2) {
-       fprintf (stderr,"trying to connect null line\n");
-       return NULL ;
+  if (!pl1 || !pl2)
+    {
+      fprintf (stderr, "trying to connect null line\n");
+      return NULL;
     }
 
     }
 
-    pl2->prev = pl1;
-    pl1->next = pl2;
+  pl2->prev = pl1;
+  pl1->next = pl2;
 
 
-    return pl2;
+  return pl2;
 }
 
 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
 }
 
 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
@@ -228,483 +406,761 @@ lineNode *connectLine (lineNode *pl1, lineNode *pl2)
 /*-----------------------------------------------------------------*/
 /* getPeepLine - parses the peep lines                             */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* getPeepLine - parses the peep lines                             */
 /*-----------------------------------------------------------------*/
-static void getPeepLine (lineNode **head, char **bpp)
+static void 
+getPeepLine (lineNode ** head, char **bpp)
 {
 {
-    char lines[MAX_PATTERN_LEN];
-    char *lp;
-
-    lineNode *currL = NULL ;
-    char *bp = *bpp;
-    while (1) {
-       
-       if (!*bp) {
-           fprintf(stderr,"unexpected end of match pattern\n");
-           return ;
+  char lines[MAX_PATTERN_LEN];
+  char *lp;
+
+  lineNode *currL = NULL;
+  char *bp = *bpp;
+  while (1)
+    {
+
+      if (!*bp)
+       {
+         fprintf (stderr, "unexpected end of match pattern\n");
+         return;
        }
        }
-       
-       if (*bp == '\n') {
-           bp++ ;
-           while (isspace(*bp) ||
-                  *bp == '\n') bp++;
+
+      if (*bp == '\n')
+       {
+         bp++;
+         while (isspace (*bp) ||
+                *bp == '\n')
+           bp++;
        }
        }
-       
-       if (*bp == '}') {
-           bp++ ;
-           break;
+
+      if (*bp == '}')
+       {
+         bp++;
+         break;
        }
        }
-       
-       /* read till end of line */
-       lp = lines ;
-       while ((*bp != '\n' && *bp != '}' ) && *bp)
-           *lp++ = *bp++ ;
-       
-       *lp = '\0';
-       if (!currL) 
-           *head = currL = newLineNode (lines);
-       else 
-           currL = connectLine(currL,newLineNode(lines));
-    }  
-
-    *bpp = bp;
+
+      /* read till end of line */
+      lp = lines;
+      while ((*bp != '\n' && *bp != '}') && *bp)
+       *lp++ = *bp++;
+
+      *lp = '\0';
+      if (!currL)
+       *head = currL = newLineNode (lines);
+      else
+       currL = connectLine (currL, newLineNode (lines));
+    }
+
+  *bpp = bp;
 }
 
 /*-----------------------------------------------------------------*/
 /* readRules - reads the rules from a string buffer                */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* readRules - reads the rules from a string buffer                */
 /*-----------------------------------------------------------------*/
-static void readRules (char *bp)
+static void 
+readRules (char *bp)
 {
 {
-    char restart = 0 ;
-    char lines[MAX_PATTERN_LEN];
-    char *lp;
-    lineNode *match;
-    lineNode *replace;
-    lineNode *currL = NULL;
-    
-    if (!bp)
-       return;
- top:
-    restart = 0;
-    /* look for the token "replace" that is the
-       start of a rule */
-    while (*bp && strncmp(bp,"replace",7)) bp++;
-    
-    /* if not found */
-    if (!*bp)        
-       return ;    
-
-    /* then look for either "restart" or '{' */
-    while (strncmp(bp,"restart",7) &&
-          *bp != '{'  && bp ) bp++ ;
-
-    /* not found */
-    if (!*bp) {
-       fprintf(stderr,"expected 'restart' or '{'\n");
-       return ;
-    }
-
-    /* if brace */
-    if (*bp == '{')
-       bp++ ;
-    else { /* must be restart */
-       restart++;
-       bp += strlen("restart");
-       /* look for '{' */
-       EXPECT_CHR(bp,'{',"expected '{'\n");    
-       bp++;
+  char restart = 0;
+  char lines[MAX_PATTERN_LEN];
+  char *lp;
+  lineNode *match;
+  lineNode *replace;
+  lineNode *currL = NULL;
+
+  if (!bp)
+    return;
+top:
+  restart = 0;
+  /* look for the token "replace" that is the
+     start of a rule */
+  while (*bp && strncmp (bp, "replace", 7))
+    bp++;
+
+  /* if not found */
+  if (!*bp)
+    return;
+
+  /* then look for either "restart" or '{' */
+  while (strncmp (bp, "restart", 7) &&
+        *bp != '{' && bp)
+    bp++;
+
+  /* not found */
+  if (!*bp)
+    {
+      fprintf (stderr, "expected 'restart' or '{'\n");
+      return;
     }
 
     }
 
-    /* skip thru all the blank space */
-    SKIP_SPACE(bp,"unexpected end of rule\n");
-
-    match = replace = currL = NULL ;
-    /* we are the start of a rule */
-    getPeepLine(&match, &bp);
-
-    /* now look for by */
-    EXPECT_STR(bp,"by","expected 'by'\n");
-
-    /* then look for a '{' */
-    EXPECT_CHR(bp,'{',"expected '{'\n");
-    bp++ ;
-    
-    SKIP_SPACE(bp,"unexpected end of rule\n");
-    getPeepLine (&replace, &bp);
-   
-    /* look for a 'if' */    
-    while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
-    
-    if (strncmp(bp,"if",2) == 0) {
-       bp += 2;
-       while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
-       if (!*bp) {
-           fprintf(stderr,"expected condition name\n");
-           return;
+  /* if brace */
+  if (*bp == '{')
+    bp++;
+  else
+    {                          /* must be restart */
+      restart++;
+      bp += strlen ("restart");
+      /* look for '{' */
+      EXPECT_CHR (bp, '{', "expected '{'\n");
+      bp++;
+    }
+
+  /* skip thru all the blank space */
+  SKIP_SPACE (bp, "unexpected end of rule\n");
+
+  match = replace = currL = NULL;
+  /* we are the start of a rule */
+  getPeepLine (&match, &bp);
+
+  /* now look for by */
+  EXPECT_STR (bp, "by", "expected 'by'\n");
+
+  /* then look for a '{' */
+  EXPECT_CHR (bp, '{', "expected '{'\n");
+  bp++;
+
+  SKIP_SPACE (bp, "unexpected end of rule\n");
+  getPeepLine (&replace, &bp);
+
+  /* look for a 'if' */
+  while ((isspace (*bp) || *bp == '\n') && *bp)
+    bp++;
+
+  if (strncmp (bp, "if", 2) == 0)
+    {
+      bp += 2;
+      while ((isspace (*bp) || *bp == '\n') && *bp)
+       bp++;
+      if (!*bp)
+       {
+         fprintf (stderr, "expected condition name\n");
+         return;
        }
        }
-           
-       /* look for the condition */
-       lp = lines;
-       while (isalnum(*bp)) {
-           *lp++ = *bp++;
+
+      /* look for the condition */
+      lp = lines;
+      while (*bp && (*bp != '\n'))
+       {
+         *lp++ = *bp++;
        }
        }
-       *lp = '\0';
-       
-       newPeepRule(match,replace,lines,restart);
-    } else
-       newPeepRule(match,replace,NULL,restart);
-    goto top;
+      *lp = '\0';
+
+      newPeepRule (match, replace, lines, restart);
+    }
+  else
+    newPeepRule (match, replace, NULL, restart);
+  goto top;
 
 }
 
 /*-----------------------------------------------------------------*/
 /* keyForVar - returns the numeric key for a var                   */
 /*-----------------------------------------------------------------*/
 
 }
 
 /*-----------------------------------------------------------------*/
 /* keyForVar - returns the numeric key for a var                   */
 /*-----------------------------------------------------------------*/
-static int keyForVar (char *d) 
+static int 
+keyForVar (char *d)
 {
 {
-    int i = 0;
+  int i = 0;
 
 
-    while (isdigit(*d)) {
-       i *= 10 ;
-       i += (*d++ - '0') ;
+  while (isdigit (*d))
+    {
+      i *= 10;
+      i += (*d++ - '0');
     }
 
     }
 
-    return i;
+  return i;
 }
 
 /*-----------------------------------------------------------------*/
 /* bindVar - binds a value to a variable in the given hashtable    */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* bindVar - binds a value to a variable in the given hashtable    */
 /*-----------------------------------------------------------------*/
-static void bindVar (int key, char **s, hTab **vtab)
+static void 
+bindVar (int key, char **s, hTab ** vtab)
 {
 {
-    char vval[MAX_PATTERN_LEN];
-    char *vvx;
-    char *vv = vval;
-    
-    /* first get the value of the variable */
-    vvx = *s;
-    /* the value is ended by a ',' or space or newline or null */
-    while (*vvx           && 
-          *vvx != ','    && 
-          !isspace(*vvx) && 
-          *vvx != '\n'   &&
-          *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--;
+  char vval[MAX_PATTERN_LEN];
+  char *vvx;
+  char *vv = vval;
+
+  /* first get the value of the variable */
+  vvx = *s;
+  /* the value is ended by a ',' or space or newline or null or ) */
+  while (*vvx &&
+        *vvx != ',' &&
+        !isspace (*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--;
            }
            }
-       } else
-           *vv++ = *vvx++ ;
-    }
-    *s = vvx ;
-    *vv = '\0';
-    /* got value */
-    ALLOC_ATOMIC(vvx,strlen(vval)+1);
-    strcpy(vvx,vval);
-    hTabAddItem(vtab,key,vvx);
-    
+         // include the trailing ')'
+         *vv++ = *vvx++;
+       }
+      else
+       *vv++ = *vvx++;
+    }
+  *s = vvx;
+  *vv = '\0';
+  /* got value */
+  vvx = traceAlloc (&_G.values, Safe_alloc(strlen (vval) + 1));
+  strcpy (vvx, vval);
+
+  hTabAddItem (vtab, key, vvx);
 }
 
 /*-----------------------------------------------------------------*/
 /* matchLine - matches one line                                    */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* matchLine - matches one line                                    */
 /*-----------------------------------------------------------------*/
-static bool matchLine (char *s, char *d, hTab **vars)
-{    
-
-    if (!s || !(*s))
-       return FALSE;
+static bool 
+matchLine (char *s, char *d, hTab ** vars)
+{
 
 
-    while (*s && *d) {
-
-       /* skip white space in both */
-       while (isspace(*s)) s++;
-       while (isspace(*d)) d++;
-       
-       /* if the destination is a var */
-       if (*d == '%' && isdigit(*(d+1))) {         
-           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++;
+  if (!s || !(*s))
+    return FALSE;
+
+  while (*s && *d)
+    {
+
+      /* skip white space in both */
+      while (isspace (*s))
+       s++;
+      while (isspace (*d))
+       d++;
+
+      /* if the destination is a var */
+      if (*d == '%' && isdigit (*(d + 1)))
+       {
+         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++;
        }
 
        }
 
-       /* they should be an exact match other wise */
-       if (*s && *d) {
-           while (isspace(*s))s++;
-           while (isspace(*d))d++;
-           if (*s++ != *d++)
-               return FALSE;
+      /* they should be an exact match other wise */
+      if (*s && *d)
+       {
+         while (isspace (*s))
+           s++;
+         while (isspace (*d))
+           d++;
+         if (*s++ != *d++)
+           return FALSE;
        }
 
     }
 
        }
 
     }
 
-    /* get rid of the trailing spaces 
-       in both source & destination */
-    if (*s) 
-       while (isspace(*s)) s++;
+  /* get rid of the trailing spaces
+     in both source & destination */
+  if (*s)
+    while (isspace (*s))
+      s++;
 
 
-    if (*d)
-       while (isspace(*d)) d++;
+  if (*d)
+    while (isspace (*d))
+      d++;
 
 
-    /* after all this if only one of them
-       has something left over then no match */
-    if (*s || *d)
-       return FALSE ;
-    
-    return TRUE ;
+  /* after all this if only one of them
+     has something left over then no match */
+  if (*s || *d)
+    return FALSE;
+
+  return TRUE;
 }
 
 /*-----------------------------------------------------------------*/
 /* matchRule - matches a all the rule lines                        */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* matchRule - matches a all the rule lines                        */
 /*-----------------------------------------------------------------*/
-static bool matchRule (lineNode *pl, 
-                      lineNode **mtail, 
-                      peepRule *pr, 
-                      lineNode *head)
+static bool 
+matchRule (lineNode * pl,
+          lineNode ** mtail,
+          peepRule * pr,
+          lineNode * head)
 {
 {
-    lineNode *spl ; /* source pl */
-    lineNode *rpl ; /* rule peep line */
-    
-    hTabClearAll(pr->vars); 
+  lineNode *spl;               /* source pl */
+  lineNode *rpl;               /* rule peep line */
+
 /*     setToNull((void **) &pr->vars);    */
 /*     pr->vars = newHashTable(100); */
 
 /*     setToNull((void **) &pr->vars);    */
 /*     pr->vars = newHashTable(100); */
 
-    /* for all the lines defined in the rule */
-    rpl = pr->match;
-    spl = pl ; 
-    while (spl && rpl) {
-
-       /* if the source line starts with a ';' then
-          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;
+  /* for all the lines defined in the rule */
+  rpl = pr->match;
+  spl = pl;
+  while (spl && rpl)
+    {
+
+      /* if the source line starts with a ';' then
+         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;
        }
 
        }
 
-       if (!matchLine(spl->line,rpl->line,&pr->vars))
-           return FALSE ;
-       
-       rpl = rpl->next ;
-       if (rpl)
-           spl = spl->next ;
-    }
-
-    /* if rules ended */
-    if (!rpl) {
-       /* if this rule has additional conditions */
-       if ( pr->cond) {
-           if (callFuncByName (pr->cond, pr->vars,pl,head) ) {
-               *mtail = spl;
-               return TRUE;  
-           } else
-               return FALSE;
-       } else {
-           *mtail = spl;
-           return TRUE;
+      if (!matchLine (spl->line, rpl->line, &pr->vars))
+       return FALSE;
+
+      rpl = rpl->next;
+      if (rpl)
+       spl = spl->next;
+    }
+
+  /* if rules ended */
+  if (!rpl)
+    {
+      /* if this rule has additional conditions */
+      if (pr->cond)
+       {
+         if (callFuncByName (pr->cond, pr->vars, pl, head))
+           {
+             *mtail = spl;
+             return TRUE;
+           }
+         else
+           return FALSE;
+       }
+      else
+       {
+         *mtail = spl;
+         return TRUE;
        }
     }
        }
     }
-    else
-       return FALSE;
+  else
+    return FALSE;
 }
 
 /*-----------------------------------------------------------------*/
 /* replaceRule - does replacement of a matching pattern            */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* replaceRule - does replacement of a matching pattern            */
 /*-----------------------------------------------------------------*/
-static void replaceRule (lineNode **shead, lineNode *stail, peepRule *pr)
+static void 
+replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
 {
 {
-    lineNode *cl = NULL;
-    lineNode *pl = NULL , *lhead = NULL;    
-    char lb[MAX_PATTERN_LEN];
-    char *lbp;
-    lineNode *comment = NULL;
-
-    /* collect all the comment lines in the source */
-    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;
+  lineNode *cl = NULL;
+  lineNode *pl = NULL, *lhead = NULL;
+  /* a long function name and long variable name can evaluate to
+     4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
+  char lb[MAX_PATTERN_LEN*4];
+  char *lbp;
+  lineNode *comment = NULL;
+
+  /* collect all the comment lines in the source */
+  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;
        }
     }
        }
     }
-    cl = NULL;
-    
-    /* for all the lines in the replacement pattern do */
-    for ( pl = pr->replace ; pl ; pl = pl->next ) {
-       char *v;
-       char *l;
-       lbp = lb;
-
-       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;
+  cl = NULL;
+
+  /* for all the lines in the replacement pattern do */
+  for (pl = pr->replace; pl; pl = pl->next)
+    {
+      char *v;
+      char *l;
+      lbp = lb;
+
+      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++;
+             while (*v) {
+               *lbp++ = *v++;
+             }
+             l++;
+             while (isdigit (*l)) {
                l++;
                l++;
-               while (isdigit(*l)) l++;
-               continue ;
+             }
+             continue;
            }
            }
-           *lbp++ = *l++;
+         *lbp++ = *l++;
        }
 
        }
 
-       *lbp = '\0';
-       if (cl)
-           cl = connectLine(cl,newLineNode(lb));
-       else
-           lhead = cl = newLineNode(lb);
-    }
-
-    /* add the comments if any to the head of list */
-    if (comment) {
-       lineNode *lc = comment;
-       while (lc->next) lc = lc->next;
-       lc->next = lhead;
-       if (lhead)
-           lhead->prev = lc;
-       lhead = comment;
-    }
-
-    /* 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;
-    } else 
-       *shead = lhead;
-    /* now for the tail */
-    if (stail && stail->next) {
-       stail->next->prev = cl;
-       if (cl)
-           cl->next = stail->next;
-    }    
+      *lbp = '\0';
+      if (cl)
+       cl = connectLine (cl, newLineNode (lb));
+      else
+       lhead = cl = newLineNode (lb);
+    }
+
+  /* add the comments if any to the head of list */
+  if (comment)
+    {
+      lineNode *lc = comment;
+      while (lc->next)
+       lc = lc->next;
+      lc->next = lhead;
+      if (lhead)
+       lhead->prev = lc;
+      lhead = comment;
+    }
+
+  /* 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;
+    }
+  else
+    *shead = lhead;
+  /* now for the tail */
+  if (stail && stail->next)
+    {
+      stail->next->prev = cl;
+      if (cl)
+       cl->next = stail->next;
+    }
 }
 
 }
 
+/* Returns TRUE if this line is a label definition.
+
+ * 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)
+{
+  const char *cp = line;
+
+  /* This line is a label if if consists of:
+   * [optional whitespace] followed by identifier chars
+   * (alnum | $ | _ ) followed by a colon.
+   */
+
+  while (*cp && isspace (*cp))
+    {
+      cp++;
+    }
+
+  if (!*cp)
+    {
+      return FALSE;
+    }
+
+  *start = cp;
+
+  while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
+    {
+      cp++;
+    }
+
+  if ((cp == *start) || (*cp != ':'))
+    {
+      return FALSE;
+    }
+
+  *len = (cp - (*start));
+  return TRUE;
+}
+
+/* Quick & dirty string hash function. */
+static int 
+hashSymbolName (const char *name)
+{
+  int hash = 0;
+
+  while (*name)
+    {
+      hash = (hash << 6) ^ *name;
+      name++;
+    }
+
+  if (hash < 0)
+    {
+      hash = -hash;
+    }
+
+  return hash % HTAB_SIZE;
+}
+
+/* Build a hash of all labels in the passed set of lines
+ * and how many times they are referenced.
+ */
+static void 
+buildLabelRefCountHash (lineNode * head)
+{
+  lineNode *line;
+  const char *label;
+  int labelLen;
+  int i;
+
+  assert (labelHash == NULL);
+  labelHash = newHashTable (HTAB_SIZE);
+
+  /* First pass: locate all the labels. */
+  line = head;
+
+  while (line)
+    {
+      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;
+
+         hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
+       }
+      line = line->next;
+    }
+
+
+  /* Second pass: for each line, note all the referenced labels. */
+  /* This is ugly, O(N^2) stuff. Optimizations welcome... */
+  line = 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);
+           }
+       }
+      line = line->next;
+    }
+
+#if 0
+  /* Spew the contents of the table. Debugging fun only. */
+  for (i = 0; i < HTAB_SIZE; i++)
+    {
+      labelHashEntry *thisEntry;
+
+      thisEntry = hTabFirstItemWK (labelHash, i);
+
+      while (thisEntry)
+       {
+         fprintf (stderr, "label: %s ref %d\n",
+                  thisEntry->name, thisEntry->refCount);
+         thisEntry = hTabNextItemWK (labelHash);
+       }
+    }
+#endif
+}
+
+/* How does this work?
+   peepHole
+    For each rule,
+     For each line,
+      Try to match
+      If it matches,
+       replace and restart.
+
+    matchRule
+     matchLine
+
+  Where is stuff allocated?
+  
+*/
+
 /*-----------------------------------------------------------------*/
 /* peepHole - matches & substitutes rules                          */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* peepHole - matches & substitutes rules                          */
 /*-----------------------------------------------------------------*/
-void peepHole (lineNode **pls )
+void 
+peepHole (lineNode ** pls)
 {
 {
-    lineNode *spl ; 
-    peepRule *pr ;
-    lineNode *mtail = NULL;
-
- top:   
-    /* for all rules */
-    for (pr = rootRules ; pr ; pr = pr->next ) {
-       for (spl = *pls ; spl ; spl = spl->next ) {
-                   
-           /* if inline assembler then no peep hole */
-           if (spl->isInline)
-               continue ;
-
-           mtail = NULL ;          
-               
-           /* if it matches */
-           if (matchRule (spl,&mtail,pr, *pls)) {
-               
-               /* then replace */ 
-               if (spl == *pls)
-                   replaceRule(pls, mtail, pr);
-               else
-                   replaceRule (&spl, mtail,pr);
-               
-               /* if it was the start then replace
-                  the start */
-               
-               /* if restart rule type then
-                  start at the top again */
-               if (pr->restart)
-                   goto top;
-           }
-       }
+  lineNode *spl;
+  peepRule *pr;
+  lineNode *mtail = NULL;
+  bool restart;
+
+#if !OPT_DISABLE_PIC
+  /* The PIC port uses a different peep hole optimizer based on "pCode" */
+  if (TARGET_IS_PIC)
+    return;
+#endif
+
+  assert(labelHash == NULL);
+
+  do
+    {
+      restart = FALSE;
+
+      /* for all rules */
+      for (pr = rootRules; pr; pr = pr->next)
+        {
+          for (spl = *pls; spl; spl = spl->next)
+            {
+              /* if inline assembler then no peep hole */
+              if (spl->isInline)
+                continue;
+              
+              mtail = NULL;
+
+              /* Tidy up any data stored in the hTab */
+              
+              /* if it matches */
+              if (matchRule (spl, &mtail, pr, *pls))
+                {
+                  
+                  /* then replace */
+                  if (spl == *pls)
+                    replaceRule (pls, mtail, pr);
+                  else
+                    replaceRule (&spl, mtail, pr);
+                  
+                  /* if restart rule type then
+                     start at the top again */
+                  if (pr->restart)
+                    {
+                      restart = TRUE;
+                    }
+                }
+              
+              if (pr->vars)
+                {
+                  hTabDeleteAll (pr->vars);
+                  Safe_free (pr->vars);
+                  pr->vars = NULL;
+                }
+              
+              freeTrace (&_G.values);
+            }
+        }
+    } while (restart == TRUE);
+
+  if (labelHash)
+    {
+      hTabDeleteAll (labelHash);
+      freeTrace (&_G.labels);
     }
     }
+  labelHash = NULL;
 }
 
 
 /*-----------------------------------------------------------------*/
 /* readFileIntoBuffer - reads a file into a string buffer          */
 /*-----------------------------------------------------------------*/
 }
 
 
 /*-----------------------------------------------------------------*/
 /* readFileIntoBuffer - reads a file into a string buffer          */
 /*-----------------------------------------------------------------*/
-static char *readFileIntoBuffer (char *fname)
+static char *
+readFileIntoBuffer (char *fname)
 {
 {
-    FILE *f;
-    char *rs = NULL;       
-    int nch = 0 ;
-    int ch;
-    char lb[MAX_PATTERN_LEN];
-
-    if (!(f = fopen(fname,"r"))) {
-       fprintf(stderr,"cannot open peep rule file\n");
-       return NULL;
-    }
-
-    while ((ch = fgetc(f)) != EOF) {
-       lb[nch++] = ch;
-
-       /* if we maxed out our local buffer */
-       if (nch >= (MAX_PATTERN_LEN - 2)) {
-           lb[nch] = '\0';
-           /* copy it into allocated buffer */
-           if (rs) {
-               rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
-               strcat(rs,lb);
-           } else {
-               ALLOC_ATOMIC(rs,strlen(lb)+1);
-               strcpy(rs,lb);
+  FILE *f;
+  char *rs = NULL;
+  int nch = 0;
+  int ch;
+  char lb[MAX_PATTERN_LEN];
+
+  if (!(f = fopen (fname, "r")))
+    {
+      fprintf (stderr, "cannot open peep rule file\n");
+      return NULL;
+    }
+
+  while ((ch = fgetc (f)) != EOF)
+    {
+      lb[nch++] = ch;
+
+      /* 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);
+             strcat (rs, lb);
            }
            }
-           nch = 0 ;           
+         else
+           {
+             rs = Safe_alloc ( strlen (lb) + 1);
+             strcpy (rs, lb);
+           }
+         nch = 0;
        }
     }
 
        }
     }
 
-    /* if some charaters left over */
-    if (nch) {
-       lb[nch] = '\0';
-       /* copy it into allocated buffer */
-       if (rs) {
-           rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
-           strcat(rs,lb);
-       } else {
-           ALLOC_ATOMIC(rs,strlen(lb)+1);
-           strcpy(rs,lb);
+  /* if some charaters left over */
+  if (nch)
+    {
+      lb[nch] = '\0';
+      /* copy it into allocated buffer */
+      if (rs)
+       {
+         rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
+         strcat (rs, lb);
+       }
+      else
+       {
+         rs = Safe_alloc ( strlen (lb) + 1);
+         strcpy (rs, lb);
        }
     }
        }
     }
-    return rs;
+  return rs;
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
-/* initPeepHole - initiaises the peep hole optimizer stuff         */
+/* initPeepHole - initialises the peep hole optimizer stuff        */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-void initPeepHole ()
+void 
+initPeepHole ()
 {
 {
-    char *s;
+  char *s;
 
 
-    /* read in the default rules */
-    readRules(port->peep.default_rules);
+  /* read in the default rules */
+  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);
+  /* if we have any additional file read it too */
+  if (options.peep_file)
+    {
+      readRules (s = readFileIntoBuffer (options.peep_file));
+      setToNull ((void **) &s);
     }
     }
+
+
+#if !OPT_DISABLE_PIC
+  /* Convert the peep rules into pcode.
+     NOTE: this is only support in the PIC port (at the moment)
+  */
+  if (TARGET_IS_PIC) {
+    peepRules2pCode(rootRules);
+  }
+#endif
+
 }
 }