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