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