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