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