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