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