comment out preprocessor directives in inline asm
[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         if (head->isInline && *head->line=='#') {
279           // comment out preprocessor directives in inline asm
280           fprintf (of, ";");
281         }
282         fprintf (of, "\t%s\n", head->line);
283       }
284       head = head->next;
285     }
286 }
287
288 /*-----------------------------------------------------------------*/
289 /* newPeepRule - creates a new peeprule and attach it to the root  */
290 /*-----------------------------------------------------------------*/
291 peepRule *
292 newPeepRule (lineNode * match,
293              lineNode * replace,
294              char *cond,
295              int restart)
296 {
297   peepRule *pr;
298
299   pr = Safe_calloc (1, sizeof (peepRule));
300   pr->match = match;
301   pr->replace = replace;
302   pr->restart = restart;
303
304   if (cond && *cond)
305     {
306       pr->cond = Safe_calloc (1, strlen (cond) + 1);
307       strcpy (pr->cond, cond);
308     }
309   else
310     pr->cond = NULL;
311
312   pr->vars = newHashTable (100);
313
314   /* if root is empty */
315   if (!rootRules)
316     rootRules = currRule = pr;
317   else
318     currRule = currRule->next = pr;
319
320   return pr;
321 }
322
323 /*-----------------------------------------------------------------*/
324 /* newLineNode - creates a new peep line                           */
325 /*-----------------------------------------------------------------*/
326 lineNode *
327 newLineNode (char *line)
328 {
329   lineNode *pl;
330
331   pl = Safe_calloc (1, sizeof (lineNode));
332   pl->line = Safe_calloc (1, strlen (line) + 1);
333   strcpy (pl->line, line);
334   return pl;
335 }
336
337 /*-----------------------------------------------------------------*/
338 /* connectLine - connects two lines                                */
339 /*-----------------------------------------------------------------*/
340 lineNode *
341 connectLine (lineNode * pl1, lineNode * pl2)
342 {
343   if (!pl1 || !pl2)
344     {
345       fprintf (stderr, "trying to connect null line\n");
346       return NULL;
347     }
348
349   pl2->prev = pl1;
350   pl1->next = pl2;
351
352   return pl2;
353 }
354
355 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
356                          if (!*x) { fprintf(stderr,y); return ; } }
357
358 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
359                            if (!*x) { fprintf(stderr,z); return ; } }
360 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
361                            if (!*x) { fprintf(stderr,z); return ; } }
362
363 /*-----------------------------------------------------------------*/
364 /* getPeepLine - parses the peep lines                             */
365 /*-----------------------------------------------------------------*/
366 static void 
367 getPeepLine (lineNode ** head, char **bpp)
368 {
369   char lines[MAX_PATTERN_LEN];
370   char *lp;
371
372   lineNode *currL = NULL;
373   char *bp = *bpp;
374   while (1)
375     {
376
377       if (!*bp)
378         {
379           fprintf (stderr, "unexpected end of match pattern\n");
380           return;
381         }
382
383       if (*bp == '\n')
384         {
385           bp++;
386           while (isspace (*bp) ||
387                  *bp == '\n')
388             bp++;
389         }
390
391       if (*bp == '}')
392         {
393           bp++;
394           break;
395         }
396
397       /* read till end of line */
398       lp = lines;
399       while ((*bp != '\n' && *bp != '}') && *bp)
400         *lp++ = *bp++;
401
402       *lp = '\0';
403       if (!currL)
404         *head = currL = newLineNode (lines);
405       else
406         currL = connectLine (currL, newLineNode (lines));
407     }
408
409   *bpp = bp;
410 }
411
412 /*-----------------------------------------------------------------*/
413 /* readRules - reads the rules from a string buffer                */
414 /*-----------------------------------------------------------------*/
415 static void 
416 readRules (char *bp)
417 {
418   char restart = 0;
419   char lines[MAX_PATTERN_LEN];
420   char *lp;
421   lineNode *match;
422   lineNode *replace;
423   lineNode *currL = NULL;
424
425   if (!bp)
426     return;
427 top:
428   restart = 0;
429   /* look for the token "replace" that is the
430      start of a rule */
431   while (*bp && strncmp (bp, "replace", 7))
432     bp++;
433
434   /* if not found */
435   if (!*bp)
436     return;
437
438   /* then look for either "restart" or '{' */
439   while (strncmp (bp, "restart", 7) &&
440          *bp != '{' && bp)
441     bp++;
442
443   /* not found */
444   if (!*bp)
445     {
446       fprintf (stderr, "expected 'restart' or '{'\n");
447       return;
448     }
449
450   /* if brace */
451   if (*bp == '{')
452     bp++;
453   else
454     {                           /* must be restart */
455       restart++;
456       bp += strlen ("restart");
457       /* look for '{' */
458       EXPECT_CHR (bp, '{', "expected '{'\n");
459       bp++;
460     }
461
462   /* skip thru all the blank space */
463   SKIP_SPACE (bp, "unexpected end of rule\n");
464
465   match = replace = currL = NULL;
466   /* we are the start of a rule */
467   getPeepLine (&match, &bp);
468
469   /* now look for by */
470   EXPECT_STR (bp, "by", "expected 'by'\n");
471
472   /* then look for a '{' */
473   EXPECT_CHR (bp, '{', "expected '{'\n");
474   bp++;
475
476   SKIP_SPACE (bp, "unexpected end of rule\n");
477   getPeepLine (&replace, &bp);
478
479   /* look for a 'if' */
480   while ((isspace (*bp) || *bp == '\n') && *bp)
481     bp++;
482
483   if (strncmp (bp, "if", 2) == 0)
484     {
485       bp += 2;
486       while ((isspace (*bp) || *bp == '\n') && *bp)
487         bp++;
488       if (!*bp)
489         {
490           fprintf (stderr, "expected condition name\n");
491           return;
492         }
493
494       /* look for the condition */
495       lp = lines;
496       while (*bp && (*bp != '\n'))
497         {
498           *lp++ = *bp++;
499         }
500       *lp = '\0';
501
502       newPeepRule (match, replace, lines, restart);
503     }
504   else
505     newPeepRule (match, replace, NULL, restart);
506   goto top;
507
508 }
509
510 /*-----------------------------------------------------------------*/
511 /* keyForVar - returns the numeric key for a var                   */
512 /*-----------------------------------------------------------------*/
513 static int 
514 keyForVar (char *d)
515 {
516   int i = 0;
517
518   while (isdigit (*d))
519     {
520       i *= 10;
521       i += (*d++ - '0');
522     }
523
524   return i;
525 }
526
527 /*-----------------------------------------------------------------*/
528 /* bindVar - binds a value to a variable in the given hashtable    */
529 /*-----------------------------------------------------------------*/
530 static void 
531 bindVar (int key, char **s, hTab ** vtab)
532 {
533   char vval[MAX_PATTERN_LEN];
534   char *vvx;
535   char *vv = vval;
536
537   /* first get the value of the variable */
538   vvx = *s;
539   /* the value is ended by a ',' or space or newline or null or ) */
540   while (*vvx &&
541          *vvx != ',' &&
542          !isspace (*vvx) &&
543          *vvx != '\n' &&
544          *vvx != ':' &&
545          *vvx != ')')
546     {
547       char ubb = 0;
548       /* if we find a '(' then we need to balance it */
549       if (*vvx == '(')
550         {
551           ubb++;
552           while (ubb)
553             {
554               *vv++ = *vvx++;
555               if (*vvx == '(')
556                 ubb++;
557               if (*vvx == ')')
558                 ubb--;
559             }
560         }
561       else
562         *vv++ = *vvx++;
563     }
564   *s = vvx;
565   *vv = '\0';
566   /* got value */
567   vvx = Safe_calloc (1, strlen (vval) + 1);
568   strcpy (vvx, vval);
569   hTabAddItem (vtab, key, vvx);
570
571 }
572
573 /*-----------------------------------------------------------------*/
574 /* matchLine - matches one line                                    */
575 /*-----------------------------------------------------------------*/
576 static bool 
577 matchLine (char *s, char *d, hTab ** vars)
578 {
579
580   if (!s || !(*s))
581     return FALSE;
582
583   while (*s && *d)
584     {
585
586       /* skip white space in both */
587       while (isspace (*s))
588         s++;
589       while (isspace (*d))
590         d++;
591
592       /* if the destination is a var */
593       if (*d == '%' && isdigit (*(d + 1)))
594         {
595           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
596           /* if the variable is already bound
597              then it MUST match with dest */
598           if (v)
599             {
600               while (*v)
601                 if (*v++ != *s++)
602                   return FALSE;
603             }
604           else
605             /* variable not bound we need to
606                bind it */
607             bindVar (keyForVar (d + 1), &s, vars);
608
609           /* in either case go past the variable */
610           d++;
611           while (isdigit (*d))
612             d++;
613         }
614
615       /* they should be an exact match other wise */
616       if (*s && *d)
617         {
618           while (isspace (*s))
619             s++;
620           while (isspace (*d))
621             d++;
622           if (*s++ != *d++)
623             return FALSE;
624         }
625
626     }
627
628   /* get rid of the trailing spaces
629      in both source & destination */
630   if (*s)
631     while (isspace (*s))
632       s++;
633
634   if (*d)
635     while (isspace (*d))
636       d++;
637
638   /* after all this if only one of them
639      has something left over then no match */
640   if (*s || *d)
641     return FALSE;
642
643   return TRUE;
644 }
645
646 /*-----------------------------------------------------------------*/
647 /* matchRule - matches a all the rule lines                        */
648 /*-----------------------------------------------------------------*/
649 static bool 
650 matchRule (lineNode * pl,
651            lineNode ** mtail,
652            peepRule * pr,
653            lineNode * head)
654 {
655   lineNode *spl;                /* source pl */
656   lineNode *rpl;                /* rule peep line */
657
658   hTabClearAll (pr->vars);
659 /*     setToNull((void **) &pr->vars);    */
660 /*     pr->vars = newHashTable(100); */
661
662   /* for all the lines defined in the rule */
663   rpl = pr->match;
664   spl = pl;
665   while (spl && rpl)
666     {
667
668       /* if the source line starts with a ';' then
669          comment line don't process or the source line
670          contains == . debugger information skip it */
671       if (spl->line &&
672           (*spl->line == ';' || spl->isDebug))
673         {
674           spl = spl->next;
675           continue;
676         }
677
678       if (!matchLine (spl->line, rpl->line, &pr->vars))
679         return FALSE;
680
681       rpl = rpl->next;
682       if (rpl)
683         spl = spl->next;
684     }
685
686   /* if rules ended */
687   if (!rpl)
688     {
689       /* if this rule has additional conditions */
690       if (pr->cond)
691         {
692           if (callFuncByName (pr->cond, pr->vars, pl, head))
693             {
694               *mtail = spl;
695               return TRUE;
696             }
697           else
698             return FALSE;
699         }
700       else
701         {
702           *mtail = spl;
703           return TRUE;
704         }
705     }
706   else
707     return FALSE;
708 }
709
710 /*-----------------------------------------------------------------*/
711 /* replaceRule - does replacement of a matching pattern            */
712 /*-----------------------------------------------------------------*/
713 static void 
714 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
715 {
716   lineNode *cl = NULL;
717   lineNode *pl = NULL, *lhead = NULL;
718   /* a long function name and long variable name can evaluate to
719      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
720   char lb[MAX_PATTERN_LEN*4];
721   char *lbp;
722   lineNode *comment = NULL;
723
724   /* collect all the comment lines in the source */
725   for (cl = *shead; cl != stail; cl = cl->next)
726     {
727       if (cl->line && (*cl->line == ';' || cl->isDebug))
728         {
729           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
730                 (comment = newLineNode (cl->line)));
731           pl->isDebug = cl->isDebug;
732         }
733     }
734   cl = NULL;
735
736   /* for all the lines in the replacement pattern do */
737   for (pl = pr->replace; pl; pl = pl->next)
738     {
739       char *v;
740       char *l;
741       lbp = lb;
742
743       l = pl->line;
744       while (*l)
745         {
746           /* if the line contains a variable */
747           if (*l == '%' && isdigit (*(l + 1)))
748             {
749               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
750               if (!v)
751                 {
752                   fprintf (stderr, "used unbound variable in replacement\n");
753                   l++;
754                   continue;
755                 }
756               while (*v) {
757                 *lbp++ = *v++;
758               }
759               l++;
760               while (isdigit (*l)) {
761                 l++;
762               }
763               continue;
764             }
765           *lbp++ = *l++;
766         }
767
768       *lbp = '\0';
769       if (cl)
770         cl = connectLine (cl, newLineNode (lb));
771       else
772         lhead = cl = newLineNode (lb);
773     }
774
775   /* add the comments if any to the head of list */
776   if (comment)
777     {
778       lineNode *lc = comment;
779       while (lc->next)
780         lc = lc->next;
781       lc->next = lhead;
782       if (lhead)
783         lhead->prev = lc;
784       lhead = comment;
785     }
786
787   /* now we need to connect / replace the original chain */
788   /* if there is a prev then change it */
789   if ((*shead)->prev)
790     {
791       (*shead)->prev->next = lhead;
792       lhead->prev = (*shead)->prev;
793     }
794   else
795     *shead = lhead;
796   /* now for the tail */
797   if (stail && stail->next)
798     {
799       stail->next->prev = cl;
800       if (cl)
801         cl->next = stail->next;
802     }
803 }
804
805 /* Returns TRUE if this line is a label definition.
806
807  * If so, start will point to the start of the label name,
808  * and len will be it's length.
809  */
810 bool 
811 isLabelDefinition (const char *line, const char **start, int *len)
812 {
813   const char *cp = line;
814
815   /* This line is a label if if consists of:
816    * [optional whitespace] followed by identifier chars
817    * (alnum | $ | _ ) followed by a colon.
818    */
819
820   while (*cp && isspace (*cp))
821     {
822       cp++;
823     }
824
825   if (!*cp)
826     {
827       return FALSE;
828     }
829
830   *start = cp;
831
832   while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
833     {
834       cp++;
835     }
836
837   if ((cp == *start) || (*cp != ':'))
838     {
839       return FALSE;
840     }
841
842   *len = (cp - (*start));
843   return TRUE;
844 }
845
846 /* Quick & dirty string hash function. */
847 static int 
848 hashSymbolName (const char *name)
849 {
850   int hash = 0;
851
852   while (*name)
853     {
854       hash = (hash << 6) ^ *name;
855       name++;
856     }
857
858   if (hash < 0)
859     {
860       hash = -hash;
861     }
862
863   return hash % HTAB_SIZE;
864 }
865
866 /* Build a hash of all labels in the passed set of lines
867  * and how many times they are referenced.
868  */
869 static void 
870 buildLabelRefCountHash (lineNode * head)
871 {
872   lineNode *line;
873   const char *label;
874   int labelLen;
875   int i;
876
877   assert (labelHash == NULL);
878   labelHash = newHashTable (HTAB_SIZE);
879
880   /* First pass: locate all the labels. */
881   line = head;
882
883   while (line)
884     {
885       if (isLabelDefinition (line->line, &label, &labelLen)
886           && labelLen <= SDCC_NAME_MAX)
887         {
888           labelHashEntry *entry;
889
890           entry = Safe_calloc (1, sizeof (labelHashEntry));
891
892           memcpy (entry->name, label, labelLen);
893           entry->name[labelLen] = 0;
894           entry->refCount = -1;
895
896           hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
897         }
898       line = line->next;
899     }
900
901
902   /* Second pass: for each line, note all the referenced labels. */
903   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
904   line = head;
905   while (line)
906     {
907       for (i = 0; i < HTAB_SIZE; i++)
908         {
909           labelHashEntry *thisEntry;
910
911           thisEntry = hTabFirstItemWK (labelHash, i);
912
913           while (thisEntry)
914             {
915               if (strstr (line->line, thisEntry->name))
916                 {
917                   thisEntry->refCount++;
918                 }
919               thisEntry = hTabNextItemWK (labelHash);
920             }
921         }
922       line = line->next;
923     }
924
925 #if 0
926   /* Spew the contents of the table. Debugging fun only. */
927   for (i = 0; i < HTAB_SIZE; i++)
928     {
929       labelHashEntry *thisEntry;
930
931       thisEntry = hTabFirstItemWK (labelHash, i);
932
933       while (thisEntry)
934         {
935           fprintf (stderr, "label: %s ref %d\n",
936                    thisEntry->name, thisEntry->refCount);
937           thisEntry = hTabNextItemWK (labelHash);
938         }
939     }
940 #endif
941 }
942
943 /*-----------------------------------------------------------------*/
944 /* peepHole - matches & substitutes rules                          */
945 /*-----------------------------------------------------------------*/
946 void 
947 peepHole (lineNode ** pls)
948 {
949   lineNode *spl;
950   peepRule *pr;
951   lineNode *mtail = NULL;
952
953   if (labelHash)
954     {
955       hTabDeleteAll (labelHash);
956     }
957   labelHash = NULL;
958
959 top:
960   /* for all rules */
961   for (pr = rootRules; pr; pr = pr->next)
962     {
963
964       for (spl = *pls; spl; spl = spl->next)
965         {
966           /* if inline assembler then no peep hole */
967           if (spl->isInline)
968             continue;
969
970           mtail = NULL;
971
972           /* if it matches */
973           if (matchRule (spl, &mtail, pr, *pls))
974             {
975
976               /* then replace */
977               if (spl == *pls)
978                 replaceRule (pls, mtail, pr);
979               else
980                 replaceRule (&spl, mtail, pr);
981
982               /* if restart rule type then
983                  start at the top again */
984               if (pr->restart)
985                 goto top;
986             }
987         }
988     }
989 }
990
991
992 /*-----------------------------------------------------------------*/
993 /* readFileIntoBuffer - reads a file into a string buffer          */
994 /*-----------------------------------------------------------------*/
995 static char *
996 readFileIntoBuffer (char *fname)
997 {
998   FILE *f;
999   char *rs = NULL;
1000   int nch = 0;
1001   int ch;
1002   char lb[MAX_PATTERN_LEN];
1003
1004   if (!(f = fopen (fname, "r")))
1005     {
1006       fprintf (stderr, "cannot open peep rule file\n");
1007       return NULL;
1008     }
1009
1010   while ((ch = fgetc (f)) != EOF)
1011     {
1012       lb[nch++] = ch;
1013
1014       /* if we maxed out our local buffer */
1015       if (nch >= (MAX_PATTERN_LEN - 2))
1016         {
1017           lb[nch] = '\0';
1018           /* copy it into allocated buffer */
1019           if (rs)
1020             {
1021               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1022               strcat (rs, lb);
1023             }
1024           else
1025             {
1026               rs = Safe_calloc (1, strlen (lb) + 1);
1027               strcpy (rs, lb);
1028             }
1029           nch = 0;
1030         }
1031     }
1032
1033   /* if some charaters left over */
1034   if (nch)
1035     {
1036       lb[nch] = '\0';
1037       /* copy it into allocated buffer */
1038       if (rs)
1039         {
1040           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1041           strcat (rs, lb);
1042         }
1043       else
1044         {
1045           rs = Safe_calloc (1, strlen (lb) + 1);
1046           strcpy (rs, lb);
1047         }
1048     }
1049   return rs;
1050 }
1051
1052 /*-----------------------------------------------------------------*/
1053 /* initPeepHole - initiaises the peep hole optimizer stuff         */
1054 /*-----------------------------------------------------------------*/
1055 void 
1056 initPeepHole ()
1057 {
1058   char *s;
1059
1060   /* read in the default rules */
1061   readRules (port->peep.default_rules);
1062
1063   /* if we have any additional file read it too */
1064   if (options.peep_file)
1065     {
1066       readRules (s = readFileIntoBuffer (options.peep_file));
1067       setToNull ((void **) &s);
1068     }
1069 }