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