* src/SDCCpeeph.c (notVolatileVariable): extra check, somehow for hc08 an operand
[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 "dbuf_string.h"
28
29 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
30 #define ISCHARSPACE(c) isspace((unsigned char)c)
31 #define ISCHARALNUM(c) isalnum((unsigned char)c)
32
33 static peepRule *rootRules = NULL;
34 static peepRule *currRule = NULL;
35
36 #define HTAB_SIZE 53
37
38 hTab *labelHash = NULL;
39
40 static struct
41 {
42   allocTrace values;
43   allocTrace labels;
44 } _G;
45
46 static int hashSymbolName (const char *name);
47 static void buildLabelRefCountHash (lineNode * head);
48 static void bindVar (int key, char **s, hTab ** vtab);
49
50 static bool matchLine (char *, char *, hTab **);
51
52 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
53         lineNode *head, char *cmdLine)
54
55 #if !OPT_DISABLE_PIC
56 void peepRules2pCode(peepRule *);
57 #endif
58
59 #if !OPT_DISABLE_PIC16
60 void pic16_peepRules2pCode(peepRule *);
61 #endif
62
63 /*-----------------------------------------------------------------*/
64 /* pcDistance - afinds a label back ward or forward                */
65 /*-----------------------------------------------------------------*/
66
67 static int
68 pcDistance (lineNode * cpos, char *lbl, bool back)
69 {
70   lineNode *pl = cpos;
71   char buff[MAX_PATTERN_LEN];
72   int dist = 0;
73
74   SNPRINTF (buff, sizeof(buff), "%s:", lbl);
75   while (pl)
76     {
77
78       if (pl->line &&
79           !pl->isComment &&
80           !pl->isLabel &&
81           !pl->isDebug) {
82                 if (port->peep.getSize) {
83                         dist += port->peep.getSize(pl);
84                 } else {
85                         dist += 3;
86                 }
87         }
88
89       if (strncmp (pl->line, buff, strlen (buff)) == 0)
90         return dist;
91
92       if (back)
93         pl = pl->prev;
94       else
95         pl = pl->next;
96
97     }
98   return 0;
99 }
100
101 /*-----------------------------------------------------------------*/
102 /* portIsDS390 - return true if port is DS390                      */
103 /*-----------------------------------------------------------------*/
104 FBYNAME (portIsDS390)
105 {
106     return ((strcmp(port->target,"ds390") == 0) ||
107             (strcmp(port->target,"ds400") == 0));
108 }
109
110 /*-----------------------------------------------------------------*/
111 /* flat24bitMode - will check to see if we are in flat24 mode      */
112 /*-----------------------------------------------------------------*/
113 FBYNAME (flat24bitMode)
114 {
115   return (options.model == MODEL_FLAT24);
116 }
117
118 /*-----------------------------------------------------------------*/
119 /* xramMovcOption - check if using movc to read xram               */
120 /*-----------------------------------------------------------------*/
121 FBYNAME (xramMovcOption)
122 {
123   return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
124 }
125
126 /*-----------------------------------------------------------------*/
127 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
128 /*-----------------------------------------------------------------*/
129 FBYNAME (useAcallAjmp)
130 {
131   return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
132 }
133
134 /*-----------------------------------------------------------------*/
135 /* labelInRange - will check to see if label %5 is within range    */
136 /*-----------------------------------------------------------------*/
137 FBYNAME (labelInRange)
138 {
139   /* assumes that %5 pattern variable has the label name */
140   char *lbl = hTabItemWithKey (vars, 5);
141   int dist = 0;
142
143   if (!lbl)
144     return FALSE;
145
146   /* Don't optimize jumps in a jump table; a more generic test */
147   if (currPl->ic && currPl->ic->op == JUMPTABLE)
148     return FALSE;
149
150   /* if the previous two instructions are "ljmp"s then don't
151      do it since it can be part of a jump table */
152   if (currPl->prev && currPl->prev->prev &&
153       strstr (currPl->prev->line, "ljmp") &&
154       strstr (currPl->prev->prev->line, "ljmp"))
155     return FALSE;
156
157   /* calculate the label distance : the jump for reladdr can be
158      +/- 127 bytes, here Iam assuming that an average 8051
159      instruction is 2 bytes long, so if the label is more than
160      63 intructions away, the label is considered out of range
161      for a relative jump. we could get more precise this will
162      suffice for now since it catches > 90% cases */
163   dist = (pcDistance (currPl, lbl, TRUE) +
164           pcDistance (currPl, lbl, FALSE));
165
166 /*    changed to 127, now that pcDistance return actual number of bytes */
167   if (!dist || dist > 127)
168     return FALSE;
169
170   return TRUE;
171 }
172
173 /*-----------------------------------------------------------------*/
174 /* labelJTInRange - will check to see if label %5 and up are       */
175 /* within range.                                                   */
176 /* Specifically meant to optimize long (3-byte) jumps to short     */
177 /* (2-byte) jumps in jumptables                                    */
178 /*-----------------------------------------------------------------*/
179 FBYNAME (labelJTInRange)
180 {
181   char *lbl;
182   int dist, count, i;
183
184   if (!getenv("SDCC_SJMP_JUMPTABLE"))
185     return FALSE;
186
187   /* Only optimize within a jump table */
188   if (currPl->ic && currPl->ic->op != JUMPTABLE)
189     return FALSE;
190
191   count = elementsInSet( IC_JTLABELS (currPl->ic) );
192
193   /* check all labels (this is needed if the case statements are unsorted) */
194   for (i=0; i<count; i++)
195     {
196       /* assumes that the %5 pattern variable has the first ljmp label */
197       lbl = hTabItemWithKey (vars, 5+i);
198       if (!lbl)
199         return FALSE;
200
201       dist = pcDistance (currPl, lbl, FALSE);
202
203       /* three terms used to calculate allowable distance */
204 // printf("\nlabel %s %i dist %i cdist 0x%02x 0x%02x\n", lbl, i, dist, dist -(count-i-1)-(7+3*i), 127+(count-i-1)+(7+3*i) - dist);
205       if (!dist ||
206           dist > 127+           /* range of sjmp */
207                  (7+3*i)+       /* offset between this jump and currPl,
208                                    should use pcDistance instead? */
209                  (count-i-1)    /* if peephole applies distance is shortened */
210          )
211         return FALSE;
212     }
213   return TRUE;
214 }
215
216 /*-----------------------------------------------------------------*/
217 /* labelIsReturnOnly - Check if label %5 is followed by RET        */
218 /*-----------------------------------------------------------------*/
219 FBYNAME (labelIsReturnOnly)
220 {
221   /* assumes that %5 pattern variable has the label name */
222   const char *label, *p;
223   const lineNode *pl;
224   int len;
225   char * retInst;
226
227   /* Don't optimize jumps in a jump table; a more generic test */
228   if (currPl->ic && currPl->ic->op == JUMPTABLE)
229     return FALSE;
230
231   label = hTabItemWithKey (vars, 5);
232   if (!label)
233     return FALSE;
234   len = strlen(label);
235
236   for(pl = currPl; pl; pl = pl->next)
237     {
238       if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
239         {
240           if (strncmp(pl->line, label, len) == 0)
241             break; /* Found Label */
242           if (strlen(pl->line) != 7       || !ISCHARDIGIT(*(pl->line))   ||
243               !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
244               !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
245               *(pl->line+5) != '$')
246             {
247               return FALSE; /* non-local label encountered */
248             }
249         }
250     }
251   if (!pl)
252     return FALSE; /* did not find the label */
253   pl = pl->next;
254   while (pl && (pl->isDebug || pl->isComment))
255     pl = pl->next;
256   if (!pl || !pl->line || pl->isDebug)
257     return FALSE; /* next line not valid */
258   p = pl->line;
259   for (p = pl->line; *p && ISCHARSPACE(*p); p++)
260     ;
261
262   retInst = "ret";
263   if (TARGET_IS_HC08)
264     retInst = "rts";
265   if (strcmp(p, retInst) == 0)
266     return TRUE;
267   return FALSE;
268 }
269
270 /*-----------------------------------------------------------------*/
271 /* labelIsUncondJump - Check if label %5 is followed by an         */
272 /* unconditional jump and put the destination of that jump in %6   */
273 /*-----------------------------------------------------------------*/
274 FBYNAME (labelIsUncondJump)
275 {
276   /* assumes that %5 pattern variable has the label name */
277   const char *label;
278   char *p, *q;
279   const lineNode *pl;
280   int len;
281   char * jpInst = NULL;
282
283   /* Don't optimize jumps in a jump table; a more generic test */
284   if (currPl->ic && currPl->ic->op == JUMPTABLE)
285     return FALSE;
286
287   label = hTabItemWithKey (vars, 5);
288   if (!label)
289     return FALSE;
290   len = strlen(label);
291
292   for (pl = currPl; pl; pl = pl->next)
293     {
294       if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
295         {
296           if (strncmp(pl->line, label, len) == 0)
297             break; /* Found Label */
298           if (strlen(pl->line) != 7       || !ISCHARDIGIT(*(pl->line))   ||
299               !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
300               !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
301               *(pl->line+5) != '$')
302             {
303               return FALSE; /* non-local label encountered */
304             }
305         }
306     }
307   if (!pl)
308     return FALSE; /* did not find the label */
309   pl = pl->next;
310   while (pl && (pl->isDebug || pl->isComment))
311     pl = pl->next;
312   if (!pl || !pl->line)
313     return FALSE; /* next line not valid */
314   p = pl->line;
315   while (*p && ISCHARSPACE(*p))
316     p++;
317
318   if (TARGET_MCS51_LIKE)
319     jpInst = "ljmp";
320   if (TARGET_IS_HC08)
321     jpInst = "jmp";
322   if (TARGET_Z80_LIKE)
323     jpInst = "jp";
324   len = strlen(jpInst);
325   if (strncmp(p, jpInst, len) != 0)
326     return FALSE; /* next line is no jump */
327   p += len;
328   while (*p && ISCHARSPACE(*p))
329     p++;
330
331   q = p;
332   while (*q && *q!=';')
333     q++;
334   while (q>p && ISCHARSPACE(*q))
335     q--;
336   len = q-p;
337   if (len == 0)
338     return FALSE; /* no destination? */
339   if (TARGET_Z80_LIKE)
340     {
341       while (q>p && *q!=',')
342         q--;
343       if (*q==',')
344         return FALSE; /* conditional jump */
345     }
346   if (strcmp(p, q) == 0)
347     return FALSE; /* labels are equal */
348   /* now put the destination in %6 */
349   bindVar (6, &p, &vars);
350   return TRUE;
351 }
352
353 /*-----------------------------------------------------------------*/
354 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other      */
355 /* usage of it in the code depends on a value from this section    */
356 /*-----------------------------------------------------------------*/
357 FBYNAME (okToRemoveSLOC)
358 {
359   const lineNode *pl;
360   const char *sloc, *p;
361   int dummy1, dummy2, dummy3;
362
363   /* assumes that %1 as the SLOC name */
364   sloc = hTabItemWithKey (vars, 1);
365   if (sloc == NULL) return FALSE;
366   p = strstr(sloc, "sloc");
367   if (p == NULL) return FALSE;
368   p += 4;
369   if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
370   /*TODO: ultra-paranoid: get funtion name from "head" and check that */
371   /* the sloc name begins with that.  Probably not really necessary */
372
373   /* Look for any occurance of this SLOC before the peephole match */
374   for (pl = currPl->prev; pl; pl = pl->prev) {
375         if (pl->line && !pl->isDebug && !pl->isComment
376           && *pl->line != ';' && strstr(pl->line, sloc))
377                 return FALSE;
378   }
379   /* Look for any occurance of this SLOC after the peephole match */
380   for (pl = endPl->next; pl; pl = pl->next) {
381         if (pl->line && !pl->isDebug && !pl->isComment
382           && *pl->line != ';' && strstr(pl->line, sloc))
383                 return FALSE;
384   }
385   return TRUE; /* safe for a peephole to remove it :) */
386 }
387
388 /*-----------------------------------------------------------------*/
389 /* deadMove - Check, if a pop/push pair can be removed             */
390 /*-----------------------------------------------------------------*/
391 FBYNAME (deadMove)
392 {
393   const char *reg = hTabItemWithKey (vars, 1);
394
395   if (port->peep.deadMove)
396     return port->peep.deadMove (reg, currPl, head);
397
398   fprintf (stderr, "Function deadMove not initialized in port structure\n");
399   return FALSE;
400 }
401
402 /*-----------------------------------------------------------------*/
403 /* operandsNotSame - check if %1 & %2 are the same                 */
404 /*-----------------------------------------------------------------*/
405 FBYNAME (operandsNotSame)
406 {
407   char *op1 = hTabItemWithKey (vars, 1);
408   char *op2 = hTabItemWithKey (vars, 2);
409
410   if (strcmp (op1, op2) == 0)
411     return FALSE;
412   else
413     return TRUE;
414 }
415
416 /*-----------------------------------------------------------------*/
417 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same    */
418 /*-----------------------------------------------------------------*/
419 FBYNAME (operandsNotSame3)
420 {
421   char *op1 = hTabItemWithKey (vars, 1);
422   char *op2 = hTabItemWithKey (vars, 2);
423   char *op3 = hTabItemWithKey (vars, 3);
424
425   if ( (strcmp (op1, op2) == 0) ||
426        (strcmp (op1, op3) == 0) ||
427        (strcmp (op2, op3) == 0) )
428     return FALSE;
429   else
430     return TRUE;
431 }
432
433 /*-----------------------------------------------------------------*/
434 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
435 /*-----------------------------------------------------------------*/
436 FBYNAME (operandsNotSame4)
437 {
438   char *op1 = hTabItemWithKey (vars, 1);
439   char *op2 = hTabItemWithKey (vars, 2);
440   char *op3 = hTabItemWithKey (vars, 3);
441   char *op4 = hTabItemWithKey (vars, 4);
442
443   if ( (strcmp (op1, op2) == 0) ||
444        (strcmp (op1, op3) == 0) ||
445        (strcmp (op1, op4) == 0) ||
446        (strcmp (op2, op3) == 0) ||
447        (strcmp (op2, op4) == 0) ||
448        (strcmp (op3, op4) == 0) )
449     return FALSE;
450   else
451     return TRUE;
452 }
453
454 /*-----------------------------------------------------------------*/
455 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
456 /*-----------------------------------------------------------------*/
457 FBYNAME (operandsNotSame5)
458 {
459   char *op1 = hTabItemWithKey (vars, 1);
460   char *op2 = hTabItemWithKey (vars, 2);
461   char *op3 = hTabItemWithKey (vars, 3);
462   char *op4 = hTabItemWithKey (vars, 4);
463   char *op5 = hTabItemWithKey (vars, 5);
464
465   if ( (strcmp (op1, op2) == 0) ||
466        (strcmp (op1, op3) == 0) ||
467        (strcmp (op1, op4) == 0) ||
468        (strcmp (op1, op5) == 0) ||
469        (strcmp (op2, op3) == 0) ||
470        (strcmp (op2, op4) == 0) ||
471        (strcmp (op2, op5) == 0) ||
472        (strcmp (op3, op4) == 0) ||
473        (strcmp (op3, op5) == 0) ||
474        (strcmp (op4, op5) == 0) )
475     return FALSE;
476   else
477     return TRUE;
478 }
479
480 /*-----------------------------------------------------------------*/
481 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
482 /*-----------------------------------------------------------------*/
483 FBYNAME (operandsNotSame6)
484 {
485   char *op1 = hTabItemWithKey (vars, 1);
486   char *op2 = hTabItemWithKey (vars, 2);
487   char *op3 = hTabItemWithKey (vars, 3);
488   char *op4 = hTabItemWithKey (vars, 4);
489   char *op5 = hTabItemWithKey (vars, 5);
490   char *op6 = hTabItemWithKey (vars, 6);
491
492   if ( (strcmp (op1, op2) == 0) ||
493        (strcmp (op1, op3) == 0) ||
494        (strcmp (op1, op4) == 0) ||
495        (strcmp (op1, op5) == 0) ||
496        (strcmp (op1, op6) == 0) ||
497        (strcmp (op2, op3) == 0) ||
498        (strcmp (op2, op4) == 0) ||
499        (strcmp (op2, op5) == 0) ||
500        (strcmp (op2, op6) == 0) ||
501        (strcmp (op3, op4) == 0) ||
502        (strcmp (op3, op5) == 0) ||
503        (strcmp (op3, op6) == 0) ||
504        (strcmp (op4, op5) == 0) ||
505        (strcmp (op4, op6) == 0) ||
506        (strcmp (op5, op6) == 0) )
507     return FALSE;
508   else
509     return TRUE;
510 }
511
512 /*-----------------------------------------------------------------*/
513 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
514 /*-----------------------------------------------------------------*/
515 FBYNAME (operandsNotSame7)
516 {
517   char *op1 = hTabItemWithKey (vars, 1);
518   char *op2 = hTabItemWithKey (vars, 2);
519   char *op3 = hTabItemWithKey (vars, 3);
520   char *op4 = hTabItemWithKey (vars, 4);
521   char *op5 = hTabItemWithKey (vars, 5);
522   char *op6 = hTabItemWithKey (vars, 6);
523   char *op7 = hTabItemWithKey (vars, 7);
524
525   if ( (strcmp (op1, op2) == 0) ||
526        (strcmp (op1, op3) == 0) ||
527        (strcmp (op1, op4) == 0) ||
528        (strcmp (op1, op5) == 0) ||
529        (strcmp (op1, op6) == 0) ||
530        (strcmp (op1, op7) == 0) ||
531        (strcmp (op2, op3) == 0) ||
532        (strcmp (op2, op4) == 0) ||
533        (strcmp (op2, op5) == 0) ||
534        (strcmp (op2, op6) == 0) ||
535        (strcmp (op2, op7) == 0) ||
536        (strcmp (op3, op4) == 0) ||
537        (strcmp (op3, op5) == 0) ||
538        (strcmp (op3, op6) == 0) ||
539        (strcmp (op3, op7) == 0) ||
540        (strcmp (op4, op5) == 0) ||
541        (strcmp (op4, op6) == 0) ||
542        (strcmp (op4, op7) == 0) ||
543        (strcmp (op5, op6) == 0) ||
544        (strcmp (op5, op7) == 0) ||
545        (strcmp (op6, op7) == 0) )
546     return FALSE;
547   else
548     return TRUE;
549 }
550
551 /*-----------------------------------------------------------------*/
552 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
553 /*-----------------------------------------------------------------*/
554 FBYNAME (operandsNotSame8)
555 {
556   char *op1 = hTabItemWithKey (vars, 1);
557   char *op2 = hTabItemWithKey (vars, 2);
558   char *op3 = hTabItemWithKey (vars, 3);
559   char *op4 = hTabItemWithKey (vars, 4);
560   char *op5 = hTabItemWithKey (vars, 5);
561   char *op6 = hTabItemWithKey (vars, 6);
562   char *op7 = hTabItemWithKey (vars, 7);
563   char *op8 = hTabItemWithKey (vars, 8);
564
565   if ( (strcmp (op1, op2) == 0) ||
566        (strcmp (op1, op3) == 0) ||
567        (strcmp (op1, op4) == 0) ||
568        (strcmp (op1, op5) == 0) ||
569        (strcmp (op1, op6) == 0) ||
570        (strcmp (op1, op7) == 0) ||
571        (strcmp (op1, op8) == 0) ||
572        (strcmp (op2, op3) == 0) ||
573        (strcmp (op2, op4) == 0) ||
574        (strcmp (op2, op5) == 0) ||
575        (strcmp (op2, op6) == 0) ||
576        (strcmp (op2, op7) == 0) ||
577        (strcmp (op2, op8) == 0) ||
578        (strcmp (op3, op4) == 0) ||
579        (strcmp (op3, op5) == 0) ||
580        (strcmp (op3, op6) == 0) ||
581        (strcmp (op3, op7) == 0) ||
582        (strcmp (op3, op8) == 0) ||
583        (strcmp (op4, op5) == 0) ||
584        (strcmp (op4, op6) == 0) ||
585        (strcmp (op4, op7) == 0) ||
586        (strcmp (op4, op8) == 0) ||
587        (strcmp (op5, op6) == 0) ||
588        (strcmp (op5, op7) == 0) ||
589        (strcmp (op5, op8) == 0) ||
590        (strcmp (op6, op7) == 0) ||
591        (strcmp (op6, op8) == 0) ||
592        (strcmp (op7, op8) == 0) )
593     return FALSE;
594   else
595     return TRUE;
596 }
597
598 /*-----------------------------------------------------------------*/
599 /* labelHashEntry- searches for a label in the list labelHash      */
600 /* Builds labelHash, if it does not yet exist.                     */
601 /* Returns the labelHashEntry or NULL                              */
602 /*-----------------------------------------------------------------*/
603 labelHashEntry *
604 getLabelRef (const char *label, lineNode *head)
605 {
606   labelHashEntry *entry;
607
608   /* If we don't have the label hash table yet, build it. */
609   if (!labelHash)
610     {
611       buildLabelRefCountHash (head);
612     }
613
614   entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
615
616   while (entry)
617     {
618       if (!strcmp (label, entry->name))
619         {
620           break;
621         }
622       entry = hTabNextItemWK (labelHash);
623     }
624   return entry;
625 }
626
627 /* labelRefCount:
628
629  * takes two parameters: a variable (bound to a label name)
630  * and an expected reference count.
631  *
632  * Returns TRUE if that label is defined and referenced exactly
633  * the given number of times.
634  */
635 FBYNAME (labelRefCount)
636 {
637   int varNumber, expectedRefCount;
638   bool rc = FALSE;
639
640   if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
641     {
642       char *label = hTabItemWithKey (vars, varNumber);
643
644       if (label)
645         {
646           labelHashEntry *entry = getLabelRef (label, head);
647
648           if (entry)
649             {
650 #if 0
651               /* debug spew. */
652               fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
653                        label, entry->refCount, expectedRefCount);
654 #endif
655
656               rc = (expectedRefCount == entry->refCount);
657             }
658           else
659             {
660               fprintf (stderr, "*** internal error: no label has entry for"
661                        " %s in labelRefCount peephole.\n",
662                        label);
663             }
664         }
665       else
666         {
667           fprintf (stderr, "*** internal error: var %d not bound"
668                    " in peephole labelRefCount rule.\n",
669                    varNumber);
670         }
671
672     }
673   else
674     {
675       fprintf (stderr,
676                "*** internal error: labelRefCount peephole restriction"
677                " malformed: %s\n", cmdLine);
678     }
679   return rc;
680 }
681
682 /* labelRefCountChange:
683  * takes two parameters: a variable (bound to a label name)
684  * and a signed int for changing the reference count.
685  *
686  * Please note, this function is not a conditional. It unconditionally
687  * changes the label. It should be passed as the 'last' function
688  * so it only is applied if all other conditions have been met.
689  *
690  * should always return TRUE
691  */
692 FBYNAME (labelRefCountChange)
693 {
694   int varNumber, RefCountDelta;
695   bool rc = FALSE;
696
697   /* If we don't have the label hash table yet, build it. */
698   if (!labelHash)
699     {
700       buildLabelRefCountHash (head);
701     }
702
703   if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
704     {
705       char *label = hTabItemWithKey (vars, varNumber);
706
707       if (label)
708         {
709           labelHashEntry *entry;
710
711           entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
712
713           while (entry)
714             {
715               if (!strcmp (label, entry->name))
716                 {
717                   break;
718                 }
719               entry = hTabNextItemWK (labelHash);
720             }
721           if (entry)
722             {
723               if (0 <= entry->refCount + RefCountDelta)
724                 {
725                   entry->refCount += RefCountDelta;
726                   rc = TRUE;
727                 }
728               else
729                 {
730                   fprintf (stderr, "*** internal error: label %s may not get"
731                           " negative refCount in %s peephole.\n",
732                            label, __FUNCTION__);
733                 }
734             }
735             else
736             {
737               fprintf (stderr, "*** internal error: no label has entry for"
738                        " %s in %s peephole.\n",
739                        label, __FUNCTION__);
740             }
741         }
742       else
743         {
744           fprintf (stderr, "*** internal error: var %d not bound"
745                    " in peephole %s rule.\n",
746                    varNumber, __FUNCTION__);
747         }
748     }
749   else
750     {
751       fprintf (stderr,
752                "*** internal error: labelRefCount peephole restriction"
753                " malformed: %s\n", cmdLine);
754     }
755   return rc;
756 }
757
758 /* Within the context of the lines currPl through endPl, determine
759 ** if the variable var contains a symbol that is volatile. Returns
760 ** TRUE only if it is certain that this was not volatile (the symbol
761 ** was found and not volatile, or var was a constant or CPU register).
762 ** Returns FALSE if the symbol was found and volatile, the symbol was
763 ** not found, or var was a indirect/pointer addressing mode.
764 */
765 static bool
766 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
767 {
768   char symname[SDCC_NAME_MAX + 1];
769   char *p = symname;
770   char *vp = var;
771   lineNode *cl;
772   operand *op;
773   iCode *last_ic;
774
775   /* Can't tell if indirect accesses are volatile or not, so
776   ** assume they are, just to be safe.
777   */
778   if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
779     {
780       if (*var=='@')
781         return FALSE;
782     }
783   if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
784     {
785       if (strstr(var,"(bc)"))
786         return FALSE;
787       if (strstr(var,"(de)"))
788         return FALSE;
789       if (strstr(var,"(hl)"))
790         return FALSE;
791       if (strstr(var,"(ix"))
792         return FALSE;
793       if (strstr(var,"(iy"))
794         return FALSE;
795     }
796
797   /* Extract a symbol name from the variable */
798   while (*vp && (*vp!='_'))
799     vp++;
800   while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
801     *p++ = *vp++;
802   *p='\0';
803
804   if (!symname[0])
805     {
806       /* Nothing resembling a symbol name was found, so it can't
807          be volatile
808       */
809       return TRUE;
810     }
811
812   last_ic = NULL;
813   for (cl = currPl; cl!=endPl->next; cl = cl->next)
814   {
815     if (cl->ic && (cl->ic!=last_ic))
816       {
817         last_ic = cl->ic;
818         switch (cl->ic->op)
819           {
820           case IFX:
821             op = IC_COND (cl->ic);
822             if (IS_SYMOP (op) &&
823                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
824                   (OP_SYMBOL (op)->isspilt &&
825                    SPIL_LOC (op) &&
826                    !strcmp(SPIL_LOC (op)->rname, symname)) ))
827               {
828                 return !op->isvolatile;
829               }
830           case JUMPTABLE:
831             op = IC_JTCOND (cl->ic);
832             if (IS_SYMOP (op) &&
833                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
834                   (OP_SYMBOL (op)->isspilt &&
835                    SPIL_LOC (op) &&
836                    !strcmp(SPIL_LOC (op)->rname, symname)) ))
837               {
838                 return !op->isvolatile;
839               }
840           default:
841             op = IC_LEFT (cl->ic);
842             if (IS_SYMOP (op) &&
843                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
844                   (OP_SYMBOL (op)->isspilt &&
845                    SPIL_LOC (op) &&
846                    !strcmp(SPIL_LOC (op)->rname, symname)) ))
847               {
848                 return !op->isvolatile;
849               }
850             op = IC_RIGHT (cl->ic);
851             if (IS_SYMOP (op) &&
852                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
853                   (OP_SYMBOL (op)->isspilt &&
854                    SPIL_LOC (op) &&
855                    !strcmp(SPIL_LOC (op)->rname, symname)) ))
856               {
857                 return !op->isvolatile;
858               }
859             op = IC_RESULT (cl->ic);
860             if (IS_SYMOP (op) &&
861                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
862                   (OP_SYMBOL (op)->isspilt &&
863                    SPIL_LOC (op) &&
864                    !strcmp(SPIL_LOC (op)->rname, symname)) ))
865               {
866                 return !op->isvolatile;
867               }
868           }
869       }
870   }
871
872   /* Couldn't find the symbol for some reason. Assume volatile. */
873   return FALSE;
874 }
875
876 /*  notVolatile:
877  *
878  *  This rule restriction has two different behaviours depending on
879  *  the number of parameters given.
880  *
881  *    if notVolatile                 (no parameters given)
882  *       The rule is applied only if none of the iCodes originating
883  *       the matched pattern reference a volatile operand.
884  *
885  *    if notVolatile %1 ...          (one or more parameters given)
886  *       The rule is applied if the parameters are not expressions
887  *       containing volatile symbols and are not pointer accesses.
888  *
889  */
890 FBYNAME (notVolatile)
891 {
892   int varNumber;
893   char *var;
894   bool notvol;
895   char *digitend;
896   lineNode *cl;
897   operand *op;
898
899   if (!cmdLine)
900     {
901       /* If no parameters given, just scan the iCodes for volatile operands */
902       for (cl = currPl; cl!=endPl->next; cl = cl->next)
903       {
904         if (cl->ic)
905           {
906             switch (cl->ic->op)
907               {
908               case IFX:
909                 op = IC_COND (cl->ic);
910                 if (IS_SYMOP (op) && op->isvolatile)
911                   return FALSE;
912               case JUMPTABLE:
913                 op = IC_JTCOND (cl->ic);
914                 if (IS_SYMOP (op) && op->isvolatile)
915                   return FALSE;
916               default:
917                 op = IC_LEFT (cl->ic);
918                 if (IS_SYMOP (op) && op->isvolatile)
919                   return FALSE;
920                 op = IC_RIGHT (cl->ic);
921                 if (IS_SYMOP (op) && op->isvolatile)
922                   return FALSE;
923                 op = IC_RESULT (cl->ic);
924                 if (IS_SYMOP (op) && op->isvolatile)
925                   return FALSE;
926               }
927           }
928       }
929       return TRUE;
930     }
931
932   /* There were parameters; check the volatility of each */
933   while (*cmdLine && ISCHARSPACE(*cmdLine))
934     cmdLine++;
935   while (*cmdLine)
936     {
937       if (*cmdLine!='%')
938         goto error;
939       cmdLine++;
940       if (!ISCHARDIGIT(*cmdLine))
941         goto error;
942       varNumber = strtol(cmdLine, &digitend, 10);
943       cmdLine = digitend;
944       while (*cmdLine && ISCHARSPACE(*cmdLine))
945         cmdLine++;
946
947       var = hTabItemWithKey (vars, varNumber);
948
949       if (var)
950         {
951           notvol = notVolatileVariable (var, currPl, endPl);
952           if (!notvol)
953             return FALSE;
954         }
955       else
956         {
957           fprintf (stderr, "*** internal error: var %d not bound"
958                    " in peephole notVolatile rule.\n",
959                    varNumber);
960           return FALSE;
961         }
962     }
963
964   return TRUE;
965
966 error:
967   fprintf (stderr,
968            "*** internal error: notVolatile peephole restriction"
969            " malformed: %s\n", cmdLine);
970   return FALSE;
971 }
972
973 /*------------------------------------------------------------------*/
974 /* setFromConditionArgs - parse a peephole condition's arguments    */
975 /* to produce a set of strings, one per argument. Variables %x will */
976 /* be replaced with their values. String literals (in single quotes)*/
977 /* are accepted and return in unquoted form.                         */
978 /*------------------------------------------------------------------*/
979 static set *
980 setFromConditionArgs (char *cmdLine, hTab * vars)
981 {
982   int varNumber;
983   char *var;
984   char *digitend;
985   set *operands = NULL;
986
987   if (!cmdLine)
988     return NULL;
989
990   while (*cmdLine && ISCHARSPACE(*cmdLine))
991     cmdLine++;
992
993   while (*cmdLine)
994     {
995       if (*cmdLine == '%')
996         {
997           cmdLine++;
998           if (!ISCHARDIGIT(*cmdLine))
999             goto error;
1000           varNumber = strtol(cmdLine, &digitend, 10);
1001           cmdLine = digitend;
1002
1003           var = hTabItemWithKey (vars, varNumber);
1004
1005           if (var)
1006             {
1007               addSetHead (&operands, var);
1008             }
1009           else
1010             goto error;
1011         }
1012       else if (*cmdLine == '\'' )
1013         {
1014           char quote = *cmdLine;
1015
1016           var = ++cmdLine;
1017           while (*cmdLine && *cmdLine != quote)
1018             cmdLine++;
1019           if (*cmdLine == quote)
1020             *cmdLine++ = '\0';
1021           else
1022             goto error;
1023           addSetHead (&operands, var);
1024         }
1025       else
1026         goto error;
1027
1028       while (*cmdLine && ISCHARSPACE(*cmdLine))
1029         cmdLine++;
1030     }
1031
1032   return operands;
1033
1034 error:
1035   deleteSet (&operands);
1036   return NULL;
1037 }
1038
1039 static const char *
1040 operandBaseName (const char *op)
1041 {
1042   if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1043     {
1044       if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1045         return "a";
1046       if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1047         return op+1;
1048     }
1049
1050   return op;
1051 }
1052
1053 /*-------------------------------------------------------------------*/
1054 /* operandsNotRelated - returns true if the condition's operands are */
1055 /* not related (taking into account register name aliases). N-way    */
1056 /* comparison performed between all operands.                        */
1057 /*-------------------------------------------------------------------*/
1058 FBYNAME (operandsNotRelated)
1059 {
1060   set *operands;
1061   const char *op1, *op2;
1062
1063   operands = setFromConditionArgs (cmdLine, vars);
1064
1065   if (!operands)
1066     {
1067       fprintf (stderr,
1068                "*** internal error: operandsNotRelated peephole restriction"
1069                " malformed: %s\n", cmdLine);
1070       return FALSE;
1071     }
1072
1073   while ((op1 = setFirstItem (operands)))
1074     {
1075       deleteSetItem (&operands, (void*)op1);
1076       op1 = operandBaseName (op1);
1077
1078       for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1079         {
1080           op2 = operandBaseName (op2);
1081           if (strcmp (op1, op2) == 0)
1082             {
1083               deleteSet (&operands);
1084               return FALSE;
1085             }
1086         }
1087     }
1088
1089   deleteSet (&operands);
1090   return TRUE;
1091 }
1092
1093 /*-------------------------------------------------------------------*/
1094 /* operandsLiteral - returns true of the condition's operands are    */
1095 /* literals.                                                         */
1096 /*-------------------------------------------------------------------*/
1097 FBYNAME (operandsLiteral)
1098 {
1099   set *operands;
1100   const char *op;
1101
1102   operands = setFromConditionArgs (cmdLine, vars);
1103
1104   if (!operands)
1105     {
1106       fprintf (stderr,
1107                "*** internal error: operandsLiteral peephole restriction"
1108                " malformed: %s\n", cmdLine);
1109       return FALSE;
1110     }
1111
1112   for (op = setFirstItem (operands); op; op = setNextItem (operands))
1113     {
1114       if (!isdigit(*op))
1115         {
1116           deleteSet (&operands);
1117           return FALSE;
1118         }
1119     }
1120
1121   deleteSet (&operands);
1122   return TRUE;
1123 }
1124
1125 static const struct ftab
1126 {
1127   char *fname;
1128   int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1129 }
1130 ftab[] =                                // sorted on the number of times used
1131 {                                       // in the peephole rules on 2007-10-29
1132   {
1133     "labelRefCount", labelRefCount                  //105
1134   },
1135   {
1136     "notVolatile", notVolatile                      //85
1137   },
1138   {
1139     "labelRefCountChange", labelRefCountChange      //74
1140   },
1141   {
1142     "labelInRange", labelInRange                    //37
1143   },
1144   {
1145     "labelJTInRange", labelJTInRange                //13
1146   },
1147   {
1148     "operandsNotRelated", operandsNotRelated        //9
1149   },
1150   {
1151     "24bitMode", flat24bitMode                      //9
1152   },
1153   {
1154     "operandsNotSame", operandsNotSame              //8
1155   },
1156   {
1157     "operandsNotSame3", operandsNotSame3
1158   },
1159   {
1160     "operandsNotSame4", operandsNotSame4
1161   },
1162   {
1163     "operandsNotSame5", operandsNotSame5
1164   },
1165   {
1166     "operandsNotSame6", operandsNotSame6
1167   },
1168   {
1169     "operandsNotSame7", operandsNotSame7
1170   },
1171   {
1172     "operandsNotSame8", operandsNotSame8
1173   },
1174   {
1175     "xramMovcOption", xramMovcOption
1176   },
1177   {
1178     "portIsDS390", portIsDS390
1179   },
1180   {
1181     "labelIsReturnOnly", labelIsReturnOnly
1182   },
1183   {
1184     "labelIsUncondJump", labelIsUncondJump
1185   },
1186   {
1187     "okToRemoveSLOC", okToRemoveSLOC
1188   },
1189   {
1190     "deadMove", deadMove
1191   },
1192   {
1193     "operandsLiteral", operandsLiteral
1194   },
1195   {
1196     "useAcallAjmp", useAcallAjmp
1197   }
1198 };
1199 /*-----------------------------------------------------------------*/
1200 /* callFuncByName - calls a function as defined in the table       */
1201 /*-----------------------------------------------------------------*/
1202 static int
1203 callFuncByName (char *fname,
1204                 hTab * vars,
1205                 lineNode * currPl,
1206                 lineNode * endPl,
1207                 lineNode * head)
1208 {
1209   int   i;
1210   char  *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1211   char  c;
1212   int   rc;
1213
1214   /* Isolate the function name part (we are passed the full condition
1215    * string including arguments)
1216    */
1217   cmdTerm = cmdCopy = Safe_strdup(fname);
1218
1219   do
1220     {
1221       funcArgs = funcName = cmdTerm;
1222       while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1223         funcArgs++;
1224       *funcArgs = '\0';  /* terminate the function name */
1225       if (c)
1226         funcArgs++;
1227
1228       /* Find the start of the arguments */
1229       if (c == ' ' || c == '\t')
1230         while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1231           funcArgs++;
1232
1233       /* If the arguments started with an opening parenthesis,  */
1234       /* use the closing parenthesis for the end of the         */
1235       /* arguments and look for the start of another condition  */
1236       /* that can optionally follow. If there was no opening    */
1237       /* parethesis, then everything that follows are arguments */
1238       /* and there can be no additional conditions.             */
1239       if (c == '(')
1240         {
1241           cmdTerm = funcArgs;
1242           while ((c = *cmdTerm) && c != ')')
1243             cmdTerm++;
1244           *cmdTerm = '\0';  /* terminate the arguments */
1245           if (c == ')')
1246             {
1247               cmdTerm++;
1248               while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1249                 cmdTerm++;
1250               if (!*cmdTerm)
1251                 cmdTerm = NULL;
1252             }
1253           else
1254             cmdTerm = NULL; /* closing parenthesis missing */
1255         }
1256       else
1257         cmdTerm = NULL;
1258
1259       if (!*funcArgs)
1260         funcArgs = NULL;
1261
1262       rc = -1;
1263       for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1264         {
1265           if (strcmp (ftab[i].fname, funcName) == 0)
1266             {
1267               rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1268               break;
1269             }
1270         }
1271
1272       if (rc == -1)
1273         {
1274           fprintf (stderr,
1275                    "could not find named function \"%s\" in "
1276                    "peephole function table\n",
1277                    funcName);
1278           // If the function couldn't be found, let's assume it's
1279           // a bad rule and refuse it.
1280           rc = FALSE;
1281           break;
1282         }
1283     }
1284   while (rc && cmdTerm);
1285
1286   Safe_free(cmdCopy);
1287
1288   return rc;
1289 }
1290
1291 /*-----------------------------------------------------------------*/
1292 /* printLine - prints a line chain into a given file               */
1293 /*-----------------------------------------------------------------*/
1294 void
1295 printLine (lineNode * head, struct dbuf_s * oBuf)
1296 {
1297   iCode *last_ic = NULL;
1298   bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1299
1300   while (head)
1301     {
1302       if (head->ic!=last_ic)
1303         {
1304           last_ic = head->ic;
1305           if (debug_iCode_tracking)
1306             {
1307               if (head->ic)
1308                 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1309                          head->ic->block, head->ic->seq);
1310               else
1311                 dbuf_append_str (oBuf, "; iCode lost\n");
1312             }
1313         }
1314
1315       /* don't indent comments & labels */
1316       if (head->line &&
1317           (head->isComment || head->isLabel)) {
1318         dbuf_printf (oBuf, "%s\n", head->line);
1319       } else {
1320         if (head->isInline && *head->line=='#') {
1321           // comment out preprocessor directives in inline asm
1322           dbuf_append_char (oBuf, ';');
1323         }
1324         dbuf_printf (oBuf, "\t%s\n", head->line);
1325       }
1326       head = head->next;
1327     }
1328 }
1329
1330 /*-----------------------------------------------------------------*/
1331 /* newPeepRule - creates a new peeprule and attach it to the root  */
1332 /*-----------------------------------------------------------------*/
1333 static peepRule *
1334 newPeepRule (lineNode * match,
1335              lineNode * replace,
1336              char *cond,
1337              int restart)
1338 {
1339   peepRule *pr;
1340
1341   pr = Safe_alloc ( sizeof (peepRule));
1342   pr->match = match;
1343   pr->replace = replace;
1344   pr->restart = restart;
1345
1346   if (cond && *cond)
1347     {
1348       pr->cond = Safe_strdup (cond);
1349     }
1350   else
1351     pr->cond = NULL;
1352
1353   pr->vars = newHashTable (100);
1354
1355   /* if root is empty */
1356   if (!rootRules)
1357     rootRules = currRule = pr;
1358   else
1359     currRule = currRule->next = pr;
1360
1361   return pr;
1362 }
1363
1364 /*-----------------------------------------------------------------*/
1365 /* newLineNode - creates a new peep line                           */
1366 /*-----------------------------------------------------------------*/
1367 lineNode *
1368 newLineNode (const char *line)
1369 {
1370   lineNode *pl;
1371
1372   pl = Safe_alloc ( sizeof (lineNode));
1373   pl->line = Safe_strdup (line);
1374   pl->ic = NULL;
1375   return pl;
1376 }
1377
1378 /*-----------------------------------------------------------------*/
1379 /* connectLine - connects two lines                                */
1380 /*-----------------------------------------------------------------*/
1381 lineNode *
1382 connectLine (lineNode * pl1, lineNode * pl2)
1383 {
1384   if (!pl1 || !pl2)
1385     {
1386       fprintf (stderr, "trying to connect null line\n");
1387       return NULL;
1388     }
1389
1390   pl2->prev = pl1;
1391   pl1->next = pl2;
1392
1393   return pl2;
1394 }
1395
1396 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1397                          if (!*x) { fprintf(stderr,y); return ; } }
1398
1399 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
1400                            if (!*x) { fprintf(stderr,z); return ; } }
1401 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
1402                            if (!*x) { fprintf(stderr,z); return ; } }
1403
1404 /*-----------------------------------------------------------------*/
1405 /* getPeepLine - parses the peep lines                             */
1406 /*-----------------------------------------------------------------*/
1407 static void
1408 getPeepLine (lineNode ** head, char **bpp)
1409 {
1410   char lines[MAX_PATTERN_LEN];
1411   char *lp;
1412   int isComment;
1413
1414   lineNode *currL = NULL;
1415   char *bp = *bpp;
1416   while (1)
1417     {
1418
1419       if (!*bp)
1420         {
1421           fprintf (stderr, "unexpected end of match pattern\n");
1422           return;
1423         }
1424
1425       if (*bp == '\n')
1426         {
1427           bp++;
1428           while (ISCHARSPACE (*bp) ||
1429                  *bp == '\n')
1430             bp++;
1431         }
1432
1433       if (*bp == '}')
1434         {
1435           bp++;
1436           break;
1437         }
1438
1439       /* read till end of line */
1440       lp = lines;
1441       while ((*bp != '\n' && *bp != '}') && *bp)
1442         *lp++ = *bp++;
1443       *lp = '\0';
1444
1445       lp = lines;
1446       while (*lp && ISCHARSPACE(*lp))
1447         lp++;
1448       isComment = (*lp == ';');
1449
1450       if (!isComment || (isComment && !options.noPeepComments))
1451         {
1452           const char *dummy1;
1453           int dummy2;
1454
1455           if (!currL)
1456             *head = currL = newLineNode (lines);
1457           else
1458             currL = connectLine (currL, newLineNode (lines));
1459           currL->isComment = isComment;
1460           currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1461                                               TRUE);
1462         }
1463
1464     }
1465
1466   *bpp = bp;
1467 }
1468
1469 /*-----------------------------------------------------------------*/
1470 /* readRules - reads the rules from a string buffer                */
1471 /*-----------------------------------------------------------------*/
1472 static void
1473 readRules (char *bp)
1474 {
1475   char restart = 0;
1476   char lines[MAX_PATTERN_LEN];
1477   char *lp, *rp;
1478   lineNode *match;
1479   lineNode *replace;
1480   lineNode *currL = NULL;
1481
1482   if (!bp)
1483     return;
1484 top:
1485   restart = 0;
1486   /* look for the token "replace" that is the
1487      start of a rule */
1488   while (*bp && strncmp (bp, "replace", 7))
1489     bp++;
1490
1491   /* if not found */
1492   if (!*bp)
1493     return;
1494
1495   /* then look for either "restart" or '{' */
1496   while (strncmp (bp, "restart", 7) &&
1497          *bp != '{' && bp)
1498     bp++;
1499
1500   /* not found */
1501   if (!*bp)
1502     {
1503       fprintf (stderr, "expected 'restart' or '{'\n");
1504       return;
1505     }
1506
1507   /* if brace */
1508   if (*bp == '{')
1509     bp++;
1510   else
1511     {                           /* must be restart */
1512       restart++;
1513       bp += strlen ("restart");
1514       /* look for '{' */
1515       EXPECT_CHR (bp, '{', "expected '{'\n");
1516       bp++;
1517     }
1518
1519   /* skip thru all the blank space */
1520   SKIP_SPACE (bp, "unexpected end of rule\n");
1521
1522   match = replace = currL = NULL;
1523   /* we are the start of a rule */
1524   getPeepLine (&match, &bp);
1525
1526   /* now look for by */
1527   EXPECT_STR (bp, "by", "expected 'by'\n");
1528
1529   /* then look for a '{' */
1530   EXPECT_CHR (bp, '{', "expected '{'\n");
1531   bp++;
1532
1533   /* save char position (needed for generating error msg) */
1534   rp = bp;
1535
1536   SKIP_SPACE (bp, "unexpected end of rule\n");
1537   getPeepLine (&replace, &bp);
1538
1539   /* look for a 'if' */
1540   while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1541     bp++;
1542
1543   if (strncmp (bp, "if", 2) == 0)
1544     {
1545       bp += 2;
1546       while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1547         bp++;
1548       if (!*bp)
1549         {
1550           fprintf (stderr, "expected condition name\n");
1551           return;
1552         }
1553
1554       /* look for the condition */
1555       lp = lines;
1556       while (*bp && (*bp != '\n'))
1557         {
1558           *lp++ = *bp++;
1559         }
1560       *lp = '\0';
1561
1562       newPeepRule (match, replace, lines, restart);
1563     }
1564   else
1565     {
1566       if (*bp && strncmp (bp, "replace", 7))
1567         {
1568           /* not the start of a new peeprule, so "if" should be here */
1569
1570           char strbuff[1000];
1571           char *cp;
1572
1573           /* go to the start of the line following "{" of the "by" token */
1574           while (*rp && (*rp == '\n'))
1575             rp++;
1576
1577           /* copy text of rule starting with line after "by {" */
1578           cp = strbuff;
1579           while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1580               *cp++ = *rp++;
1581
1582           /* and now the rest of the line */
1583           while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1584             *cp++ = *rp++;
1585
1586           *cp = '\0';
1587           fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1588           return;
1589         }
1590       newPeepRule (match, replace, NULL, restart);
1591     }
1592   goto top;
1593
1594 }
1595
1596 /*-----------------------------------------------------------------*/
1597 /* keyForVar - returns the numeric key for a var                   */
1598 /*-----------------------------------------------------------------*/
1599 static int
1600 keyForVar (char *d)
1601 {
1602   int i = 0;
1603
1604   while (ISCHARDIGIT (*d))
1605     {
1606       i *= 10;
1607       i += (*d++ - '0');
1608     }
1609
1610   return i;
1611 }
1612
1613 /*-----------------------------------------------------------------*/
1614 /* bindVar - binds a value to a variable in the given hashtable    */
1615 /*-----------------------------------------------------------------*/
1616 static void
1617 bindVar (int key, char **s, hTab ** vtab)
1618 {
1619   char vval[MAX_PATTERN_LEN];
1620   char *vvx;
1621   char *vv = vval;
1622
1623   /* first get the value of the variable */
1624   vvx = *s;
1625   /* the value is ended by a ',' or space or newline or null or ) */
1626   while (*vvx &&
1627          *vvx != ',' &&
1628          !ISCHARSPACE (*vvx) &&
1629          *vvx != '\n' &&
1630          *vvx != ':' &&
1631          *vvx != ')')
1632     {
1633       char ubb = 0;
1634       /* if we find a '(' then we need to balance it */
1635       if (*vvx == '(')
1636         {
1637           ubb++;
1638           while (ubb)
1639             {
1640               *vv++ = *vvx++;
1641               if (*vvx == '(')
1642                 ubb++;
1643               if (*vvx == ')')
1644                 ubb--;
1645             }
1646           // include the trailing ')'
1647           *vv++ = *vvx++;
1648         }
1649       else
1650         *vv++ = *vvx++;
1651     }
1652   *s = vvx;
1653   *vv = '\0';
1654   /* got value */
1655   vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1656
1657   hTabAddItem (vtab, key, vvx);
1658 }
1659
1660 /*-----------------------------------------------------------------*/
1661 /* matchLine - matches one line                                    */
1662 /*-----------------------------------------------------------------*/
1663 static bool
1664 matchLine (char *s, char *d, hTab ** vars)
1665 {
1666
1667   if (!s || !(*s))
1668     return FALSE;
1669
1670   while (*s && *d)
1671     {
1672
1673       /* skip white space in both */
1674       while (ISCHARSPACE (*s))
1675         s++;
1676       while (ISCHARSPACE (*d))
1677         d++;
1678
1679       /* if the destination is a var */
1680       if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1681         {
1682           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1683           /* if the variable is already bound
1684              then it MUST match with dest */
1685           if (v)
1686             {
1687               while (*v)
1688                 if (*v++ != *s++)
1689                   return FALSE;
1690             }
1691           else
1692             /* variable not bound we need to bind it */
1693             bindVar (keyForVar (d + 1), &s, vars);
1694
1695           /* in either case go past the variable */
1696           d++;
1697           while (ISCHARDIGIT (*d))
1698             d++;
1699
1700           while (ISCHARSPACE (*s))
1701             s++;
1702           while (ISCHARSPACE (*d))
1703             d++;
1704         }
1705
1706       /* they should be an exact match other wise */
1707       if (*s && *d)
1708         {
1709           if (*s++ != *d++)
1710             return FALSE;
1711         }
1712
1713     }
1714
1715   /* get rid of the trailing spaces
1716      in both source & destination */
1717   if (*s)
1718     while (ISCHARSPACE (*s))
1719       s++;
1720
1721   if (*d)
1722     while (ISCHARSPACE (*d))
1723       d++;
1724
1725   /* after all this if only one of them
1726      has something left over then no match */
1727   if (*s || *d)
1728     return FALSE;
1729
1730   return TRUE;
1731 }
1732
1733 /*-----------------------------------------------------------------*/
1734 /* matchRule - matches a all the rule lines                        */
1735 /*-----------------------------------------------------------------*/
1736 static bool
1737 matchRule (lineNode * pl,
1738            lineNode ** mtail,
1739            peepRule * pr,
1740            lineNode * head)
1741 {
1742   lineNode *spl;                /* source pl */
1743   lineNode *rpl;                /* rule peep line */
1744
1745 /*     setToNull((void *) &pr->vars);    */
1746 /*     pr->vars = newHashTable(100); */
1747
1748   /* for all the lines defined in the rule */
1749   rpl = pr->match;
1750   spl = pl;
1751   while (spl && rpl)
1752     {
1753
1754       /* if the source line starts with a ';' then
1755          comment line don't process or the source line
1756          contains == . debugger information skip it */
1757       if (spl->line &&
1758           (*spl->line == ';' || spl->isDebug))
1759         {
1760           spl = spl->next;
1761           continue;
1762         }
1763
1764       if (!matchLine (spl->line, rpl->line, &pr->vars))
1765         return FALSE;
1766
1767       rpl = rpl->next;
1768       if (rpl)
1769         spl = spl->next;
1770     }
1771
1772   /* if rules ended */
1773   if (!rpl)
1774     {
1775       /* if this rule has additional conditions */
1776       if (pr->cond)
1777         {
1778           if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1779             {
1780               *mtail = spl;
1781               return TRUE;
1782             }
1783           else
1784             return FALSE;
1785         }
1786       else
1787         {
1788           *mtail = spl;
1789           return TRUE;
1790         }
1791     }
1792   else
1793     return FALSE;
1794 }
1795
1796 static void
1797 reassociate_ic_down (lineNode *shead, lineNode *stail,
1798                      lineNode *rhead, lineNode *rtail)
1799 {
1800   lineNode *csl;        /* current source line */
1801   lineNode *crl;        /* current replacement line */
1802
1803   csl = shead;
1804   crl = rhead;
1805   while (1)
1806     {
1807       /* skip over any comments */
1808       while (csl!=stail->next && csl->isComment)
1809         csl = csl->next;
1810       while (crl!=rtail->next && crl->isComment)
1811         crl = crl->next;
1812
1813       /* quit if we reach the end */
1814       if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1815         break;
1816
1817       if (matchLine(csl->line,crl->line,NULL))
1818         {
1819           crl->ic = csl->ic;
1820           csl = csl->next;
1821           crl = crl->next;
1822         }
1823       else
1824         break;
1825     }
1826 }
1827
1828 static void
1829 reassociate_ic_up (lineNode *shead, lineNode *stail,
1830                    lineNode *rhead, lineNode *rtail)
1831 {
1832   lineNode *csl;        /* current source line */
1833   lineNode *crl;        /* current replacement line */
1834
1835   csl = stail;
1836   crl = rtail;
1837   while (1)
1838     {
1839       /* skip over any comments */
1840       while (csl!=shead->prev && csl->isComment)
1841         csl = csl->prev;
1842       while (crl!=rhead->prev && crl->isComment)
1843         crl = crl->prev;
1844
1845       /* quit if we reach the end */
1846       if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1847         break;
1848
1849       if (matchLine(csl->line,crl->line,NULL))
1850         {
1851           crl->ic = csl->ic;
1852           csl = csl->prev;
1853           crl = crl->prev;
1854         }
1855       else
1856         break;
1857     }
1858 }
1859
1860 /*------------------------------------------------------------------*/
1861 /* reassociate_ic - reassociate replacement lines with origin iCode */
1862 /*------------------------------------------------------------------*/
1863 static void
1864 reassociate_ic (lineNode *shead, lineNode *stail,
1865                 lineNode *rhead, lineNode *rtail)
1866 {
1867   lineNode *csl;        /* current source line */
1868   lineNode *crl;        /* current replacement line */
1869   bool single_iCode;
1870   iCode *ic;
1871
1872   /* Check to see if all the source lines (excluding comments) came
1873   ** for the same iCode
1874   */
1875   ic = NULL;
1876   for (csl=shead;csl!=stail->next;csl=csl->next)
1877     if (csl->ic && !csl->isComment)
1878       {
1879         ic = csl->ic;
1880         break;
1881       }
1882   single_iCode = (ic!=NULL);
1883   for (csl=shead;csl!=stail->next;csl=csl->next)
1884     if ((csl->ic != ic) && !csl->isComment)
1885       {
1886         /* More than one iCode was found. However, if it's just the
1887         ** last line with the different iCode and it was not changed
1888         ** in the replacement, everything else must be the first iCode.
1889         */
1890         if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1891           {
1892             rtail->ic = stail->ic;
1893             for (crl=rhead;crl!=rtail;crl=crl->next)
1894               crl->ic = ic;
1895             return;
1896           }
1897
1898         single_iCode = FALSE;
1899         break;
1900       }
1901
1902   /* If all of the source lines came from the same iCode, then so have
1903   ** all of the replacement lines too.
1904   */
1905   if (single_iCode)
1906     {
1907       for (crl=rhead;crl!=rtail->next;crl=crl->next)
1908         crl->ic = ic;
1909       return;
1910     }
1911
1912   /* The source lines span iCodes, so we may end up with replacement
1913   ** lines that we don't know which iCode(s) to associate with. Do the
1914   ** best we can by using the following strategies:
1915   **    1) Start at the top and scan down. As long as the source line
1916   **       matches the replacement line, they have the same iCode.
1917   **    2) Start at the bottom and scan up. As long as the source line
1918   **       matches the replacement line, they have the same iCode.
1919   **    3) For any label in the source, look for a matching label in
1920   **       the replacment. If found, they have the same iCode. From
1921   **       these matching labels, scan down for additional matching
1922   **       lines; if found, they also have the same iCode.
1923   */
1924
1925   /* Strategy #1: Start at the top and scan down for matches
1926   */
1927   reassociate_ic_down(shead,stail,rhead,rtail);
1928
1929   /* Strategy #2: Start at the bottom and scan up for matches
1930   */
1931   reassociate_ic_up(shead,stail,rhead,rtail);
1932
1933   /* Strategy #3: Try to match labels
1934   */
1935   csl = shead;
1936   while (1)
1937     {
1938       /* skip over any comments */
1939       while (csl!=stail->next && csl->isComment)
1940         csl = csl->next;
1941       if (csl==stail->next)
1942         break;
1943
1944       if (csl->isLabel)
1945         {
1946           /* found a source line label; look for it in the replacment lines */
1947           crl = rhead;
1948           while (1)
1949             {
1950               while (crl!=rtail->next && crl->isComment)
1951                 crl = crl->next;
1952               if (crl==rtail->next)
1953                 break;
1954               if (matchLine(csl->line, crl->line, NULL))
1955                 {
1956                   reassociate_ic_down(csl,stail,crl,rtail);
1957                   break;
1958                 }
1959               else
1960                 crl = crl->next;
1961             }
1962         }
1963       csl = csl->next;
1964     }
1965
1966   /* Try to assign a meaningful iCode to any comment that is missing
1967      one. Since they are comments, it's ok to make mistakes; we are just
1968      trying to improve continuity to simplify other tests.
1969   */
1970   ic = NULL;
1971   for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1972     {
1973       if (!crl->ic && ic && crl->isComment)
1974         crl->ic = ic;
1975       ic = crl->ic;
1976     }
1977 }
1978
1979
1980 /*-----------------------------------------------------------------*/
1981 /* replaceRule - does replacement of a matching pattern            */
1982 /*-----------------------------------------------------------------*/
1983 static void
1984 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1985 {
1986   lineNode *cl = NULL;
1987   lineNode *pl = NULL, *lhead = NULL;
1988   /* a long function name and long variable name can evaluate to
1989      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1990   char lb[MAX_PATTERN_LEN*4];
1991   char *lbp;
1992   lineNode *comment = NULL;
1993
1994   /* collect all the comment lines in the source */
1995   for (cl = *shead; cl != stail; cl = cl->next)
1996     {
1997       if (cl->line && (*cl->line == ';' || cl->isDebug))
1998         {
1999           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2000                 (comment = newLineNode (cl->line)));
2001           pl->isDebug = cl->isDebug;
2002           pl->isComment = cl->isComment || (*cl->line == ';');
2003         }
2004     }
2005   cl = NULL;
2006
2007   /* for all the lines in the replacement pattern do */
2008   for (pl = pr->replace; pl; pl = pl->next)
2009     {
2010       char *v;
2011       char *l;
2012       lbp = lb;
2013
2014       l = pl->line;
2015
2016       while (*l)
2017         {
2018           /* if the line contains a variable */
2019           if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2020             {
2021               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2022               if (!v)
2023                 {
2024                   fprintf (stderr, "used unbound variable in replacement\n");
2025                   l++;
2026                   continue;
2027                 }
2028               while (*v) {
2029                 *lbp++ = *v++;
2030               }
2031               l++;
2032               while (ISCHARDIGIT (*l)) {
2033                 l++;
2034               }
2035               continue;
2036             }
2037           *lbp++ = *l++;
2038         }
2039
2040       *lbp = '\0';
2041       if (cl)
2042         cl = connectLine (cl, newLineNode (lb));
2043       else
2044         lhead = cl = newLineNode (lb);
2045       cl->isComment = pl->isComment;
2046       cl->isLabel   = pl->isLabel;
2047     }
2048
2049   /* add the comments if any to the head of list */
2050   if (comment)
2051     {
2052       lineNode *lc = comment;
2053       while (lc->next)
2054         lc = lc->next;
2055       lc->next = lhead;
2056       if (lhead)
2057         lhead->prev = lc;
2058       lhead = comment;
2059     }
2060
2061   if (lhead)
2062     {
2063       /* determine which iCodes the replacment lines relate to */
2064       reassociate_ic(*shead,stail,lhead,cl);
2065
2066       /* now we need to connect / replace the original chain */
2067       /* if there is a prev then change it */
2068       if ((*shead)->prev)
2069         {
2070           (*shead)->prev->next = lhead;
2071           lhead->prev = (*shead)->prev;
2072         }
2073       *shead = lhead;
2074       /* now for the tail */
2075       if (stail && stail->next)
2076         {
2077           stail->next->prev = cl;
2078           if (cl)
2079             cl->next = stail->next;
2080         }
2081     }
2082   else
2083     {
2084       /* the replacement is empty - delete the source lines */
2085       if ((*shead)->prev)
2086         (*shead)->prev->next = stail->next;
2087       if (stail->next)
2088         stail->next->prev = (*shead)->prev;
2089       *shead = stail->next;
2090     }
2091 }
2092
2093 /* Returns TRUE if this line is a label definition.
2094
2095  * If so, start will point to the start of the label name,
2096  * and len will be it's length.
2097  */
2098 bool
2099 isLabelDefinition (const char *line, const char **start, int *len,
2100                    bool isPeepRule)
2101 {
2102   const char *cp = line;
2103
2104   /* This line is a label if if consists of:
2105    * [optional whitespace] followed by identifier chars
2106    * (alnum | $ | _ ) followed by a colon.
2107    */
2108
2109   while (*cp && ISCHARSPACE (*cp))
2110     {
2111       cp++;
2112     }
2113
2114   if (!*cp)
2115     {
2116       return FALSE;
2117     }
2118
2119   *start = cp;
2120
2121   while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2122          (isPeepRule && (*cp == '%')))
2123     {
2124       cp++;
2125     }
2126
2127   if ((cp == *start) || (*cp != ':'))
2128     {
2129       return FALSE;
2130     }
2131
2132   *len = (cp - (*start));
2133   return TRUE;
2134 }
2135
2136 /* Quick & dirty string hash function. */
2137 static int
2138 hashSymbolName (const char *name)
2139 {
2140   int hash = 0;
2141
2142   while (*name)
2143     {
2144       hash = (hash << 6) ^ *name;
2145       name++;
2146     }
2147
2148   if (hash < 0)
2149     {
2150       hash = -hash;
2151     }
2152
2153   return hash % HTAB_SIZE;
2154 }
2155
2156 /* Build a hash of all labels in the passed set of lines
2157  * and how many times they are referenced.
2158  */
2159 static void
2160 buildLabelRefCountHash (lineNode * head)
2161 {
2162   lineNode *line;
2163   const char *label;
2164   int labelLen;
2165   int i;
2166
2167   assert (labelHash == NULL);
2168   labelHash = newHashTable (HTAB_SIZE);
2169
2170   /* First pass: locate all the labels. */
2171   for (line = head; line; line = line->next)
2172     {
2173       if (line->isLabel  ||
2174           line->isInline)
2175         {
2176           /* run isLabelDefinition to:
2177              - look for labels in inline assembler
2178              - calculate labelLen
2179           */
2180           if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2181               labelLen <= SDCC_NAME_MAX)
2182             {
2183               labelHashEntry *entry;
2184
2185               entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2186
2187               memcpy (entry->name, label, labelLen);
2188               entry->name[labelLen] = 0;
2189               entry->refCount = -1;
2190
2191               /* Assume function entry points are referenced somewhere,   */
2192               /* even if we can't find a reference (might be from outside */
2193               /* the function) */
2194               if (line->ic && (line->ic->op == FUNCTION))
2195                 entry->refCount++;
2196
2197               hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2198             }
2199         }
2200     }
2201
2202
2203   /* Second pass: for each line, note all the referenced labels. */
2204   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2205   line = head;
2206   while (line)
2207     {
2208       for (i = 0; i < HTAB_SIZE; i++)
2209         {
2210           labelHashEntry *thisEntry;
2211
2212           thisEntry = hTabFirstItemWK (labelHash, i);
2213
2214           while (thisEntry)
2215             {
2216               if (strstr (line->line, thisEntry->name))
2217                 {
2218                   thisEntry->refCount++;
2219                 }
2220               thisEntry = hTabNextItemWK (labelHash);
2221             }
2222         }
2223       line = line->next;
2224     }
2225
2226 #if 0
2227   /* Spew the contents of the table. Debugging fun only. */
2228   for (i = 0; i < HTAB_SIZE; i++)
2229     {
2230       labelHashEntry *thisEntry;
2231
2232       thisEntry = hTabFirstItemWK (labelHash, i);
2233
2234       while (thisEntry)
2235         {
2236           fprintf (stderr, "label: %s ref %d\n",
2237                    thisEntry->name, thisEntry->refCount);
2238           thisEntry = hTabNextItemWK (labelHash);
2239         }
2240     }
2241 #endif
2242 }
2243
2244 /* How does this work?
2245    peepHole
2246     For each rule,
2247      For each line,
2248       Try to match
2249       If it matches,
2250        replace and restart.
2251
2252     matchRule
2253      matchLine
2254
2255   Where is stuff allocated?
2256
2257 */
2258
2259 /*-----------------------------------------------------------------*/
2260 /* peepHole - matches & substitutes rules                          */
2261 /*-----------------------------------------------------------------*/
2262 void
2263 peepHole (lineNode ** pls)
2264 {
2265   lineNode *spl;
2266   peepRule *pr;
2267   lineNode *mtail = NULL;
2268   bool restart, replaced;
2269
2270 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2271   /* The PIC port uses a different peep hole optimizer based on "pCode" */
2272   if (TARGET_IS_PIC || TARGET_IS_PIC16)
2273     return;
2274 #endif
2275
2276   assert(labelHash == NULL);
2277
2278   do
2279     {
2280       restart = FALSE;
2281
2282       /* for all rules */
2283       for (pr = rootRules; pr; pr = pr->next)
2284         {
2285           for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2286             {
2287               replaced = FALSE;
2288
2289               /* if inline assembler then no peep hole */
2290               if (spl->isInline)
2291                 continue;
2292
2293               /* don't waste time starting a match on debug symbol
2294               ** or comment */
2295               if (spl->isDebug || spl->isComment || *(spl->line)==';')
2296                 continue;
2297
2298               mtail = NULL;
2299
2300               /* Tidy up any data stored in the hTab */
2301
2302               /* if it matches */
2303               if (matchRule (spl, &mtail, pr, *pls))
2304                 {
2305                   /* restart at the replaced line */
2306                   replaced = TRUE;
2307
2308                   /* then replace */
2309                   if (spl == *pls)
2310                     {
2311                       replaceRule (pls, mtail, pr);
2312                       spl = *pls;
2313                     }
2314                   else
2315                     replaceRule (&spl, mtail, pr);
2316
2317                   /* if restart rule type then
2318                      start at the top again */
2319                   if (pr->restart)
2320                     {
2321                       restart = TRUE;
2322                     }
2323                 }
2324
2325               if (pr->vars)
2326                 {
2327                   hTabDeleteAll (pr->vars);
2328                   Safe_free (pr->vars);
2329                   pr->vars = NULL;
2330                 }
2331
2332               freeTrace (&_G.values);
2333             }
2334         }
2335     } while (restart == TRUE);
2336
2337   if (labelHash)
2338     {
2339       hTabDeleteAll (labelHash);
2340       freeTrace (&_G.labels);
2341     }
2342   labelHash = NULL;
2343 }
2344
2345
2346 /*-----------------------------------------------------------------*/
2347 /* readFileIntoBuffer - reads a file into a string buffer          */
2348 /*-----------------------------------------------------------------*/
2349 static char *
2350 readFileIntoBuffer (char *fname)
2351 {
2352   FILE *f;
2353   char *rs = NULL;
2354   int nch = 0;
2355   int ch;
2356   char lb[MAX_PATTERN_LEN];
2357
2358   if (!(f = fopen (fname, "r")))
2359     {
2360       fprintf (stderr, "cannot open peep rule file\n");
2361       return NULL;
2362     }
2363
2364   while ((ch = fgetc (f)) != EOF)
2365     {
2366       lb[nch++] = ch;
2367
2368       /* if we maxed out our local buffer */
2369       if (nch >= (MAX_PATTERN_LEN - 2))
2370         {
2371           lb[nch] = '\0';
2372           /* copy it into allocated buffer */
2373           if (rs)
2374             {
2375               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2376               strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
2377             }
2378           else
2379             {
2380               rs = Safe_strdup (lb);
2381             }
2382           nch = 0;
2383         }
2384     }
2385
2386   /* if some charaters left over */
2387   if (nch)
2388     {
2389       lb[nch] = '\0';
2390       /* copy it into allocated buffer */
2391       if (rs)
2392         {
2393           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2394           strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2395         }
2396       else
2397         {
2398           rs = Safe_strdup (lb);
2399         }
2400     }
2401   return rs;
2402 }
2403
2404 /*-----------------------------------------------------------------*/
2405 /* initPeepHole - initialises the peep hole optimizer stuff        */
2406 /*-----------------------------------------------------------------*/
2407 void
2408 initPeepHole ()
2409 {
2410   char *s;
2411
2412   /* read in the default rules */
2413   if (!options.nopeep)
2414     {
2415       readRules (port->peep.default_rules);
2416     }
2417
2418   /* if we have any additional file read it too */
2419   if (options.peep_file)
2420     {
2421       readRules (s = readFileIntoBuffer (options.peep_file));
2422       setToNull ((void *) &s);
2423       /* override nopeep setting, default rules have not been read */
2424       options.nopeep = 0;
2425     }
2426
2427
2428 #if !OPT_DISABLE_PIC
2429   /* Convert the peep rules into pcode.
2430      NOTE: this is only support in the PIC port (at the moment)
2431   */
2432         if (TARGET_IS_PIC)
2433                 peepRules2pCode(rootRules);
2434 #endif
2435
2436 #if !OPT_DISABLE_PIC16
2437   /* Convert the peep rules into pcode.
2438      NOTE: this is only support in the PIC port (at the moment)
2439        and the PIC16 port (VR 030601)
2440   */
2441         if (TARGET_IS_PIC16)
2442                 pic16_peepRules2pCode(rootRules);
2443
2444 #endif
2445
2446 }