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