pCode peep is fully working for the PIC port.
[fw/sdcc] / src / SDCCpeeph.c
1 /*-------------------------------------------------------------------------
2   SDCCpeeph.c - The peep hole optimizer: for interpreting the
3                 peep hole rules
4
5              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
6
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 2, or (at your option) any
10    later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21    In other words, you are welcome to use, share and improve this program.
22    You are forbidden to forbid anyone else to use, share and improve
23    what you give them.   Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
25
26 #include "common.h"
27 #include "SDCCpeeph.h"
28 #include "newalloc.h"
29
30 peepRule *rootRules = NULL;
31 peepRule *currRule = NULL;
32
33 #define HTAB_SIZE 53
34 typedef struct
35   {
36     char name[SDCC_NAME_MAX + 1];
37     int refCount;
38   }
39 labelHashEntry;
40
41 hTab *labelHash = NULL;
42
43 static int hashSymbolName (const char *name);
44 static void buildLabelRefCountHash (lineNode * head);
45
46 static bool matchLine (char *, char *, hTab **);
47
48 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head, \
49         const char *cmdLine)
50
51 #if !OPT_DISABLE_PIC
52 void  peepRules2pCode(peepRule *);
53 #endif
54
55 /*-----------------------------------------------------------------*/
56 /* pcDistance - afinds a label back ward or forward                */
57 /*-----------------------------------------------------------------*/
58 int 
59 pcDistance (lineNode * cpos, char *lbl, bool back)
60 {
61   lineNode *pl = cpos;
62   char buff[MAX_PATTERN_LEN];
63   int dist = 0;
64
65   sprintf (buff, "%s:", lbl);
66   while (pl)
67     {
68
69       if (pl->line &&
70           *pl->line != ';' &&
71           pl->line[strlen (pl->line) - 1] != ':' &&
72           !pl->isDebug)
73
74         dist++;
75
76       if (strncmp (pl->line, buff, strlen (buff)) == 0)
77         return dist;
78
79       if (back)
80         pl = pl->prev;
81       else
82         pl = pl->next;
83
84     }
85   return 0;
86 }
87
88 /*-----------------------------------------------------------------*/
89 /* flat24bitMode - will check to see if we are in flat24 mode      */
90 /*-----------------------------------------------------------------*/
91 FBYNAME (flat24bitMode)
92 {
93   return (options.model == MODEL_FLAT24);
94 }
95
96 /*-----------------------------------------------------------------*/
97 /* labelInRange - will check to see if label %5 is within range    */
98 /*-----------------------------------------------------------------*/
99 FBYNAME (labelInRange)
100 {
101   /* assumes that %5 pattern variable has the label name */
102   char *lbl = hTabItemWithKey (vars, 5);
103   int dist = 0;
104
105   if (!lbl)
106     return FALSE;
107
108   /* if the previous teo instructions are "ljmp"s then don't
109      do it since it can be part of a jump table */
110   if (currPl->prev && currPl->prev->prev &&
111       strstr (currPl->prev->line, "ljmp") &&
112       strstr (currPl->prev->prev->line, "ljmp"))
113     return FALSE;
114
115   /* calculate the label distance : the jump for reladdr can be
116      +/- 127 bytes, here Iam assuming that an average 8051
117      instruction is 2 bytes long, so if the label is more than
118      63 intructions away, the label is considered out of range
119      for a relative jump. we could get more precise this will
120      suffice for now since it catches > 90% cases */
121   dist = (pcDistance (currPl, lbl, TRUE) +
122           pcDistance (currPl, lbl, FALSE));
123
124 /*    if (!dist || dist > 45) has produced wrong sjmp */
125   /* 07-Sep-2000 Michael Schmitt */
126   /* FIX for Peephole 132 */
127   /* switch with lots of case can lead to a sjmp with a distance */
128   /* out of the range for sjmp */
129   if (!dist || dist > 43)
130     return FALSE;
131
132   return TRUE;
133 }
134
135 /*-----------------------------------------------------------------*/
136 /* operandsNotSame - check if %1 & %2 are the same                 */
137 /*-----------------------------------------------------------------*/
138 FBYNAME (operandsNotSame)
139 {
140   char *op1 = hTabItemWithKey (vars, 1);
141   char *op2 = hTabItemWithKey (vars, 2);
142
143   if (strcmp (op1, op2) == 0)
144     return FALSE;
145   else
146     return TRUE;
147 }
148
149 /* labelRefCount:
150
151  * takes two parameters: a variable (bound to a label name)
152  * and an expected reference count.
153  *
154  * Returns TRUE if that label is defined and referenced exactly
155  * the given number of times.
156  */
157 FBYNAME (labelRefCount)
158 {
159   int varNumber, expectedRefCount;
160   bool rc = FALSE;
161
162   /* If we don't have the label hash table yet, build it. */
163   if (!labelHash)
164     {
165       buildLabelRefCountHash (head);
166     }
167
168   if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
169     {
170       char *label = hTabItemWithKey (vars, varNumber);
171
172       if (label)
173         {
174           labelHashEntry *entry;
175
176           entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
177
178           while (entry)
179             {
180               if (!strcmp (label, entry->name))
181                 {
182                   break;
183                 }
184               entry = hTabNextItemWK (labelHash);
185             }
186           if (entry)
187             {
188 #if 0
189               /* debug spew. */
190               fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
191                        label, entry->refCount, expectedRefCount);
192 #endif
193
194               rc = (expectedRefCount == entry->refCount);
195             }
196           else
197             {
198               fprintf (stderr, "*** internal error: no label has entry for"
199                        " %s in labelRefCount peephole.\n",
200                        label);
201             }
202         }
203       else
204         {
205           fprintf (stderr, "*** internal error: var %d not bound"
206                    " in peephole labelRefCount rule.\n",
207                    varNumber);
208         }
209
210     }
211   else
212     {
213       fprintf (stderr,
214                "*** internal error: labelRefCount peephole restriction"
215                " malformed: %s\n", cmdLine);
216     }
217   return rc;
218 }
219
220 /*-----------------------------------------------------------------*/
221 /* callFuncByName - calls a function as defined in the table       */
222 /*-----------------------------------------------------------------*/
223 int 
224 callFuncByName (char *fname,
225                 hTab * vars,
226                 lineNode * currPl,
227                 lineNode * head)
228 {
229   struct ftab
230   {
231     char *fname;
232     int (*func) (hTab *, lineNode *, lineNode *, const char *);
233   }
234   ftab[] =
235   {
236     {
237       "labelInRange", labelInRange
238     }
239     ,
240     {
241       "operandsNotSame", operandsNotSame
242     }
243     ,
244     {
245       "24bitMode", flat24bitMode
246     }
247     ,
248     {
249       "labelRefCount", labelRefCount
250     }
251     ,
252   };
253   int i;
254
255   for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
256     if (strncmp (ftab[i].fname, fname, strlen (ftab[i].fname)) == 0)
257       {
258         return (*ftab[i].func) (vars, currPl, head,
259                                 fname + strlen (ftab[i].fname));
260       }
261   fprintf (stderr, "could not find named function in function table\n");
262   return TRUE;
263 }
264
265 /*-----------------------------------------------------------------*/
266 /* printLine - prints a line chain into a given file               */
267 /*-----------------------------------------------------------------*/
268 void 
269 printLine (lineNode * head, FILE * of)
270 {
271   if (!of)
272     of = stdout;
273
274   while (head)
275     {
276       /* don't indent comments & labels */
277       if (head->line &&
278           (*head->line == ';' ||
279            head->line[strlen (head->line) - 1] == ':')) {
280         fprintf (of, "%s\n", head->line);
281       } else {
282         if (head->isInline && *head->line=='#') {
283           // comment out preprocessor directives in inline asm
284           fprintf (of, ";");
285         }
286         fprintf (of, "\t%s\n", head->line);
287       }
288       head = head->next;
289     }
290 }
291
292 /*-----------------------------------------------------------------*/
293 /* newPeepRule - creates a new peeprule and attach it to the root  */
294 /*-----------------------------------------------------------------*/
295 peepRule *
296 newPeepRule (lineNode * match,
297              lineNode * replace,
298              char *cond,
299              int restart)
300 {
301   peepRule *pr;
302
303   pr = Safe_calloc (1, sizeof (peepRule));
304   pr->match = match;
305   pr->replace = replace;
306   pr->restart = restart;
307
308   if (cond && *cond)
309     {
310       pr->cond = Safe_calloc (1, strlen (cond) + 1);
311       strcpy (pr->cond, cond);
312     }
313   else
314     pr->cond = NULL;
315
316   pr->vars = newHashTable (100);
317
318   /* if root is empty */
319   if (!rootRules)
320     rootRules = currRule = pr;
321   else
322     currRule = currRule->next = pr;
323
324   return pr;
325 }
326
327 /*-----------------------------------------------------------------*/
328 /* newLineNode - creates a new peep line                           */
329 /*-----------------------------------------------------------------*/
330 lineNode *
331 newLineNode (char *line)
332 {
333   lineNode *pl;
334
335   pl = Safe_calloc (1, sizeof (lineNode));
336   pl->line = Safe_calloc (1, strlen (line) + 1);
337   strcpy (pl->line, line);
338   return pl;
339 }
340
341 /*-----------------------------------------------------------------*/
342 /* connectLine - connects two lines                                */
343 /*-----------------------------------------------------------------*/
344 lineNode *
345 connectLine (lineNode * pl1, lineNode * pl2)
346 {
347   if (!pl1 || !pl2)
348     {
349       fprintf (stderr, "trying to connect null line\n");
350       return NULL;
351     }
352
353   pl2->prev = pl1;
354   pl1->next = pl2;
355
356   return pl2;
357 }
358
359 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
360                          if (!*x) { fprintf(stderr,y); return ; } }
361
362 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
363                            if (!*x) { fprintf(stderr,z); return ; } }
364 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
365                            if (!*x) { fprintf(stderr,z); return ; } }
366
367 /*-----------------------------------------------------------------*/
368 /* getPeepLine - parses the peep lines                             */
369 /*-----------------------------------------------------------------*/
370 static void 
371 getPeepLine (lineNode ** head, char **bpp)
372 {
373   char lines[MAX_PATTERN_LEN];
374   char *lp;
375
376   lineNode *currL = NULL;
377   char *bp = *bpp;
378   while (1)
379     {
380
381       if (!*bp)
382         {
383           fprintf (stderr, "unexpected end of match pattern\n");
384           return;
385         }
386
387       if (*bp == '\n')
388         {
389           bp++;
390           while (isspace (*bp) ||
391                  *bp == '\n')
392             bp++;
393         }
394
395       if (*bp == '}')
396         {
397           bp++;
398           break;
399         }
400
401       /* read till end of line */
402       lp = lines;
403       while ((*bp != '\n' && *bp != '}') && *bp)
404         *lp++ = *bp++;
405
406       *lp = '\0';
407       if (!currL)
408         *head = currL = newLineNode (lines);
409       else
410         currL = connectLine (currL, newLineNode (lines));
411     }
412
413   *bpp = bp;
414 }
415
416 /*-----------------------------------------------------------------*/
417 /* readRules - reads the rules from a string buffer                */
418 /*-----------------------------------------------------------------*/
419 static void 
420 readRules (char *bp)
421 {
422   char restart = 0;
423   char lines[MAX_PATTERN_LEN];
424   char *lp;
425   lineNode *match;
426   lineNode *replace;
427   lineNode *currL = NULL;
428
429   if (!bp)
430     return;
431 top:
432   restart = 0;
433   /* look for the token "replace" that is the
434      start of a rule */
435   while (*bp && strncmp (bp, "replace", 7))
436     bp++;
437
438   /* if not found */
439   if (!*bp)
440     return;
441
442   /* then look for either "restart" or '{' */
443   while (strncmp (bp, "restart", 7) &&
444          *bp != '{' && bp)
445     bp++;
446
447   /* not found */
448   if (!*bp)
449     {
450       fprintf (stderr, "expected 'restart' or '{'\n");
451       return;
452     }
453
454   /* if brace */
455   if (*bp == '{')
456     bp++;
457   else
458     {                           /* must be restart */
459       restart++;
460       bp += strlen ("restart");
461       /* look for '{' */
462       EXPECT_CHR (bp, '{', "expected '{'\n");
463       bp++;
464     }
465
466   /* skip thru all the blank space */
467   SKIP_SPACE (bp, "unexpected end of rule\n");
468
469   match = replace = currL = NULL;
470   /* we are the start of a rule */
471   getPeepLine (&match, &bp);
472
473   /* now look for by */
474   EXPECT_STR (bp, "by", "expected 'by'\n");
475
476   /* then look for a '{' */
477   EXPECT_CHR (bp, '{', "expected '{'\n");
478   bp++;
479
480   SKIP_SPACE (bp, "unexpected end of rule\n");
481   getPeepLine (&replace, &bp);
482
483   /* look for a 'if' */
484   while ((isspace (*bp) || *bp == '\n') && *bp)
485     bp++;
486
487   if (strncmp (bp, "if", 2) == 0)
488     {
489       bp += 2;
490       while ((isspace (*bp) || *bp == '\n') && *bp)
491         bp++;
492       if (!*bp)
493         {
494           fprintf (stderr, "expected condition name\n");
495           return;
496         }
497
498       /* look for the condition */
499       lp = lines;
500       while (*bp && (*bp != '\n'))
501         {
502           *lp++ = *bp++;
503         }
504       *lp = '\0';
505
506       newPeepRule (match, replace, lines, restart);
507     }
508   else
509     newPeepRule (match, replace, NULL, restart);
510   goto top;
511
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* keyForVar - returns the numeric key for a var                   */
516 /*-----------------------------------------------------------------*/
517 static int 
518 keyForVar (char *d)
519 {
520   int i = 0;
521
522   while (isdigit (*d))
523     {
524       i *= 10;
525       i += (*d++ - '0');
526     }
527
528   return i;
529 }
530
531 /*-----------------------------------------------------------------*/
532 /* bindVar - binds a value to a variable in the given hashtable    */
533 /*-----------------------------------------------------------------*/
534 static void 
535 bindVar (int key, char **s, hTab ** vtab)
536 {
537   char vval[MAX_PATTERN_LEN];
538   char *vvx;
539   char *vv = vval;
540
541   /* first get the value of the variable */
542   vvx = *s;
543   /* the value is ended by a ',' or space or newline or null or ) */
544   while (*vvx &&
545          *vvx != ',' &&
546          !isspace (*vvx) &&
547          *vvx != '\n' &&
548          *vvx != ':' &&
549          *vvx != ')')
550     {
551       char ubb = 0;
552       /* if we find a '(' then we need to balance it */
553       if (*vvx == '(')
554         {
555           ubb++;
556           while (ubb)
557             {
558               *vv++ = *vvx++;
559               if (*vvx == '(')
560                 ubb++;
561               if (*vvx == ')')
562                 ubb--;
563             }
564         }
565       else
566         *vv++ = *vvx++;
567     }
568   *s = vvx;
569   *vv = '\0';
570   /* got value */
571   vvx = Safe_calloc (1, strlen (vval) + 1);
572   strcpy (vvx, vval);
573   hTabAddItem (vtab, key, vvx);
574
575 }
576
577 /*-----------------------------------------------------------------*/
578 /* matchLine - matches one line                                    */
579 /*-----------------------------------------------------------------*/
580 static bool 
581 matchLine (char *s, char *d, hTab ** vars)
582 {
583
584   if (!s || !(*s))
585     return FALSE;
586
587   while (*s && *d)
588     {
589
590       /* skip white space in both */
591       while (isspace (*s))
592         s++;
593       while (isspace (*d))
594         d++;
595
596       /* if the destination is a var */
597       if (*d == '%' && isdigit (*(d + 1)))
598         {
599           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
600           /* if the variable is already bound
601              then it MUST match with dest */
602           if (v)
603             {
604               while (*v)
605                 if (*v++ != *s++)
606                   return FALSE;
607             }
608           else
609             /* variable not bound we need to
610                bind it */
611             bindVar (keyForVar (d + 1), &s, vars);
612
613           /* in either case go past the variable */
614           d++;
615           while (isdigit (*d))
616             d++;
617         }
618
619       /* they should be an exact match other wise */
620       if (*s && *d)
621         {
622           while (isspace (*s))
623             s++;
624           while (isspace (*d))
625             d++;
626           if (*s++ != *d++)
627             return FALSE;
628         }
629
630     }
631
632   /* get rid of the trailing spaces
633      in both source & destination */
634   if (*s)
635     while (isspace (*s))
636       s++;
637
638   if (*d)
639     while (isspace (*d))
640       d++;
641
642   /* after all this if only one of them
643      has something left over then no match */
644   if (*s || *d)
645     return FALSE;
646
647   return TRUE;
648 }
649
650 /*-----------------------------------------------------------------*/
651 /* matchRule - matches a all the rule lines                        */
652 /*-----------------------------------------------------------------*/
653 static bool 
654 matchRule (lineNode * pl,
655            lineNode ** mtail,
656            peepRule * pr,
657            lineNode * head)
658 {
659   lineNode *spl;                /* source pl */
660   lineNode *rpl;                /* rule peep line */
661
662   hTabClearAll (pr->vars);
663 /*     setToNull((void **) &pr->vars);    */
664 /*     pr->vars = newHashTable(100); */
665
666   /* for all the lines defined in the rule */
667   rpl = pr->match;
668   spl = pl;
669   while (spl && rpl)
670     {
671
672       /* if the source line starts with a ';' then
673          comment line don't process or the source line
674          contains == . debugger information skip it */
675       if (spl->line &&
676           (*spl->line == ';' || spl->isDebug))
677         {
678           spl = spl->next;
679           continue;
680         }
681
682       if (!matchLine (spl->line, rpl->line, &pr->vars))
683         return FALSE;
684
685       rpl = rpl->next;
686       if (rpl)
687         spl = spl->next;
688     }
689
690   /* if rules ended */
691   if (!rpl)
692     {
693       /* if this rule has additional conditions */
694       if (pr->cond)
695         {
696           if (callFuncByName (pr->cond, pr->vars, pl, head))
697             {
698               *mtail = spl;
699               return TRUE;
700             }
701           else
702             return FALSE;
703         }
704       else
705         {
706           *mtail = spl;
707           return TRUE;
708         }
709     }
710   else
711     return FALSE;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* replaceRule - does replacement of a matching pattern            */
716 /*-----------------------------------------------------------------*/
717 static void 
718 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
719 {
720   lineNode *cl = NULL;
721   lineNode *pl = NULL, *lhead = NULL;
722   /* a long function name and long variable name can evaluate to
723      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
724   char lb[MAX_PATTERN_LEN*4];
725   char *lbp;
726   lineNode *comment = NULL;
727
728   /* collect all the comment lines in the source */
729   for (cl = *shead; cl != stail; cl = cl->next)
730     {
731       if (cl->line && (*cl->line == ';' || cl->isDebug))
732         {
733           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
734                 (comment = newLineNode (cl->line)));
735           pl->isDebug = cl->isDebug;
736         }
737     }
738   cl = NULL;
739
740   /* for all the lines in the replacement pattern do */
741   for (pl = pr->replace; pl; pl = pl->next)
742     {
743       char *v;
744       char *l;
745       lbp = lb;
746
747       l = pl->line;
748       while (*l)
749         {
750           /* if the line contains a variable */
751           if (*l == '%' && isdigit (*(l + 1)))
752             {
753               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
754               if (!v)
755                 {
756                   fprintf (stderr, "used unbound variable in replacement\n");
757                   l++;
758                   continue;
759                 }
760               while (*v) {
761                 *lbp++ = *v++;
762               }
763               l++;
764               while (isdigit (*l)) {
765                 l++;
766               }
767               continue;
768             }
769           *lbp++ = *l++;
770         }
771
772       *lbp = '\0';
773       if (cl)
774         cl = connectLine (cl, newLineNode (lb));
775       else
776         lhead = cl = newLineNode (lb);
777     }
778
779   /* add the comments if any to the head of list */
780   if (comment)
781     {
782       lineNode *lc = comment;
783       while (lc->next)
784         lc = lc->next;
785       lc->next = lhead;
786       if (lhead)
787         lhead->prev = lc;
788       lhead = comment;
789     }
790
791   /* now we need to connect / replace the original chain */
792   /* if there is a prev then change it */
793   if ((*shead)->prev)
794     {
795       (*shead)->prev->next = lhead;
796       lhead->prev = (*shead)->prev;
797     }
798   else
799     *shead = lhead;
800   /* now for the tail */
801   if (stail && stail->next)
802     {
803       stail->next->prev = cl;
804       if (cl)
805         cl->next = stail->next;
806     }
807 }
808
809 /* Returns TRUE if this line is a label definition.
810
811  * If so, start will point to the start of the label name,
812  * and len will be it's length.
813  */
814 bool 
815 isLabelDefinition (const char *line, const char **start, int *len)
816 {
817   const char *cp = line;
818
819   /* This line is a label if if consists of:
820    * [optional whitespace] followed by identifier chars
821    * (alnum | $ | _ ) followed by a colon.
822    */
823
824   while (*cp && isspace (*cp))
825     {
826       cp++;
827     }
828
829   if (!*cp)
830     {
831       return FALSE;
832     }
833
834   *start = cp;
835
836   while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
837     {
838       cp++;
839     }
840
841   if ((cp == *start) || (*cp != ':'))
842     {
843       return FALSE;
844     }
845
846   *len = (cp - (*start));
847   return TRUE;
848 }
849
850 /* Quick & dirty string hash function. */
851 static int 
852 hashSymbolName (const char *name)
853 {
854   int hash = 0;
855
856   while (*name)
857     {
858       hash = (hash << 6) ^ *name;
859       name++;
860     }
861
862   if (hash < 0)
863     {
864       hash = -hash;
865     }
866
867   return hash % HTAB_SIZE;
868 }
869
870 /* Build a hash of all labels in the passed set of lines
871  * and how many times they are referenced.
872  */
873 static void 
874 buildLabelRefCountHash (lineNode * head)
875 {
876   lineNode *line;
877   const char *label;
878   int labelLen;
879   int i;
880
881   assert (labelHash == NULL);
882   labelHash = newHashTable (HTAB_SIZE);
883
884   /* First pass: locate all the labels. */
885   line = head;
886
887   while (line)
888     {
889       if (isLabelDefinition (line->line, &label, &labelLen)
890           && labelLen <= SDCC_NAME_MAX)
891         {
892           labelHashEntry *entry;
893
894           entry = Safe_calloc (1, sizeof (labelHashEntry));
895
896           memcpy (entry->name, label, labelLen);
897           entry->name[labelLen] = 0;
898           entry->refCount = -1;
899
900           hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
901         }
902       line = line->next;
903     }
904
905
906   /* Second pass: for each line, note all the referenced labels. */
907   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
908   line = head;
909   while (line)
910     {
911       for (i = 0; i < HTAB_SIZE; i++)
912         {
913           labelHashEntry *thisEntry;
914
915           thisEntry = hTabFirstItemWK (labelHash, i);
916
917           while (thisEntry)
918             {
919               if (strstr (line->line, thisEntry->name))
920                 {
921                   thisEntry->refCount++;
922                 }
923               thisEntry = hTabNextItemWK (labelHash);
924             }
925         }
926       line = line->next;
927     }
928
929 #if 0
930   /* Spew the contents of the table. Debugging fun only. */
931   for (i = 0; i < HTAB_SIZE; i++)
932     {
933       labelHashEntry *thisEntry;
934
935       thisEntry = hTabFirstItemWK (labelHash, i);
936
937       while (thisEntry)
938         {
939           fprintf (stderr, "label: %s ref %d\n",
940                    thisEntry->name, thisEntry->refCount);
941           thisEntry = hTabNextItemWK (labelHash);
942         }
943     }
944 #endif
945 }
946
947 /*-----------------------------------------------------------------*/
948 /* peepHole - matches & substitutes rules                          */
949 /*-----------------------------------------------------------------*/
950 void 
951 peepHole (lineNode ** pls)
952 {
953   lineNode *spl;
954   peepRule *pr;
955   lineNode *mtail = NULL;
956
957   if (labelHash)
958     {
959       hTabDeleteAll (labelHash);
960     }
961   labelHash = NULL;
962
963 top:
964   /* for all rules */
965   for (pr = rootRules; pr; pr = pr->next)
966     {
967
968       for (spl = *pls; spl; spl = spl->next)
969         {
970           /* if inline assembler then no peep hole */
971           if (spl->isInline)
972             continue;
973
974           mtail = NULL;
975
976           /* if it matches */
977           if (matchRule (spl, &mtail, pr, *pls))
978             {
979
980               /* then replace */
981               if (spl == *pls)
982                 replaceRule (pls, mtail, pr);
983               else
984                 replaceRule (&spl, mtail, pr);
985
986               /* if restart rule type then
987                  start at the top again */
988               if (pr->restart)
989                 goto top;
990             }
991         }
992     }
993 }
994
995
996 /*-----------------------------------------------------------------*/
997 /* readFileIntoBuffer - reads a file into a string buffer          */
998 /*-----------------------------------------------------------------*/
999 static char *
1000 readFileIntoBuffer (char *fname)
1001 {
1002   FILE *f;
1003   char *rs = NULL;
1004   int nch = 0;
1005   int ch;
1006   char lb[MAX_PATTERN_LEN];
1007
1008   if (!(f = fopen (fname, "r")))
1009     {
1010       fprintf (stderr, "cannot open peep rule file\n");
1011       return NULL;
1012     }
1013
1014   while ((ch = fgetc (f)) != EOF)
1015     {
1016       lb[nch++] = ch;
1017
1018       /* if we maxed out our local buffer */
1019       if (nch >= (MAX_PATTERN_LEN - 2))
1020         {
1021           lb[nch] = '\0';
1022           /* copy it into allocated buffer */
1023           if (rs)
1024             {
1025               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1026               strcat (rs, lb);
1027             }
1028           else
1029             {
1030               rs = Safe_calloc (1, strlen (lb) + 1);
1031               strcpy (rs, lb);
1032             }
1033           nch = 0;
1034         }
1035     }
1036
1037   /* if some charaters left over */
1038   if (nch)
1039     {
1040       lb[nch] = '\0';
1041       /* copy it into allocated buffer */
1042       if (rs)
1043         {
1044           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1045           strcat (rs, lb);
1046         }
1047       else
1048         {
1049           rs = Safe_calloc (1, strlen (lb) + 1);
1050           strcpy (rs, lb);
1051         }
1052     }
1053   return rs;
1054 }
1055
1056 /*-----------------------------------------------------------------*/
1057 /* initPeepHole - initialises the peep hole optimizer stuff        */
1058 /*-----------------------------------------------------------------*/
1059 void 
1060 initPeepHole ()
1061 {
1062   char *s;
1063
1064   /* read in the default rules */
1065   readRules (port->peep.default_rules);
1066
1067   /* if we have any additional file read it too */
1068   if (options.peep_file)
1069     {
1070       readRules (s = readFileIntoBuffer (options.peep_file));
1071       setToNull ((void **) &s);
1072     }
1073
1074
1075 #if !OPT_DISABLE_PIC
1076   /* Convert the peep rules into pcode.
1077      NOTE: this is only support in the PIC port (at the moment)
1078   */
1079   if (TARGET_IS_PIC) {
1080     peepRules2pCode(rootRules);
1081   }
1082 #endif
1083
1084 }