* as/hc08/lkaomf51.c (OutputName): made name unsigned char,
[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;
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   SKIP_SPACE (bp, "unexpected end of rule\n");
1378   getPeepLine (&replace, &bp);
1379
1380   /* look for a 'if' */
1381   while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1382     bp++;
1383
1384   if (strncmp (bp, "if", 2) == 0)
1385     {
1386       bp += 2;
1387       while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1388         bp++;
1389       if (!*bp)
1390         {
1391           fprintf (stderr, "expected condition name\n");
1392           return;
1393         }
1394
1395       /* look for the condition */
1396       lp = lines;
1397       while (*bp && (*bp != '\n'))
1398         {
1399           *lp++ = *bp++;
1400         }
1401       *lp = '\0';
1402
1403       newPeepRule (match, replace, lines, restart);
1404     }
1405   else
1406     newPeepRule (match, replace, NULL, restart);
1407   goto top;
1408
1409 }
1410
1411 /*-----------------------------------------------------------------*/
1412 /* keyForVar - returns the numeric key for a var                   */
1413 /*-----------------------------------------------------------------*/
1414 static int
1415 keyForVar (char *d)
1416 {
1417   int i = 0;
1418
1419   while (ISCHARDIGIT (*d))
1420     {
1421       i *= 10;
1422       i += (*d++ - '0');
1423     }
1424
1425   return i;
1426 }
1427
1428 /*-----------------------------------------------------------------*/
1429 /* bindVar - binds a value to a variable in the given hashtable    */
1430 /*-----------------------------------------------------------------*/
1431 static void
1432 bindVar (int key, char **s, hTab ** vtab)
1433 {
1434   char vval[MAX_PATTERN_LEN];
1435   char *vvx;
1436   char *vv = vval;
1437
1438   /* first get the value of the variable */
1439   vvx = *s;
1440   /* the value is ended by a ',' or space or newline or null or ) */
1441   while (*vvx &&
1442          *vvx != ',' &&
1443          !ISCHARSPACE (*vvx) &&
1444          *vvx != '\n' &&
1445          *vvx != ':' &&
1446          *vvx != ')')
1447     {
1448       char ubb = 0;
1449       /* if we find a '(' then we need to balance it */
1450       if (*vvx == '(')
1451         {
1452           ubb++;
1453           while (ubb)
1454             {
1455               *vv++ = *vvx++;
1456               if (*vvx == '(')
1457                 ubb++;
1458               if (*vvx == ')')
1459                 ubb--;
1460             }
1461           // include the trailing ')'
1462           *vv++ = *vvx++;
1463         }
1464       else
1465         *vv++ = *vvx++;
1466     }
1467   *s = vvx;
1468   *vv = '\0';
1469   /* got value */
1470   vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1471
1472   hTabAddItem (vtab, key, vvx);
1473 }
1474
1475 /*-----------------------------------------------------------------*/
1476 /* matchLine - matches one line                                    */
1477 /*-----------------------------------------------------------------*/
1478 static bool
1479 matchLine (char *s, char *d, hTab ** vars)
1480 {
1481
1482   if (!s || !(*s))
1483     return FALSE;
1484
1485   while (*s && *d)
1486     {
1487
1488       /* skip white space in both */
1489       while (ISCHARSPACE (*s))
1490         s++;
1491       while (ISCHARSPACE (*d))
1492         d++;
1493
1494       /* if the destination is a var */
1495       if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1496         {
1497           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1498           /* if the variable is already bound
1499              then it MUST match with dest */
1500           if (v)
1501             {
1502               while (*v)
1503                 if (*v++ != *s++)
1504                   return FALSE;
1505             }
1506           else
1507             /* variable not bound we need to
1508                bind it */
1509             bindVar (keyForVar (d + 1), &s, vars);
1510
1511           /* in either case go past the variable */
1512           d++;
1513           while (ISCHARDIGIT (*d))
1514             d++;
1515
1516           while (ISCHARSPACE (*s))
1517             s++;
1518           while (ISCHARSPACE (*d))
1519             d++;
1520         }
1521
1522       /* they should be an exact match other wise */
1523       if (*s && *d)
1524         {
1525           if (*s++ != *d++)
1526             return FALSE;
1527         }
1528
1529     }
1530
1531   /* get rid of the trailing spaces
1532      in both source & destination */
1533   if (*s)
1534     while (ISCHARSPACE (*s))
1535       s++;
1536
1537   if (*d)
1538     while (ISCHARSPACE (*d))
1539       d++;
1540
1541   /* after all this if only one of them
1542      has something left over then no match */
1543   if (*s || *d)
1544     return FALSE;
1545
1546   return TRUE;
1547 }
1548
1549 /*-----------------------------------------------------------------*/
1550 /* matchRule - matches a all the rule lines                        */
1551 /*-----------------------------------------------------------------*/
1552 static bool
1553 matchRule (lineNode * pl,
1554            lineNode ** mtail,
1555            peepRule * pr,
1556            lineNode * head)
1557 {
1558   lineNode *spl;                /* source pl */
1559   lineNode *rpl;                /* rule peep line */
1560
1561 /*     setToNull((void *) &pr->vars);    */
1562 /*     pr->vars = newHashTable(100); */
1563
1564   /* for all the lines defined in the rule */
1565   rpl = pr->match;
1566   spl = pl;
1567   while (spl && rpl)
1568     {
1569
1570       /* if the source line starts with a ';' then
1571          comment line don't process or the source line
1572          contains == . debugger information skip it */
1573       if (spl->line &&
1574           (*spl->line == ';' || spl->isDebug))
1575         {
1576           spl = spl->next;
1577           continue;
1578         }
1579
1580       if (!matchLine (spl->line, rpl->line, &pr->vars))
1581         return FALSE;
1582
1583       rpl = rpl->next;
1584       if (rpl)
1585         spl = spl->next;
1586     }
1587
1588   /* if rules ended */
1589   if (!rpl)
1590     {
1591       /* if this rule has additional conditions */
1592       if (pr->cond)
1593         {
1594           if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1595             {
1596               *mtail = spl;
1597               return TRUE;
1598             }
1599           else
1600             return FALSE;
1601         }
1602       else
1603         {
1604           *mtail = spl;
1605           return TRUE;
1606         }
1607     }
1608   else
1609     return FALSE;
1610 }
1611
1612 static void
1613 reassociate_ic_down (lineNode *shead, lineNode *stail,
1614                      lineNode *rhead, lineNode *rtail)
1615 {
1616   lineNode *csl;        /* current source line */
1617   lineNode *crl;        /* current replacement line */
1618
1619   csl = shead;
1620   crl = rhead;
1621   while (1)
1622     {
1623       /* skip over any comments */
1624       while (csl!=stail->next && csl->isComment)
1625         csl = csl->next;
1626       while (crl!=rtail->next && crl->isComment)
1627         crl = crl->next;
1628
1629       /* quit if we reach the end */
1630       if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1631         break;
1632
1633       if (matchLine(csl->line,crl->line,NULL))
1634         {
1635           crl->ic = csl->ic;
1636           csl = csl->next;
1637           crl = crl->next;
1638         }
1639       else
1640         break;
1641     }
1642 }
1643
1644 static void
1645 reassociate_ic_up (lineNode *shead, lineNode *stail,
1646                    lineNode *rhead, lineNode *rtail)
1647 {
1648   lineNode *csl;        /* current source line */
1649   lineNode *crl;        /* current replacement line */
1650
1651   csl = stail;
1652   crl = rtail;
1653   while (1)
1654     {
1655       /* skip over any comments */
1656       while (csl!=shead->prev && csl->isComment)
1657         csl = csl->prev;
1658       while (crl!=rhead->prev && crl->isComment)
1659         crl = crl->prev;
1660
1661       /* quit if we reach the end */
1662       if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1663         break;
1664
1665       if (matchLine(csl->line,crl->line,NULL))
1666         {
1667           crl->ic = csl->ic;
1668           csl = csl->prev;
1669           crl = crl->prev;
1670         }
1671       else
1672         break;
1673     }
1674 }
1675
1676 /*------------------------------------------------------------------*/
1677 /* reassociate_ic - reassociate replacement lines with origin iCode */
1678 /*------------------------------------------------------------------*/
1679 static void
1680 reassociate_ic (lineNode *shead, lineNode *stail,
1681                 lineNode *rhead, lineNode *rtail)
1682 {
1683   lineNode *csl;        /* current source line */
1684   lineNode *crl;        /* current replacement line */
1685   bool single_iCode;
1686   iCode *ic;
1687
1688   /* Check to see if all the source lines (excluding comments) came
1689   ** for the same iCode
1690   */
1691   ic = NULL;
1692   for (csl=shead;csl!=stail->next;csl=csl->next)
1693     if (csl->ic && !csl->isComment)
1694       {
1695         ic = csl->ic;
1696         break;
1697       }
1698   single_iCode = (ic!=NULL);
1699   for (csl=shead;csl!=stail->next;csl=csl->next)
1700     if ((csl->ic != ic) && !csl->isComment)
1701       {
1702         /* More than one iCode was found. However, if it's just the
1703         ** last line with the different iCode and it was not changed
1704         ** in the replacement, everything else must be the first iCode.
1705         */
1706         if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1707           {
1708             rtail->ic = stail->ic;
1709             for (crl=rhead;crl!=rtail;crl=crl->next)
1710               crl->ic = ic;
1711             return;
1712           }
1713
1714         single_iCode = FALSE;
1715         break;
1716       }
1717
1718   /* If all of the source lines came from the same iCode, then so have
1719   ** all of the replacement lines too.
1720   */
1721   if (single_iCode)
1722     {
1723       for (crl=rhead;crl!=rtail->next;crl=crl->next)
1724         crl->ic = ic;
1725       return;
1726     }
1727
1728   /* The source lines span iCodes, so we may end up with replacement
1729   ** lines that we don't know which iCode(s) to associate with. Do the
1730   ** best we can by using the following strategies:
1731   **    1) Start at the top and scan down. As long as the source line
1732   **       matches the replacement line, they have the same iCode.
1733   **    2) Start at the bottom and scan up. As long as the source line
1734   **       matches the replacement line, they have the same iCode.
1735   **    3) For any label in the source, look for a matching label in
1736   **       the replacment. If found, they have the same iCode. From
1737   **       these matching labels, scan down for additional matching
1738   **       lines; if found, they also have the same iCode.
1739   */
1740
1741   /* Strategy #1: Start at the top and scan down for matches
1742   */
1743   reassociate_ic_down(shead,stail,rhead,rtail);
1744
1745   /* Strategy #2: Start at the bottom and scan up for matches
1746   */
1747   reassociate_ic_up(shead,stail,rhead,rtail);
1748
1749   /* Strategy #3: Try to match labels
1750   */
1751   csl = shead;
1752   while (1)
1753     {
1754       const char *labelStart;
1755       int labelLength;
1756
1757       /* skip over any comments */
1758       while (csl!=stail->next && csl->isComment)
1759         csl = csl->next;
1760       if (csl==stail->next)
1761         break;
1762
1763       if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1764         {
1765           /* found a source line label; look for it in the replacment lines */
1766           crl = rhead;
1767           while (1)
1768             {
1769               while (crl!=rtail->next && crl->isComment)
1770                 crl = crl->next;
1771               if (crl==rtail->next)
1772                 break;
1773               if (matchLine(csl->line, crl->line, NULL))
1774                 {
1775                   reassociate_ic_down(csl,stail,crl,rtail);
1776                   break;
1777                 }
1778               else
1779                 crl = crl->next;
1780             }
1781         }
1782       csl = csl->next;
1783     }
1784
1785   /* Try to assign a meaningful iCode to any comment that is missing
1786      one. Since they are comments, it's ok to make mistakes; we are just
1787      trying to improve continuity to simplify other tests.
1788   */
1789   ic = NULL;
1790   for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1791     {
1792       if (!crl->ic && ic && crl->isComment)
1793         crl->ic = ic;
1794       ic = crl->ic;
1795     }
1796 }
1797
1798
1799 /*-----------------------------------------------------------------*/
1800 /* replaceRule - does replacement of a matching pattern            */
1801 /*-----------------------------------------------------------------*/
1802 static void
1803 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1804 {
1805   lineNode *cl = NULL;
1806   lineNode *pl = NULL, *lhead = NULL;
1807   /* a long function name and long variable name can evaluate to
1808      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1809   char lb[MAX_PATTERN_LEN*4];
1810   char *lbp;
1811   lineNode *comment = NULL;
1812
1813   /* collect all the comment lines in the source */
1814   for (cl = *shead; cl != stail; cl = cl->next)
1815     {
1816       if (cl->line && (*cl->line == ';' || cl->isDebug))
1817         {
1818           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1819                 (comment = newLineNode (cl->line)));
1820           pl->isDebug = cl->isDebug;
1821           pl->isComment = cl->isComment || (*cl->line == ';');
1822         }
1823     }
1824   cl = NULL;
1825
1826   /* for all the lines in the replacement pattern do */
1827   for (pl = pr->replace; pl; pl = pl->next)
1828     {
1829       char *v;
1830       char *l;
1831       lbp = lb;
1832
1833       l = pl->line;
1834
1835       while (*l)
1836         {
1837           /* if the line contains a variable */
1838           if (*l == '%' && ISCHARDIGIT (*(l + 1)))
1839             {
1840               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1841               if (!v)
1842                 {
1843                   fprintf (stderr, "used unbound variable in replacement\n");
1844                   l++;
1845                   continue;
1846                 }
1847               while (*v) {
1848                 *lbp++ = *v++;
1849               }
1850               l++;
1851               while (ISCHARDIGIT (*l)) {
1852                 l++;
1853               }
1854               continue;
1855             }
1856           *lbp++ = *l++;
1857         }
1858
1859       *lbp = '\0';
1860       if (cl)
1861         cl = connectLine (cl, newLineNode (lb));
1862       else
1863         lhead = cl = newLineNode (lb);
1864       cl->isComment = pl->isComment;
1865     }
1866
1867   /* add the comments if any to the head of list */
1868   if (comment)
1869     {
1870       lineNode *lc = comment;
1871       while (lc->next)
1872         lc = lc->next;
1873       lc->next = lhead;
1874       if (lhead)
1875         lhead->prev = lc;
1876       lhead = comment;
1877     }
1878
1879   if (lhead)
1880     {
1881       /* determine which iCodes the replacment lines relate to */
1882       reassociate_ic(*shead,stail,lhead,cl);
1883
1884       /* now we need to connect / replace the original chain */
1885       /* if there is a prev then change it */
1886       if ((*shead)->prev)
1887         {
1888           (*shead)->prev->next = lhead;
1889           lhead->prev = (*shead)->prev;
1890         }
1891       *shead = lhead;
1892       /* now for the tail */
1893       if (stail && stail->next)
1894         {
1895           stail->next->prev = cl;
1896           if (cl)
1897             cl->next = stail->next;
1898         }
1899     }
1900   else
1901     {
1902       /* the replacement is empty - delete the source lines */
1903       if ((*shead)->prev)
1904         (*shead)->prev->next = stail->next;
1905       if (stail->next)
1906         stail->next->prev = (*shead)->prev;
1907       *shead = stail->next;
1908     }
1909 }
1910
1911 /* Returns TRUE if this line is a label definition.
1912
1913  * If so, start will point to the start of the label name,
1914  * and len will be it's length.
1915  */
1916 bool
1917 isLabelDefinition (const char *line, const char **start, int *len)
1918 {
1919   const char *cp = line;
1920
1921   /* This line is a label if if consists of:
1922    * [optional whitespace] followed by identifier chars
1923    * (alnum | $ | _ ) followed by a colon.
1924    */
1925
1926   while (*cp && ISCHARSPACE (*cp))
1927     {
1928       cp++;
1929     }
1930
1931   if (!*cp)
1932     {
1933       return FALSE;
1934     }
1935
1936   *start = cp;
1937
1938   while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_'))
1939     {
1940       cp++;
1941     }
1942
1943   if ((cp == *start) || (*cp != ':'))
1944     {
1945       return FALSE;
1946     }
1947
1948   *len = (cp - (*start));
1949   return TRUE;
1950 }
1951
1952 /* Quick & dirty string hash function. */
1953 static int
1954 hashSymbolName (const char *name)
1955 {
1956   int hash = 0;
1957
1958   while (*name)
1959     {
1960       hash = (hash << 6) ^ *name;
1961       name++;
1962     }
1963
1964   if (hash < 0)
1965     {
1966       hash = -hash;
1967     }
1968
1969   return hash % HTAB_SIZE;
1970 }
1971
1972 /* Build a hash of all labels in the passed set of lines
1973  * and how many times they are referenced.
1974  */
1975 static void
1976 buildLabelRefCountHash (lineNode * head)
1977 {
1978   lineNode *line;
1979   const char *label;
1980   int labelLen;
1981   int i;
1982
1983   assert (labelHash == NULL);
1984   labelHash = newHashTable (HTAB_SIZE);
1985
1986   /* First pass: locate all the labels. */
1987   line = head;
1988
1989   while (line)
1990     {
1991       if (isLabelDefinition (line->line, &label, &labelLen)
1992           && labelLen <= SDCC_NAME_MAX)
1993         {
1994           labelHashEntry *entry;
1995
1996           entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1997
1998           memcpy (entry->name, label, labelLen);
1999           entry->name[labelLen] = 0;
2000           entry->refCount = -1;
2001
2002           /* Assume function entry points are referenced somewhere,   */
2003           /* even if we can't find a reference (might be from outside */
2004           /* the function) */
2005           if (line->ic && (line->ic->op == FUNCTION))
2006             entry->refCount++;
2007
2008           hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2009         }
2010       line = line->next;
2011     }
2012
2013
2014   /* Second pass: for each line, note all the referenced labels. */
2015   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2016   line = head;
2017   while (line)
2018     {
2019       for (i = 0; i < HTAB_SIZE; i++)
2020         {
2021           labelHashEntry *thisEntry;
2022
2023           thisEntry = hTabFirstItemWK (labelHash, i);
2024
2025           while (thisEntry)
2026             {
2027               if (strstr (line->line, thisEntry->name))
2028                 {
2029                   thisEntry->refCount++;
2030                 }
2031               thisEntry = hTabNextItemWK (labelHash);
2032             }
2033         }
2034       line = line->next;
2035     }
2036
2037 #if 0
2038   /* Spew the contents of the table. Debugging fun only. */
2039   for (i = 0; i < HTAB_SIZE; i++)
2040     {
2041       labelHashEntry *thisEntry;
2042
2043       thisEntry = hTabFirstItemWK (labelHash, i);
2044
2045       while (thisEntry)
2046         {
2047           fprintf (stderr, "label: %s ref %d\n",
2048                    thisEntry->name, thisEntry->refCount);
2049           thisEntry = hTabNextItemWK (labelHash);
2050         }
2051     }
2052 #endif
2053 }
2054
2055 /* How does this work?
2056    peepHole
2057     For each rule,
2058      For each line,
2059       Try to match
2060       If it matches,
2061        replace and restart.
2062
2063     matchRule
2064      matchLine
2065
2066   Where is stuff allocated?
2067
2068 */
2069
2070 /*-----------------------------------------------------------------*/
2071 /* peepHole - matches & substitutes rules                          */
2072 /*-----------------------------------------------------------------*/
2073 void
2074 peepHole (lineNode ** pls)
2075 {
2076   lineNode *spl;
2077   peepRule *pr;
2078   lineNode *mtail = NULL;
2079   bool restart;
2080
2081 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2082   /* The PIC port uses a different peep hole optimizer based on "pCode" */
2083   if (TARGET_IS_PIC || TARGET_IS_PIC16)
2084     return;
2085 #endif
2086
2087   assert(labelHash == NULL);
2088
2089   do
2090     {
2091       restart = FALSE;
2092
2093       /* for all rules */
2094       for (pr = rootRules; pr; pr = pr->next)
2095         {
2096           for (spl = *pls; spl; spl = spl->next)
2097             {
2098               /* if inline assembler then no peep hole */
2099               if (spl->isInline)
2100                 continue;
2101
2102               /* don't waste time starting a match on debug symbol
2103               ** or comment */
2104               if (spl->isDebug || spl->isComment || *(spl->line)==';')
2105                 continue;
2106
2107               mtail = NULL;
2108
2109               /* Tidy up any data stored in the hTab */
2110
2111               /* if it matches */
2112               if (matchRule (spl, &mtail, pr, *pls))
2113                 {
2114
2115                   /* then replace */
2116                   if (spl == *pls)
2117                     replaceRule (pls, mtail, pr);
2118                   else
2119                     replaceRule (&spl, mtail, pr);
2120
2121                   /* if restart rule type then
2122                      start at the top again */
2123                   if (pr->restart)
2124                     {
2125                       restart = TRUE;
2126                     }
2127                 }
2128
2129               if (pr->vars)
2130                 {
2131                   hTabDeleteAll (pr->vars);
2132                   Safe_free (pr->vars);
2133                   pr->vars = NULL;
2134                 }
2135
2136               freeTrace (&_G.values);
2137             }
2138         }
2139     } while (restart == TRUE);
2140
2141   if (labelHash)
2142     {
2143       hTabDeleteAll (labelHash);
2144       freeTrace (&_G.labels);
2145     }
2146   labelHash = NULL;
2147 }
2148
2149
2150 /*-----------------------------------------------------------------*/
2151 /* readFileIntoBuffer - reads a file into a string buffer          */
2152 /*-----------------------------------------------------------------*/
2153 static char *
2154 readFileIntoBuffer (char *fname)
2155 {
2156   FILE *f;
2157   char *rs = NULL;
2158   int nch = 0;
2159   int ch;
2160   char lb[MAX_PATTERN_LEN];
2161
2162   if (!(f = fopen (fname, "r")))
2163     {
2164       fprintf (stderr, "cannot open peep rule file\n");
2165       return NULL;
2166     }
2167
2168   while ((ch = fgetc (f)) != EOF)
2169     {
2170       lb[nch++] = ch;
2171
2172       /* if we maxed out our local buffer */
2173       if (nch >= (MAX_PATTERN_LEN - 2))
2174         {
2175           lb[nch] = '\0';
2176           /* copy it into allocated buffer */
2177           if (rs)
2178             {
2179               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2180               strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
2181             }
2182           else
2183             {
2184               rs = Safe_strdup (lb);
2185             }
2186           nch = 0;
2187         }
2188     }
2189
2190   /* if some charaters left over */
2191   if (nch)
2192     {
2193       lb[nch] = '\0';
2194       /* copy it into allocated buffer */
2195       if (rs)
2196         {
2197           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2198           strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2199         }
2200       else
2201         {
2202           rs = Safe_strdup (lb);
2203         }
2204     }
2205   return rs;
2206 }
2207
2208 /*-----------------------------------------------------------------*/
2209 /* initPeepHole - initialises the peep hole optimizer stuff        */
2210 /*-----------------------------------------------------------------*/
2211 void
2212 initPeepHole ()
2213 {
2214   char *s;
2215
2216   /* read in the default rules */
2217   readRules (port->peep.default_rules);
2218
2219   /* if we have any additional file read it too */
2220   if (options.peep_file)
2221     {
2222       readRules (s = readFileIntoBuffer (options.peep_file));
2223       setToNull ((void *) &s);
2224     }
2225
2226
2227 #if !OPT_DISABLE_PIC
2228   /* Convert the peep rules into pcode.
2229      NOTE: this is only support in the PIC port (at the moment)
2230   */
2231         if (TARGET_IS_PIC)
2232                 peepRules2pCode(rootRules);
2233 #endif
2234
2235 #if !OPT_DISABLE_PIC16
2236   /* Convert the peep rules into pcode.
2237      NOTE: this is only support in the PIC port (at the moment)
2238        and the PIC16 port (VR 030601)
2239   */
2240         if (TARGET_IS_PIC16)
2241                 pic16_peepRules2pCode(rootRules);
2242
2243 #endif
2244
2245 }