* src/ds390/peeph.def: replaced 24bitModeAndPortDS390 by
[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 && !strcmp(SPIL_LOC (op)->rname, symname)) ))
825               {
826                 return !op->isvolatile;
827               }
828           case JUMPTABLE:
829             op = IC_JTCOND (cl->ic);
830             if (IS_SYMOP (op) &&
831                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
832                   (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
833               {
834                 return !op->isvolatile;
835               }
836           default:
837             op = IC_LEFT (cl->ic);
838             if (IS_SYMOP (op) &&
839                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
840                   (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
841               {
842                 return !op->isvolatile;
843               }
844             op = IC_RIGHT (cl->ic);
845             if (IS_SYMOP (op) &&
846                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
847                   (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
848               {
849                 return !op->isvolatile;
850               }
851             op = IC_RESULT (cl->ic);
852             if (IS_SYMOP (op) &&
853                 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
854                   (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
855               {
856                 return !op->isvolatile;
857               }
858           }
859       }
860   }
861
862   /* Couldn't find the symbol for some reason. Assume volatile. */
863   return FALSE;
864 }
865
866 /*  notVolatile:
867  *
868  *  This rule restriction has two different behaviours depending on
869  *  the number of parameters given.
870  *
871  *    if notVolatile                 (no parameters given)
872  *       The rule is applied only if none of the iCodes originating
873  *       the matched pattern reference a volatile operand.
874  *
875  *    if notVolatile %1 ...          (one or more parameters given)
876  *       The rule is applied if the parameters are not expressions
877  *       containing volatile symbols and are not pointer accesses.
878  *
879  */
880 FBYNAME (notVolatile)
881 {
882   int varNumber;
883   char *var;
884   bool notvol;
885   char *digitend;
886   lineNode *cl;
887   operand *op;
888
889   if (!cmdLine)
890     {
891       /* If no parameters given, just scan the iCodes for volatile operands */
892       for (cl = currPl; cl!=endPl->next; cl = cl->next)
893       {
894         if (cl->ic)
895           {
896             switch (cl->ic->op)
897               {
898               case IFX:
899                 op = IC_COND (cl->ic);
900                 if (IS_SYMOP (op) && op->isvolatile)
901                   return FALSE;
902               case JUMPTABLE:
903                 op = IC_JTCOND (cl->ic);
904                 if (IS_SYMOP (op) && op->isvolatile)
905                   return FALSE;
906               default:
907                 op = IC_LEFT (cl->ic);
908                 if (IS_SYMOP (op) && op->isvolatile)
909                   return FALSE;
910                 op = IC_RIGHT (cl->ic);
911                 if (IS_SYMOP (op) && op->isvolatile)
912                   return FALSE;
913                 op = IC_RESULT (cl->ic);
914                 if (IS_SYMOP (op) && op->isvolatile)
915                   return FALSE;
916               }
917           }
918       }
919       return TRUE;
920     }
921
922   /* There were parameters; check the volatility of each */
923   while (*cmdLine && ISCHARSPACE(*cmdLine))
924     cmdLine++;
925   while (*cmdLine)
926     {
927       if (*cmdLine!='%')
928         goto error;
929       cmdLine++;
930       if (!ISCHARDIGIT(*cmdLine))
931         goto error;
932       varNumber = strtol(cmdLine, &digitend, 10);
933       cmdLine = digitend;
934       while (*cmdLine && ISCHARSPACE(*cmdLine))
935         cmdLine++;
936
937       var = hTabItemWithKey (vars, varNumber);
938
939       if (var)
940         {
941           notvol = notVolatileVariable (var, currPl, endPl);
942           if (!notvol)
943             return FALSE;
944         }
945       else
946         {
947           fprintf (stderr, "*** internal error: var %d not bound"
948                    " in peephole notVolatile rule.\n",
949                    varNumber);
950           return FALSE;
951         }
952     }
953
954   return TRUE;
955
956 error:
957   fprintf (stderr,
958            "*** internal error: notVolatile peephole restriction"
959            " malformed: %s\n", cmdLine);
960   return FALSE;
961 }
962
963 /*------------------------------------------------------------------*/
964 /* setFromConditionArgs - parse a peephole condition's arguments    */
965 /* to produce a set of strings, one per argument. Variables %x will */
966 /* be replaced with their values. String literals (in single quotes)*/
967 /* are accepted and return in unquoted form.                         */
968 /*------------------------------------------------------------------*/
969 static set *
970 setFromConditionArgs (char *cmdLine, hTab * vars)
971 {
972   int varNumber;
973   char *var;
974   char *digitend;
975   set *operands = NULL;
976
977   if (!cmdLine)
978     return NULL;
979
980   while (*cmdLine && ISCHARSPACE(*cmdLine))
981     cmdLine++;
982
983   while (*cmdLine)
984     {
985       if (*cmdLine == '%')
986         {
987           cmdLine++;
988           if (!ISCHARDIGIT(*cmdLine))
989             goto error;
990           varNumber = strtol(cmdLine, &digitend, 10);
991           cmdLine = digitend;
992
993           var = hTabItemWithKey (vars, varNumber);
994
995           if (var)
996             {
997               addSetHead (&operands, var);
998             }
999           else
1000             goto error;
1001         }
1002       else if (*cmdLine == '\'' )
1003         {
1004           char quote = *cmdLine;
1005
1006           var = ++cmdLine;
1007           while (*cmdLine && *cmdLine != quote)
1008             cmdLine++;
1009           if (*cmdLine == quote)
1010             *cmdLine++ = '\0';
1011           else
1012             goto error;
1013           addSetHead (&operands, var);
1014         }
1015       else
1016         goto error;
1017
1018       while (*cmdLine && ISCHARSPACE(*cmdLine))
1019         cmdLine++;
1020     }
1021
1022   return operands;
1023
1024 error:
1025   deleteSet (&operands);
1026   return NULL;
1027 }
1028
1029 static const char *
1030 operandBaseName (const char *op)
1031 {
1032   if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1033     {
1034       if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1035         return "a";
1036       if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1037         return op+1;
1038     }
1039
1040   return op;
1041 }
1042
1043 /*-------------------------------------------------------------------*/
1044 /* operandsNotRelated - returns true if the condition's operands are */
1045 /* not related (taking into account register name aliases). N-way    */
1046 /* comparison performed between all operands.                        */
1047 /*-------------------------------------------------------------------*/
1048 FBYNAME (operandsNotRelated)
1049 {
1050   set *operands;
1051   const char *op1, *op2;
1052
1053   operands = setFromConditionArgs (cmdLine, vars);
1054
1055   if (!operands)
1056     {
1057       fprintf (stderr,
1058                "*** internal error: operandsNotRelated peephole restriction"
1059                " malformed: %s\n", cmdLine);
1060       return FALSE;
1061     }
1062
1063   while ((op1 = setFirstItem (operands)))
1064     {
1065       deleteSetItem (&operands, (void*)op1);
1066       op1 = operandBaseName (op1);
1067
1068       for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1069         {
1070           op2 = operandBaseName (op2);
1071           if (strcmp (op1, op2) == 0)
1072             {
1073               deleteSet (&operands);
1074               return FALSE;
1075             }
1076         }
1077     }
1078
1079   deleteSet (&operands);
1080   return TRUE;
1081 }
1082
1083 /*-------------------------------------------------------------------*/
1084 /* operandsLiteral - returns true of the condition's operands are    */
1085 /* literals.                                                         */
1086 /*-------------------------------------------------------------------*/
1087 FBYNAME (operandsLiteral)
1088 {
1089   set *operands;
1090   const char *op;
1091
1092   operands = setFromConditionArgs (cmdLine, vars);
1093
1094   if (!operands)
1095     {
1096       fprintf (stderr,
1097                "*** internal error: operandsLiteral peephole restriction"
1098                " malformed: %s\n", cmdLine);
1099       return FALSE;
1100     }
1101
1102   for (op = setFirstItem (operands); op; op = setNextItem (operands))
1103     {
1104       if (!isdigit(*op))
1105         {
1106           deleteSet (&operands);
1107           return FALSE;
1108         }
1109     }
1110
1111   deleteSet (&operands);
1112   return TRUE;
1113 }
1114
1115 static const struct ftab
1116 {
1117   char *fname;
1118   int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1119 }
1120 ftab[] =                                // sorted on the number of times used
1121 {                                       // in the peephole rules on 2007-10-29
1122   {
1123     "labelRefCount", labelRefCount                  //105
1124   },
1125   {
1126     "notVolatile", notVolatile                      //85
1127   },
1128   {
1129     "labelRefCountChange", labelRefCountChange      //74
1130   },
1131   {
1132     "labelInRange", labelInRange                    //37
1133   },
1134   {
1135     "labelJTInRange", labelJTInRange                //13
1136   },
1137   {
1138     "operandsNotRelated", operandsNotRelated        //9
1139   },
1140   {
1141     "24bitMode", flat24bitMode                      //9
1142   },
1143   {
1144     "operandsNotSame", operandsNotSame              //8
1145   },
1146   {
1147     "operandsNotSame3", operandsNotSame3
1148   },
1149   {
1150     "operandsNotSame4", operandsNotSame4
1151   },
1152   {
1153     "operandsNotSame5", operandsNotSame5
1154   },
1155   {
1156     "operandsNotSame6", operandsNotSame6
1157   },
1158   {
1159     "operandsNotSame7", operandsNotSame7
1160   },
1161   {
1162     "operandsNotSame8", operandsNotSame8
1163   },
1164   {
1165     "xramMovcOption", xramMovcOption
1166   },
1167   {
1168     "portIsDS390", portIsDS390
1169   },
1170   {
1171     "labelIsReturnOnly", labelIsReturnOnly
1172   },
1173   {
1174     "labelIsUncondJump", labelIsUncondJump
1175   },
1176   {
1177     "okToRemoveSLOC", okToRemoveSLOC
1178   },
1179   {
1180     "deadMove", deadMove
1181   },
1182   {
1183     "operandsLiteral", operandsLiteral
1184   },
1185   {
1186     "useAcallAjmp", useAcallAjmp
1187   }
1188 };
1189 /*-----------------------------------------------------------------*/
1190 /* callFuncByName - calls a function as defined in the table       */
1191 /*-----------------------------------------------------------------*/
1192 static int
1193 callFuncByName (char *fname,
1194                 hTab * vars,
1195                 lineNode * currPl,
1196                 lineNode * endPl,
1197                 lineNode * head)
1198 {
1199   int   i;
1200   char  *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1201   char  c;
1202   int   rc;
1203
1204   /* Isolate the function name part (we are passed the full condition
1205    * string including arguments)
1206    */
1207   cmdTerm = cmdCopy = Safe_strdup(fname);
1208
1209   do
1210     {
1211       funcArgs = funcName = cmdTerm;
1212       while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1213         funcArgs++;
1214       *funcArgs = '\0';  /* terminate the function name */
1215       if (c)
1216         funcArgs++;
1217
1218       /* Find the start of the arguments */
1219       if (c == ' ' || c == '\t')
1220         while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1221           funcArgs++;
1222
1223       /* If the arguments started with an opening parenthesis,  */
1224       /* use the closing parenthesis for the end of the         */
1225       /* arguments and look for the start of another condition  */
1226       /* that can optionally follow. If there was no opening    */
1227       /* parethesis, then everything that follows are arguments */
1228       /* and there can be no additional conditions.             */
1229       if (c == '(')
1230         {
1231           cmdTerm = funcArgs;
1232           while ((c = *cmdTerm) && c != ')')
1233             cmdTerm++;
1234           *cmdTerm = '\0';  /* terminate the arguments */
1235           if (c == ')')
1236             {
1237               cmdTerm++;
1238               while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1239                 cmdTerm++;
1240               if (!*cmdTerm)
1241                 cmdTerm = NULL;
1242             }
1243           else
1244             cmdTerm = NULL; /* closing parenthesis missing */
1245         }
1246       else
1247         cmdTerm = NULL;
1248
1249       if (!*funcArgs)
1250         funcArgs = NULL;
1251
1252       rc = -1;
1253       for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1254         {
1255           if (strcmp (ftab[i].fname, funcName) == 0)
1256             {
1257               rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1258               break;
1259             }
1260         }
1261
1262       if (rc == -1)
1263         {
1264           fprintf (stderr,
1265                    "could not find named function \"%s\" in "
1266                    "peephole function table\n",
1267                    funcName);
1268           // If the function couldn't be found, let's assume it's
1269           // a bad rule and refuse it.
1270           rc = FALSE;
1271           break;
1272         }
1273     }
1274   while (rc && cmdTerm);
1275
1276   Safe_free(cmdCopy);
1277
1278   return rc;
1279 }
1280
1281 /*-----------------------------------------------------------------*/
1282 /* printLine - prints a line chain into a given file               */
1283 /*-----------------------------------------------------------------*/
1284 void
1285 printLine (lineNode * head, struct dbuf_s * oBuf)
1286 {
1287   iCode *last_ic = NULL;
1288   bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1289
1290   while (head)
1291     {
1292       if (head->ic!=last_ic)
1293         {
1294           last_ic = head->ic;
1295           if (debug_iCode_tracking)
1296             {
1297               if (head->ic)
1298                 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1299                          head->ic->block, head->ic->seq);
1300               else
1301                 dbuf_append_str (oBuf, "; iCode lost\n");
1302             }
1303         }
1304
1305       /* don't indent comments & labels */
1306       if (head->line &&
1307           (head->isComment || head->isLabel)) {
1308         dbuf_printf (oBuf, "%s\n", head->line);
1309       } else {
1310         if (head->isInline && *head->line=='#') {
1311           // comment out preprocessor directives in inline asm
1312           dbuf_append_char (oBuf, ';');
1313         }
1314         dbuf_printf (oBuf, "\t%s\n", head->line);
1315       }
1316       head = head->next;
1317     }
1318 }
1319
1320 /*-----------------------------------------------------------------*/
1321 /* newPeepRule - creates a new peeprule and attach it to the root  */
1322 /*-----------------------------------------------------------------*/
1323 static peepRule *
1324 newPeepRule (lineNode * match,
1325              lineNode * replace,
1326              char *cond,
1327              int restart)
1328 {
1329   peepRule *pr;
1330
1331   pr = Safe_alloc ( sizeof (peepRule));
1332   pr->match = match;
1333   pr->replace = replace;
1334   pr->restart = restart;
1335
1336   if (cond && *cond)
1337     {
1338       pr->cond = Safe_strdup (cond);
1339     }
1340   else
1341     pr->cond = NULL;
1342
1343   pr->vars = newHashTable (100);
1344
1345   /* if root is empty */
1346   if (!rootRules)
1347     rootRules = currRule = pr;
1348   else
1349     currRule = currRule->next = pr;
1350
1351   return pr;
1352 }
1353
1354 /*-----------------------------------------------------------------*/
1355 /* newLineNode - creates a new peep line                           */
1356 /*-----------------------------------------------------------------*/
1357 lineNode *
1358 newLineNode (const char *line)
1359 {
1360   lineNode *pl;
1361
1362   pl = Safe_alloc ( sizeof (lineNode));
1363   pl->line = Safe_strdup (line);
1364   pl->ic = NULL;
1365   return pl;
1366 }
1367
1368 /*-----------------------------------------------------------------*/
1369 /* connectLine - connects two lines                                */
1370 /*-----------------------------------------------------------------*/
1371 lineNode *
1372 connectLine (lineNode * pl1, lineNode * pl2)
1373 {
1374   if (!pl1 || !pl2)
1375     {
1376       fprintf (stderr, "trying to connect null line\n");
1377       return NULL;
1378     }
1379
1380   pl2->prev = pl1;
1381   pl1->next = pl2;
1382
1383   return pl2;
1384 }
1385
1386 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1387                          if (!*x) { fprintf(stderr,y); return ; } }
1388
1389 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
1390                            if (!*x) { fprintf(stderr,z); return ; } }
1391 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
1392                            if (!*x) { fprintf(stderr,z); return ; } }
1393
1394 /*-----------------------------------------------------------------*/
1395 /* getPeepLine - parses the peep lines                             */
1396 /*-----------------------------------------------------------------*/
1397 static void
1398 getPeepLine (lineNode ** head, char **bpp)
1399 {
1400   char lines[MAX_PATTERN_LEN];
1401   char *lp;
1402   int isComment;
1403
1404   lineNode *currL = NULL;
1405   char *bp = *bpp;
1406   while (1)
1407     {
1408
1409       if (!*bp)
1410         {
1411           fprintf (stderr, "unexpected end of match pattern\n");
1412           return;
1413         }
1414
1415       if (*bp == '\n')
1416         {
1417           bp++;
1418           while (ISCHARSPACE (*bp) ||
1419                  *bp == '\n')
1420             bp++;
1421         }
1422
1423       if (*bp == '}')
1424         {
1425           bp++;
1426           break;
1427         }
1428
1429       /* read till end of line */
1430       lp = lines;
1431       while ((*bp != '\n' && *bp != '}') && *bp)
1432         *lp++ = *bp++;
1433       *lp = '\0';
1434
1435       lp = lines;
1436       while (*lp && ISCHARSPACE(*lp))
1437         lp++;
1438       isComment = (*lp == ';');
1439
1440       if (!isComment || (isComment && !options.noPeepComments))
1441         {
1442           const char *dummy1;
1443           int dummy2;
1444
1445           if (!currL)
1446             *head = currL = newLineNode (lines);
1447           else
1448             currL = connectLine (currL, newLineNode (lines));
1449           currL->isComment = isComment;
1450           currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1451                                               TRUE);
1452         }
1453
1454     }
1455
1456   *bpp = bp;
1457 }
1458
1459 /*-----------------------------------------------------------------*/
1460 /* readRules - reads the rules from a string buffer                */
1461 /*-----------------------------------------------------------------*/
1462 static void
1463 readRules (char *bp)
1464 {
1465   char restart = 0;
1466   char lines[MAX_PATTERN_LEN];
1467   char *lp, *rp;
1468   lineNode *match;
1469   lineNode *replace;
1470   lineNode *currL = NULL;
1471
1472   if (!bp)
1473     return;
1474 top:
1475   restart = 0;
1476   /* look for the token "replace" that is the
1477      start of a rule */
1478   while (*bp && strncmp (bp, "replace", 7))
1479     bp++;
1480
1481   /* if not found */
1482   if (!*bp)
1483     return;
1484
1485   /* then look for either "restart" or '{' */
1486   while (strncmp (bp, "restart", 7) &&
1487          *bp != '{' && bp)
1488     bp++;
1489
1490   /* not found */
1491   if (!*bp)
1492     {
1493       fprintf (stderr, "expected 'restart' or '{'\n");
1494       return;
1495     }
1496
1497   /* if brace */
1498   if (*bp == '{')
1499     bp++;
1500   else
1501     {                           /* must be restart */
1502       restart++;
1503       bp += strlen ("restart");
1504       /* look for '{' */
1505       EXPECT_CHR (bp, '{', "expected '{'\n");
1506       bp++;
1507     }
1508
1509   /* skip thru all the blank space */
1510   SKIP_SPACE (bp, "unexpected end of rule\n");
1511
1512   match = replace = currL = NULL;
1513   /* we are the start of a rule */
1514   getPeepLine (&match, &bp);
1515
1516   /* now look for by */
1517   EXPECT_STR (bp, "by", "expected 'by'\n");
1518
1519   /* then look for a '{' */
1520   EXPECT_CHR (bp, '{', "expected '{'\n");
1521   bp++;
1522
1523   /* save char position (needed for generating error msg) */
1524   rp = bp;
1525
1526   SKIP_SPACE (bp, "unexpected end of rule\n");
1527   getPeepLine (&replace, &bp);
1528
1529   /* look for a 'if' */
1530   while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1531     bp++;
1532
1533   if (strncmp (bp, "if", 2) == 0)
1534     {
1535       bp += 2;
1536       while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1537         bp++;
1538       if (!*bp)
1539         {
1540           fprintf (stderr, "expected condition name\n");
1541           return;
1542         }
1543
1544       /* look for the condition */
1545       lp = lines;
1546       while (*bp && (*bp != '\n'))
1547         {
1548           *lp++ = *bp++;
1549         }
1550       *lp = '\0';
1551
1552       newPeepRule (match, replace, lines, restart);
1553     }
1554   else
1555     {
1556       if (*bp && strncmp (bp, "replace", 7))
1557         {
1558           /* not the start of a new peeprule, so "if" should be here */
1559
1560           char strbuff[1000];
1561           char *cp;
1562
1563           /* go to the start of the line following "{" of the "by" token */
1564           while (*rp && (*rp == '\n'))
1565             rp++;
1566
1567           /* copy text of rule starting with line after "by {" */
1568           cp = strbuff;
1569           while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1570               *cp++ = *rp++;
1571
1572           /* and now the rest of the line */
1573           while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1574             *cp++ = *rp++;
1575
1576           *cp = '\0';
1577           fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1578           return;
1579         }
1580       newPeepRule (match, replace, NULL, restart);
1581     }
1582   goto top;
1583
1584 }
1585
1586 /*-----------------------------------------------------------------*/
1587 /* keyForVar - returns the numeric key for a var                   */
1588 /*-----------------------------------------------------------------*/
1589 static int
1590 keyForVar (char *d)
1591 {
1592   int i = 0;
1593
1594   while (ISCHARDIGIT (*d))
1595     {
1596       i *= 10;
1597       i += (*d++ - '0');
1598     }
1599
1600   return i;
1601 }
1602
1603 /*-----------------------------------------------------------------*/
1604 /* bindVar - binds a value to a variable in the given hashtable    */
1605 /*-----------------------------------------------------------------*/
1606 static void
1607 bindVar (int key, char **s, hTab ** vtab)
1608 {
1609   char vval[MAX_PATTERN_LEN];
1610   char *vvx;
1611   char *vv = vval;
1612
1613   /* first get the value of the variable */
1614   vvx = *s;
1615   /* the value is ended by a ',' or space or newline or null or ) */
1616   while (*vvx &&
1617          *vvx != ',' &&
1618          !ISCHARSPACE (*vvx) &&
1619          *vvx != '\n' &&
1620          *vvx != ':' &&
1621          *vvx != ')')
1622     {
1623       char ubb = 0;
1624       /* if we find a '(' then we need to balance it */
1625       if (*vvx == '(')
1626         {
1627           ubb++;
1628           while (ubb)
1629             {
1630               *vv++ = *vvx++;
1631               if (*vvx == '(')
1632                 ubb++;
1633               if (*vvx == ')')
1634                 ubb--;
1635             }
1636           // include the trailing ')'
1637           *vv++ = *vvx++;
1638         }
1639       else
1640         *vv++ = *vvx++;
1641     }
1642   *s = vvx;
1643   *vv = '\0';
1644   /* got value */
1645   vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1646
1647   hTabAddItem (vtab, key, vvx);
1648 }
1649
1650 /*-----------------------------------------------------------------*/
1651 /* matchLine - matches one line                                    */
1652 /*-----------------------------------------------------------------*/
1653 static bool
1654 matchLine (char *s, char *d, hTab ** vars)
1655 {
1656
1657   if (!s || !(*s))
1658     return FALSE;
1659
1660   while (*s && *d)
1661     {
1662
1663       /* skip white space in both */
1664       while (ISCHARSPACE (*s))
1665         s++;
1666       while (ISCHARSPACE (*d))
1667         d++;
1668
1669       /* if the destination is a var */
1670       if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1671         {
1672           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1673           /* if the variable is already bound
1674              then it MUST match with dest */
1675           if (v)
1676             {
1677               while (*v)
1678                 if (*v++ != *s++)
1679                   return FALSE;
1680             }
1681           else
1682             /* variable not bound we need to bind it */
1683             bindVar (keyForVar (d + 1), &s, vars);
1684
1685           /* in either case go past the variable */
1686           d++;
1687           while (ISCHARDIGIT (*d))
1688             d++;
1689
1690           while (ISCHARSPACE (*s))
1691             s++;
1692           while (ISCHARSPACE (*d))
1693             d++;
1694         }
1695
1696       /* they should be an exact match other wise */
1697       if (*s && *d)
1698         {
1699           if (*s++ != *d++)
1700             return FALSE;
1701         }
1702
1703     }
1704
1705   /* get rid of the trailing spaces
1706      in both source & destination */
1707   if (*s)
1708     while (ISCHARSPACE (*s))
1709       s++;
1710
1711   if (*d)
1712     while (ISCHARSPACE (*d))
1713       d++;
1714
1715   /* after all this if only one of them
1716      has something left over then no match */
1717   if (*s || *d)
1718     return FALSE;
1719
1720   return TRUE;
1721 }
1722
1723 /*-----------------------------------------------------------------*/
1724 /* matchRule - matches a all the rule lines                        */
1725 /*-----------------------------------------------------------------*/
1726 static bool
1727 matchRule (lineNode * pl,
1728            lineNode ** mtail,
1729            peepRule * pr,
1730            lineNode * head)
1731 {
1732   lineNode *spl;                /* source pl */
1733   lineNode *rpl;                /* rule peep line */
1734
1735 /*     setToNull((void *) &pr->vars);    */
1736 /*     pr->vars = newHashTable(100); */
1737
1738   /* for all the lines defined in the rule */
1739   rpl = pr->match;
1740   spl = pl;
1741   while (spl && rpl)
1742     {
1743
1744       /* if the source line starts with a ';' then
1745          comment line don't process or the source line
1746          contains == . debugger information skip it */
1747       if (spl->line &&
1748           (*spl->line == ';' || spl->isDebug))
1749         {
1750           spl = spl->next;
1751           continue;
1752         }
1753
1754       if (!matchLine (spl->line, rpl->line, &pr->vars))
1755         return FALSE;
1756
1757       rpl = rpl->next;
1758       if (rpl)
1759         spl = spl->next;
1760     }
1761
1762   /* if rules ended */
1763   if (!rpl)
1764     {
1765       /* if this rule has additional conditions */
1766       if (pr->cond)
1767         {
1768           if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1769             {
1770               *mtail = spl;
1771               return TRUE;
1772             }
1773           else
1774             return FALSE;
1775         }
1776       else
1777         {
1778           *mtail = spl;
1779           return TRUE;
1780         }
1781     }
1782   else
1783     return FALSE;
1784 }
1785
1786 static void
1787 reassociate_ic_down (lineNode *shead, lineNode *stail,
1788                      lineNode *rhead, lineNode *rtail)
1789 {
1790   lineNode *csl;        /* current source line */
1791   lineNode *crl;        /* current replacement line */
1792
1793   csl = shead;
1794   crl = rhead;
1795   while (1)
1796     {
1797       /* skip over any comments */
1798       while (csl!=stail->next && csl->isComment)
1799         csl = csl->next;
1800       while (crl!=rtail->next && crl->isComment)
1801         crl = crl->next;
1802
1803       /* quit if we reach the end */
1804       if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1805         break;
1806
1807       if (matchLine(csl->line,crl->line,NULL))
1808         {
1809           crl->ic = csl->ic;
1810           csl = csl->next;
1811           crl = crl->next;
1812         }
1813       else
1814         break;
1815     }
1816 }
1817
1818 static void
1819 reassociate_ic_up (lineNode *shead, lineNode *stail,
1820                    lineNode *rhead, lineNode *rtail)
1821 {
1822   lineNode *csl;        /* current source line */
1823   lineNode *crl;        /* current replacement line */
1824
1825   csl = stail;
1826   crl = rtail;
1827   while (1)
1828     {
1829       /* skip over any comments */
1830       while (csl!=shead->prev && csl->isComment)
1831         csl = csl->prev;
1832       while (crl!=rhead->prev && crl->isComment)
1833         crl = crl->prev;
1834
1835       /* quit if we reach the end */
1836       if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1837         break;
1838
1839       if (matchLine(csl->line,crl->line,NULL))
1840         {
1841           crl->ic = csl->ic;
1842           csl = csl->prev;
1843           crl = crl->prev;
1844         }
1845       else
1846         break;
1847     }
1848 }
1849
1850 /*------------------------------------------------------------------*/
1851 /* reassociate_ic - reassociate replacement lines with origin iCode */
1852 /*------------------------------------------------------------------*/
1853 static void
1854 reassociate_ic (lineNode *shead, lineNode *stail,
1855                 lineNode *rhead, lineNode *rtail)
1856 {
1857   lineNode *csl;        /* current source line */
1858   lineNode *crl;        /* current replacement line */
1859   bool single_iCode;
1860   iCode *ic;
1861
1862   /* Check to see if all the source lines (excluding comments) came
1863   ** for the same iCode
1864   */
1865   ic = NULL;
1866   for (csl=shead;csl!=stail->next;csl=csl->next)
1867     if (csl->ic && !csl->isComment)
1868       {
1869         ic = csl->ic;
1870         break;
1871       }
1872   single_iCode = (ic!=NULL);
1873   for (csl=shead;csl!=stail->next;csl=csl->next)
1874     if ((csl->ic != ic) && !csl->isComment)
1875       {
1876         /* More than one iCode was found. However, if it's just the
1877         ** last line with the different iCode and it was not changed
1878         ** in the replacement, everything else must be the first iCode.
1879         */
1880         if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1881           {
1882             rtail->ic = stail->ic;
1883             for (crl=rhead;crl!=rtail;crl=crl->next)
1884               crl->ic = ic;
1885             return;
1886           }
1887
1888         single_iCode = FALSE;
1889         break;
1890       }
1891
1892   /* If all of the source lines came from the same iCode, then so have
1893   ** all of the replacement lines too.
1894   */
1895   if (single_iCode)
1896     {
1897       for (crl=rhead;crl!=rtail->next;crl=crl->next)
1898         crl->ic = ic;
1899       return;
1900     }
1901
1902   /* The source lines span iCodes, so we may end up with replacement
1903   ** lines that we don't know which iCode(s) to associate with. Do the
1904   ** best we can by using the following strategies:
1905   **    1) Start at the top and scan down. As long as the source line
1906   **       matches the replacement line, they have the same iCode.
1907   **    2) Start at the bottom and scan up. As long as the source line
1908   **       matches the replacement line, they have the same iCode.
1909   **    3) For any label in the source, look for a matching label in
1910   **       the replacment. If found, they have the same iCode. From
1911   **       these matching labels, scan down for additional matching
1912   **       lines; if found, they also have the same iCode.
1913   */
1914
1915   /* Strategy #1: Start at the top and scan down for matches
1916   */
1917   reassociate_ic_down(shead,stail,rhead,rtail);
1918
1919   /* Strategy #2: Start at the bottom and scan up for matches
1920   */
1921   reassociate_ic_up(shead,stail,rhead,rtail);
1922
1923   /* Strategy #3: Try to match labels
1924   */
1925   csl = shead;
1926   while (1)
1927     {
1928       /* skip over any comments */
1929       while (csl!=stail->next && csl->isComment)
1930         csl = csl->next;
1931       if (csl==stail->next)
1932         break;
1933
1934       if (csl->isLabel)
1935         {
1936           /* found a source line label; look for it in the replacment lines */
1937           crl = rhead;
1938           while (1)
1939             {
1940               while (crl!=rtail->next && crl->isComment)
1941                 crl = crl->next;
1942               if (crl==rtail->next)
1943                 break;
1944               if (matchLine(csl->line, crl->line, NULL))
1945                 {
1946                   reassociate_ic_down(csl,stail,crl,rtail);
1947                   break;
1948                 }
1949               else
1950                 crl = crl->next;
1951             }
1952         }
1953       csl = csl->next;
1954     }
1955
1956   /* Try to assign a meaningful iCode to any comment that is missing
1957      one. Since they are comments, it's ok to make mistakes; we are just
1958      trying to improve continuity to simplify other tests.
1959   */
1960   ic = NULL;
1961   for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1962     {
1963       if (!crl->ic && ic && crl->isComment)
1964         crl->ic = ic;
1965       ic = crl->ic;
1966     }
1967 }
1968
1969
1970 /*-----------------------------------------------------------------*/
1971 /* replaceRule - does replacement of a matching pattern            */
1972 /*-----------------------------------------------------------------*/
1973 static void
1974 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1975 {
1976   lineNode *cl = NULL;
1977   lineNode *pl = NULL, *lhead = NULL;
1978   /* a long function name and long variable name can evaluate to
1979      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1980   char lb[MAX_PATTERN_LEN*4];
1981   char *lbp;
1982   lineNode *comment = NULL;
1983
1984   /* collect all the comment lines in the source */
1985   for (cl = *shead; cl != stail; cl = cl->next)
1986     {
1987       if (cl->line && (*cl->line == ';' || cl->isDebug))
1988         {
1989           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1990                 (comment = newLineNode (cl->line)));
1991           pl->isDebug = cl->isDebug;
1992           pl->isComment = cl->isComment || (*cl->line == ';');
1993         }
1994     }
1995   cl = NULL;
1996
1997   /* for all the lines in the replacement pattern do */
1998   for (pl = pr->replace; pl; pl = pl->next)
1999     {
2000       char *v;
2001       char *l;
2002       lbp = lb;
2003
2004       l = pl->line;
2005
2006       while (*l)
2007         {
2008           /* if the line contains a variable */
2009           if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2010             {
2011               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2012               if (!v)
2013                 {
2014                   fprintf (stderr, "used unbound variable in replacement\n");
2015                   l++;
2016                   continue;
2017                 }
2018               while (*v) {
2019                 *lbp++ = *v++;
2020               }
2021               l++;
2022               while (ISCHARDIGIT (*l)) {
2023                 l++;
2024               }
2025               continue;
2026             }
2027           *lbp++ = *l++;
2028         }
2029
2030       *lbp = '\0';
2031       if (cl)
2032         cl = connectLine (cl, newLineNode (lb));
2033       else
2034         lhead = cl = newLineNode (lb);
2035       cl->isComment = pl->isComment;
2036       cl->isLabel   = pl->isLabel;
2037     }
2038
2039   /* add the comments if any to the head of list */
2040   if (comment)
2041     {
2042       lineNode *lc = comment;
2043       while (lc->next)
2044         lc = lc->next;
2045       lc->next = lhead;
2046       if (lhead)
2047         lhead->prev = lc;
2048       lhead = comment;
2049     }
2050
2051   if (lhead)
2052     {
2053       /* determine which iCodes the replacment lines relate to */
2054       reassociate_ic(*shead,stail,lhead,cl);
2055
2056       /* now we need to connect / replace the original chain */
2057       /* if there is a prev then change it */
2058       if ((*shead)->prev)
2059         {
2060           (*shead)->prev->next = lhead;
2061           lhead->prev = (*shead)->prev;
2062         }
2063       *shead = lhead;
2064       /* now for the tail */
2065       if (stail && stail->next)
2066         {
2067           stail->next->prev = cl;
2068           if (cl)
2069             cl->next = stail->next;
2070         }
2071     }
2072   else
2073     {
2074       /* the replacement is empty - delete the source lines */
2075       if ((*shead)->prev)
2076         (*shead)->prev->next = stail->next;
2077       if (stail->next)
2078         stail->next->prev = (*shead)->prev;
2079       *shead = stail->next;
2080     }
2081 }
2082
2083 /* Returns TRUE if this line is a label definition.
2084
2085  * If so, start will point to the start of the label name,
2086  * and len will be it's length.
2087  */
2088 bool
2089 isLabelDefinition (const char *line, const char **start, int *len,
2090                    bool isPeepRule)
2091 {
2092   const char *cp = line;
2093
2094   /* This line is a label if if consists of:
2095    * [optional whitespace] followed by identifier chars
2096    * (alnum | $ | _ ) followed by a colon.
2097    */
2098
2099   while (*cp && ISCHARSPACE (*cp))
2100     {
2101       cp++;
2102     }
2103
2104   if (!*cp)
2105     {
2106       return FALSE;
2107     }
2108
2109   *start = cp;
2110
2111   while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2112          (isPeepRule && (*cp == '%')))
2113     {
2114       cp++;
2115     }
2116
2117   if ((cp == *start) || (*cp != ':'))
2118     {
2119       return FALSE;
2120     }
2121
2122   *len = (cp - (*start));
2123   return TRUE;
2124 }
2125
2126 /* Quick & dirty string hash function. */
2127 static int
2128 hashSymbolName (const char *name)
2129 {
2130   int hash = 0;
2131
2132   while (*name)
2133     {
2134       hash = (hash << 6) ^ *name;
2135       name++;
2136     }
2137
2138   if (hash < 0)
2139     {
2140       hash = -hash;
2141     }
2142
2143   return hash % HTAB_SIZE;
2144 }
2145
2146 /* Build a hash of all labels in the passed set of lines
2147  * and how many times they are referenced.
2148  */
2149 static void
2150 buildLabelRefCountHash (lineNode * head)
2151 {
2152   lineNode *line;
2153   const char *label;
2154   int labelLen;
2155   int i;
2156
2157   assert (labelHash == NULL);
2158   labelHash = newHashTable (HTAB_SIZE);
2159
2160   /* First pass: locate all the labels. */
2161   for (line = head; line; line = line->next)
2162     {
2163       if (line->isLabel  ||
2164           line->isInline)
2165         {
2166           /* run isLabelDefinition to:
2167              - look for labels in inline assembler
2168              - calculate labelLen
2169           */
2170           if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2171               labelLen <= SDCC_NAME_MAX)
2172             {
2173               labelHashEntry *entry;
2174
2175               entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2176
2177               memcpy (entry->name, label, labelLen);
2178               entry->name[labelLen] = 0;
2179               entry->refCount = -1;
2180
2181               /* Assume function entry points are referenced somewhere,   */
2182               /* even if we can't find a reference (might be from outside */
2183               /* the function) */
2184               if (line->ic && (line->ic->op == FUNCTION))
2185                 entry->refCount++;
2186
2187               hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2188             }
2189         }
2190     }
2191
2192
2193   /* Second pass: for each line, note all the referenced labels. */
2194   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2195   line = head;
2196   while (line)
2197     {
2198       for (i = 0; i < HTAB_SIZE; i++)
2199         {
2200           labelHashEntry *thisEntry;
2201
2202           thisEntry = hTabFirstItemWK (labelHash, i);
2203
2204           while (thisEntry)
2205             {
2206               if (strstr (line->line, thisEntry->name))
2207                 {
2208                   thisEntry->refCount++;
2209                 }
2210               thisEntry = hTabNextItemWK (labelHash);
2211             }
2212         }
2213       line = line->next;
2214     }
2215
2216 #if 0
2217   /* Spew the contents of the table. Debugging fun only. */
2218   for (i = 0; i < HTAB_SIZE; i++)
2219     {
2220       labelHashEntry *thisEntry;
2221
2222       thisEntry = hTabFirstItemWK (labelHash, i);
2223
2224       while (thisEntry)
2225         {
2226           fprintf (stderr, "label: %s ref %d\n",
2227                    thisEntry->name, thisEntry->refCount);
2228           thisEntry = hTabNextItemWK (labelHash);
2229         }
2230     }
2231 #endif
2232 }
2233
2234 /* How does this work?
2235    peepHole
2236     For each rule,
2237      For each line,
2238       Try to match
2239       If it matches,
2240        replace and restart.
2241
2242     matchRule
2243      matchLine
2244
2245   Where is stuff allocated?
2246
2247 */
2248
2249 /*-----------------------------------------------------------------*/
2250 /* peepHole - matches & substitutes rules                          */
2251 /*-----------------------------------------------------------------*/
2252 void
2253 peepHole (lineNode ** pls)
2254 {
2255   lineNode *spl;
2256   peepRule *pr;
2257   lineNode *mtail = NULL;
2258   bool restart, replaced;
2259
2260 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2261   /* The PIC port uses a different peep hole optimizer based on "pCode" */
2262   if (TARGET_IS_PIC || TARGET_IS_PIC16)
2263     return;
2264 #endif
2265
2266   assert(labelHash == NULL);
2267
2268   do
2269     {
2270       restart = FALSE;
2271
2272       /* for all rules */
2273       for (pr = rootRules; pr; pr = pr->next)
2274         {
2275           for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2276             {
2277               replaced = FALSE;
2278
2279               /* if inline assembler then no peep hole */
2280               if (spl->isInline)
2281                 continue;
2282
2283               /* don't waste time starting a match on debug symbol
2284               ** or comment */
2285               if (spl->isDebug || spl->isComment || *(spl->line)==';')
2286                 continue;
2287
2288               mtail = NULL;
2289
2290               /* Tidy up any data stored in the hTab */
2291
2292               /* if it matches */
2293               if (matchRule (spl, &mtail, pr, *pls))
2294                 {
2295                   /* restart at the replaced line */
2296                   replaced = TRUE;
2297
2298                   /* then replace */
2299                   if (spl == *pls)
2300                     {
2301                       replaceRule (pls, mtail, pr);
2302                       spl = *pls;
2303                     }
2304                   else
2305                     replaceRule (&spl, mtail, pr);
2306
2307                   /* if restart rule type then
2308                      start at the top again */
2309                   if (pr->restart)
2310                     {
2311                       restart = TRUE;
2312                     }
2313                 }
2314
2315               if (pr->vars)
2316                 {
2317                   hTabDeleteAll (pr->vars);
2318                   Safe_free (pr->vars);
2319                   pr->vars = NULL;
2320                 }
2321
2322               freeTrace (&_G.values);
2323             }
2324         }
2325     } while (restart == TRUE);
2326
2327   if (labelHash)
2328     {
2329       hTabDeleteAll (labelHash);
2330       freeTrace (&_G.labels);
2331     }
2332   labelHash = NULL;
2333 }
2334
2335
2336 /*-----------------------------------------------------------------*/
2337 /* readFileIntoBuffer - reads a file into a string buffer          */
2338 /*-----------------------------------------------------------------*/
2339 static char *
2340 readFileIntoBuffer (char *fname)
2341 {
2342   FILE *f;
2343   char *rs = NULL;
2344   int nch = 0;
2345   int ch;
2346   char lb[MAX_PATTERN_LEN];
2347
2348   if (!(f = fopen (fname, "r")))
2349     {
2350       fprintf (stderr, "cannot open peep rule file\n");
2351       return NULL;
2352     }
2353
2354   while ((ch = fgetc (f)) != EOF)
2355     {
2356       lb[nch++] = ch;
2357
2358       /* if we maxed out our local buffer */
2359       if (nch >= (MAX_PATTERN_LEN - 2))
2360         {
2361           lb[nch] = '\0';
2362           /* copy it into allocated buffer */
2363           if (rs)
2364             {
2365               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2366               strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
2367             }
2368           else
2369             {
2370               rs = Safe_strdup (lb);
2371             }
2372           nch = 0;
2373         }
2374     }
2375
2376   /* if some charaters left over */
2377   if (nch)
2378     {
2379       lb[nch] = '\0';
2380       /* copy it into allocated buffer */
2381       if (rs)
2382         {
2383           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2384           strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2385         }
2386       else
2387         {
2388           rs = Safe_strdup (lb);
2389         }
2390     }
2391   return rs;
2392 }
2393
2394 /*-----------------------------------------------------------------*/
2395 /* initPeepHole - initialises the peep hole optimizer stuff        */
2396 /*-----------------------------------------------------------------*/
2397 void
2398 initPeepHole ()
2399 {
2400   char *s;
2401
2402   /* read in the default rules */
2403   if (!options.nopeep)
2404     {
2405       readRules (port->peep.default_rules);
2406     }
2407
2408   /* if we have any additional file read it too */
2409   if (options.peep_file)
2410     {
2411       readRules (s = readFileIntoBuffer (options.peep_file));
2412       setToNull ((void *) &s);
2413       /* override nopeep setting, default rules have not been read */
2414       options.nopeep = 0;
2415     }
2416
2417
2418 #if !OPT_DISABLE_PIC
2419   /* Convert the peep rules into pcode.
2420      NOTE: this is only support in the PIC port (at the moment)
2421   */
2422         if (TARGET_IS_PIC)
2423                 peepRules2pCode(rootRules);
2424 #endif
2425
2426 #if !OPT_DISABLE_PIC16
2427   /* Convert the peep rules into pcode.
2428      NOTE: this is only support in the PIC port (at the moment)
2429        and the PIC16 port (VR 030601)
2430   */
2431         if (TARGET_IS_PIC16)
2432                 pic16_peepRules2pCode(rootRules);
2433
2434 #endif
2435
2436 }