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