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