* src/SDCCicode.c (geniCodeJumpTable): fixed bug #967601
[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, const 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 /* labelIsReturnOnly - Check if label %5 is followed by RET        */
183 /*-----------------------------------------------------------------*/
184 FBYNAME (labelIsReturnOnly)
185 {
186   /* assumes that %5 pattern variable has the label name */
187   const char *label, *p;
188   const lineNode *pl;
189   int len;
190
191   label = hTabItemWithKey (vars, 5);
192   if (!label) return FALSE;
193   len = strlen(label);
194
195   for(pl = currPl; pl; pl = pl->next) {
196         if (pl->line && !pl->isDebug && !pl->isComment &&
197           pl->line[strlen(pl->line)-1] == ':') {
198                 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
199                 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
200                   !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
201                   !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
202                   *(pl->line+5) != '$') {
203                         return FALSE; /* non-local label encountered */
204                 }
205         }
206   }
207   if (!pl) return FALSE; /* did not find the label */
208   pl = pl->next;
209   while (pl && (pl->isDebug || pl->isComment))
210     pl = pl->next;
211   if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
212   p = pl->line;
213   for (p = pl->line; *p && isspace(*p); p++)
214           ;
215   if (strcmp(p, "ret") == 0) return TRUE;
216   return FALSE;
217 }
218
219
220 /*-----------------------------------------------------------------*/
221 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other      */
222 /* usage of it in the code depends on a value from this section    */
223 /*-----------------------------------------------------------------*/
224 FBYNAME (okToRemoveSLOC)
225 {
226   const lineNode *pl;
227   const char *sloc, *p;
228   int dummy1, dummy2, dummy3;
229
230   /* assumes that %1 as the SLOC name */
231   sloc = hTabItemWithKey (vars, 1);
232   if (sloc == NULL) return FALSE;
233   p = strstr(sloc, "sloc");
234   if (p == NULL) return FALSE;
235   p += 4;
236   if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
237   /*TODO: ultra-paranoid: get funtion name from "head" and check that */
238   /* the sloc name begins with that.  Probably not really necessary */
239
240   /* Look for any occurance of this SLOC before the peephole match */
241   for (pl = currPl->prev; pl; pl = pl->prev) {
242         if (pl->line && !pl->isDebug && !pl->isComment
243           && *pl->line != ';' && strstr(pl->line, sloc))
244                 return FALSE;
245   }
246   /* Look for any occurance of this SLOC after the peephole match */
247   for (pl = endPl->next; pl; pl = pl->next) {
248         if (pl->line && !pl->isDebug && !pl->isComment
249           && *pl->line != ';' && strstr(pl->line, sloc))
250                 return FALSE;
251   }
252   return TRUE; /* safe for a peephole to remove it :) */
253 }
254
255
256 /*-----------------------------------------------------------------*/
257 /* operandsNotSame - check if %1 & %2 are the same                 */
258 /*-----------------------------------------------------------------*/
259 FBYNAME (operandsNotSame)
260 {
261   char *op1 = hTabItemWithKey (vars, 1);
262   char *op2 = hTabItemWithKey (vars, 2);
263
264   if (strcmp (op1, op2) == 0)
265     return FALSE;
266   else
267     return TRUE;
268 }
269
270 /*-----------------------------------------------------------------*/
271 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same    */
272 /*-----------------------------------------------------------------*/
273 FBYNAME (operandsNotSame3)
274 {
275   char *op1 = hTabItemWithKey (vars, 1);
276   char *op2 = hTabItemWithKey (vars, 2);
277   char *op3 = hTabItemWithKey (vars, 3);
278
279   if ( (strcmp (op1, op2) == 0) ||
280        (strcmp (op1, op3) == 0) ||
281        (strcmp (op2, op3) == 0) )
282     return FALSE;
283   else
284     return TRUE;
285 }
286
287 /*-----------------------------------------------------------------*/
288 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
289 /*-----------------------------------------------------------------*/
290 FBYNAME (operandsNotSame4)
291 {
292   char *op1 = hTabItemWithKey (vars, 1);
293   char *op2 = hTabItemWithKey (vars, 2);
294   char *op3 = hTabItemWithKey (vars, 3);
295   char *op4 = hTabItemWithKey (vars, 4);
296
297   if ( (strcmp (op1, op2) == 0) ||
298        (strcmp (op1, op3) == 0) ||
299        (strcmp (op1, op4) == 0) ||
300        (strcmp (op2, op3) == 0) ||
301        (strcmp (op2, op4) == 0) ||
302        (strcmp (op3, op4) == 0) )
303     return FALSE;
304   else
305     return TRUE;
306 }
307
308 /*-----------------------------------------------------------------*/
309 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
310 /*-----------------------------------------------------------------*/
311 FBYNAME (operandsNotSame5)
312 {
313   char *op1 = hTabItemWithKey (vars, 1);
314   char *op2 = hTabItemWithKey (vars, 2);
315   char *op3 = hTabItemWithKey (vars, 3);
316   char *op4 = hTabItemWithKey (vars, 4);
317   char *op5 = hTabItemWithKey (vars, 5);
318
319   if ( (strcmp (op1, op2) == 0) ||
320        (strcmp (op1, op3) == 0) ||
321        (strcmp (op1, op4) == 0) ||
322        (strcmp (op1, op5) == 0) ||
323        (strcmp (op2, op3) == 0) ||
324        (strcmp (op2, op4) == 0) ||
325        (strcmp (op2, op5) == 0) ||
326        (strcmp (op3, op4) == 0) ||
327        (strcmp (op3, op5) == 0) ||
328        (strcmp (op4, op5) == 0) )
329     return FALSE;
330   else
331     return TRUE;
332 }
333
334 /*-----------------------------------------------------------------*/
335 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
336 /*-----------------------------------------------------------------*/
337 FBYNAME (operandsNotSame6)
338 {
339   char *op1 = hTabItemWithKey (vars, 1);
340   char *op2 = hTabItemWithKey (vars, 2);
341   char *op3 = hTabItemWithKey (vars, 3);
342   char *op4 = hTabItemWithKey (vars, 4);
343   char *op5 = hTabItemWithKey (vars, 5);
344   char *op6 = hTabItemWithKey (vars, 6);
345
346   if ( (strcmp (op1, op2) == 0) ||
347        (strcmp (op1, op3) == 0) ||
348        (strcmp (op1, op4) == 0) ||
349        (strcmp (op1, op5) == 0) ||
350        (strcmp (op1, op6) == 0) ||
351        (strcmp (op2, op3) == 0) ||
352        (strcmp (op2, op4) == 0) ||
353        (strcmp (op2, op5) == 0) ||
354        (strcmp (op2, op6) == 0) ||
355        (strcmp (op3, op4) == 0) ||
356        (strcmp (op3, op5) == 0) ||
357        (strcmp (op3, op6) == 0) ||
358        (strcmp (op4, op5) == 0) ||
359        (strcmp (op4, op6) == 0) ||
360        (strcmp (op5, op6) == 0) )
361     return FALSE;
362   else
363     return TRUE;
364 }
365
366
367 /*-----------------------------------------------------------------*/
368 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
369 /*-----------------------------------------------------------------*/
370 FBYNAME (operandsNotSame7)
371 {
372   char *op1 = hTabItemWithKey (vars, 1);
373   char *op2 = hTabItemWithKey (vars, 2);
374   char *op3 = hTabItemWithKey (vars, 3);
375   char *op4 = hTabItemWithKey (vars, 4);
376   char *op5 = hTabItemWithKey (vars, 5);
377   char *op6 = hTabItemWithKey (vars, 6);
378   char *op7 = hTabItemWithKey (vars, 7);
379
380   if ( (strcmp (op1, op2) == 0) ||
381        (strcmp (op1, op3) == 0) ||
382        (strcmp (op1, op4) == 0) ||
383        (strcmp (op1, op5) == 0) ||
384        (strcmp (op1, op6) == 0) ||
385        (strcmp (op1, op7) == 0) ||
386        (strcmp (op2, op3) == 0) ||
387        (strcmp (op2, op4) == 0) ||
388        (strcmp (op2, op5) == 0) ||
389        (strcmp (op2, op6) == 0) ||
390        (strcmp (op2, op7) == 0) ||
391        (strcmp (op3, op4) == 0) ||
392        (strcmp (op3, op5) == 0) ||
393        (strcmp (op3, op6) == 0) ||
394        (strcmp (op3, op7) == 0) ||
395        (strcmp (op4, op5) == 0) ||
396        (strcmp (op4, op6) == 0) ||
397        (strcmp (op4, op7) == 0) ||
398        (strcmp (op5, op6) == 0) ||
399        (strcmp (op5, op7) == 0) ||
400        (strcmp (op6, op7) == 0) )
401     return FALSE;
402   else
403     return TRUE;
404 }
405
406 /*-----------------------------------------------------------------*/
407 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
408 /*-----------------------------------------------------------------*/
409 FBYNAME (operandsNotSame8)
410 {
411   char *op1 = hTabItemWithKey (vars, 1);
412   char *op2 = hTabItemWithKey (vars, 2);
413   char *op3 = hTabItemWithKey (vars, 3);
414   char *op4 = hTabItemWithKey (vars, 4);
415   char *op5 = hTabItemWithKey (vars, 5);
416   char *op6 = hTabItemWithKey (vars, 6);
417   char *op7 = hTabItemWithKey (vars, 7);
418   char *op8 = hTabItemWithKey (vars, 8);
419
420   if ( (strcmp (op1, op2) == 0) ||
421        (strcmp (op1, op3) == 0) ||
422        (strcmp (op1, op4) == 0) ||
423        (strcmp (op1, op5) == 0) ||
424        (strcmp (op1, op6) == 0) ||
425        (strcmp (op1, op7) == 0) ||
426        (strcmp (op1, op8) == 0) ||
427        (strcmp (op2, op3) == 0) ||
428        (strcmp (op2, op4) == 0) ||
429        (strcmp (op2, op5) == 0) ||
430        (strcmp (op2, op6) == 0) ||
431        (strcmp (op2, op7) == 0) ||
432        (strcmp (op2, op8) == 0) ||
433        (strcmp (op3, op4) == 0) ||
434        (strcmp (op3, op5) == 0) ||
435        (strcmp (op3, op6) == 0) ||
436        (strcmp (op3, op7) == 0) ||
437        (strcmp (op3, op8) == 0) ||
438        (strcmp (op4, op5) == 0) ||
439        (strcmp (op4, op6) == 0) ||
440        (strcmp (op4, op7) == 0) ||
441        (strcmp (op4, op8) == 0) ||
442        (strcmp (op5, op6) == 0) ||
443        (strcmp (op5, op7) == 0) ||
444        (strcmp (op5, op8) == 0) ||
445        (strcmp (op6, op7) == 0) ||
446        (strcmp (op6, op8) == 0) ||
447        (strcmp (op7, op8) == 0) )
448     return FALSE;
449   else
450     return TRUE;
451 }
452
453
454 /* labelRefCount:
455
456  * takes two parameters: a variable (bound to a label name)
457  * and an expected reference count.
458  *
459  * Returns TRUE if that label is defined and referenced exactly
460  * the given number of times.
461  */
462 FBYNAME (labelRefCount)
463 {
464   int varNumber, expectedRefCount;
465   bool rc = FALSE;
466
467   /* If we don't have the label hash table yet, build it. */
468   if (!labelHash)
469     {
470       buildLabelRefCountHash (head);
471     }
472
473   if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
474     {
475       char *label = hTabItemWithKey (vars, varNumber);
476
477       if (label)
478         {
479           labelHashEntry *entry;
480
481           entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
482
483           while (entry)
484             {
485               if (!strcmp (label, entry->name))
486                 {
487                   break;
488                 }
489               entry = hTabNextItemWK (labelHash);
490             }
491           if (entry)
492             {
493 #if 0
494               /* debug spew. */
495               fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
496                        label, entry->refCount, expectedRefCount);
497 #endif
498
499               rc = (expectedRefCount == entry->refCount);
500             }
501           else
502             {
503               fprintf (stderr, "*** internal error: no label has entry for"
504                        " %s in labelRefCount peephole.\n",
505                        label);
506             }
507         }
508       else
509         {
510           fprintf (stderr, "*** internal error: var %d not bound"
511                    " in peephole labelRefCount rule.\n",
512                    varNumber);
513         }
514
515     }
516   else
517     {
518       fprintf (stderr,
519                "*** internal error: labelRefCount peephole restriction"
520                " malformed: %s\n", cmdLine);
521     }
522   return rc;
523 }
524
525 /* Within the context of the lines currPl through endPl, determine
526 ** if the variable var contains a symbol that is volatile. Returns
527 ** TRUE only if it is certain that this was not volatile (the symbol
528 ** was found and not volatile, or var was a constant or CPU register).
529 ** Returns FALSE if the symbol was found and volatile, the symbol was
530 ** not found, or var was a indirect/pointer addressing mode.
531 */
532 static bool
533 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
534 {
535   char symname[SDCC_NAME_MAX + 1];
536   char *p = symname;
537   char *vp = var;
538   lineNode *cl;
539   operand *op;
540   iCode *last_ic;
541
542   /* Can't tell if indirect accesses are volatile or not, so
543   ** assume they are, just to be safe.
544   */
545   if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
546     {
547       if (*var=='@')
548         return FALSE;
549     }
550   if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
551     {
552       if (strstr(var,"(bc)"))
553         return FALSE;
554       if (strstr(var,"(de)"))
555         return FALSE;
556       if (strstr(var,"(hl)"))
557         return FALSE;
558       if (strstr(var,"(ix"))
559         return FALSE;
560       if (strstr(var,"(iy"))
561         return FALSE;
562     }
563
564   /* Extract a symbol name from the variable */
565   while (*vp && (*vp!='_'))
566     vp++;
567   while (*vp && (isalnum(*vp) || *vp=='_'))
568     *p++ = *vp++;
569   *p='\0';
570
571   if (!symname[0])
572     {
573       /* Nothing resembling a symbol name was found, so it can't
574          be volatile
575       */
576       return TRUE;
577     }
578
579   last_ic = NULL;
580   for (cl = currPl; cl!=endPl->next; cl = cl->next)
581   {
582     if (cl->ic && (cl->ic!=last_ic))
583       {
584         last_ic = cl->ic;
585         switch (cl->ic->op)
586           {
587           case IFX:
588             op = IC_COND (cl->ic);
589             if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
590               return !op->isvolatile;
591           case JUMPTABLE:
592             op = IC_JTCOND (cl->ic);
593             if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
594               return !op->isvolatile;
595           default:
596             op = IC_LEFT (cl->ic);
597             if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
598               return !op->isvolatile;
599             op = IC_RIGHT (cl->ic);
600             if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
601               return !op->isvolatile;
602             op = IC_RESULT (cl->ic);
603             if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
604               return !op->isvolatile;
605           }
606       }
607   }
608   
609   /* Couldn't find the symbol for some reason. Assume volatile. */
610   return FALSE;
611 }
612
613 /*  notVolatile:
614  *
615  *  This rule restriction has two different behaviours depending on
616  *  the number of parameters given.
617  *
618  *    if notVolatile                 (no parameters given)
619  *       The rule is applied only if none of the iCodes originating
620  *       the matched pattern reference a volatile operand.
621  *
622  *    if notVolatile %1 ...          (one or more parameters given)
623  *       The rule is applied if the parameters are not expressions
624  *       containing volatile symbols and are not pointer accesses.
625  *
626  */
627 FBYNAME (notVolatile)
628 {
629   int varNumber;
630   char *var;
631   bool notvol;
632   char *digitend;
633   lineNode *cl;
634   operand *op;
635
636   if (!cmdLine)
637     {
638       /* If no parameters given, just scan the iCodes for volatile operands */
639       for (cl = currPl; cl!=endPl->next; cl = cl->next)
640       {
641         if (cl->ic)
642           {
643             switch (cl->ic->op)
644               {
645               case IFX:
646                 op = IC_COND (cl->ic);
647                 if (IS_SYMOP (op) && op->isvolatile)
648                   return FALSE;
649               case JUMPTABLE:
650                 op = IC_JTCOND (cl->ic);
651                 if (IS_SYMOP (op) && op->isvolatile)
652                   return FALSE;
653               default:
654                 op = IC_LEFT (cl->ic);
655                 if (IS_SYMOP (op) && op->isvolatile)
656                   return FALSE;
657                 op = IC_RIGHT (cl->ic);
658                 if (IS_SYMOP (op) && op->isvolatile)
659                   return FALSE;
660                 op = IC_RESULT (cl->ic);
661                 if (IS_SYMOP (op) && op->isvolatile)
662                   return FALSE;
663               }
664           }
665       }
666       return TRUE;
667     }
668
669   /* There were parameters; check the volatility of each */
670   while (*cmdLine && isspace(*cmdLine))
671     cmdLine++;
672   while (*cmdLine)
673     {
674       if (*cmdLine!='%')
675         goto error;
676       cmdLine++;
677       if (!isdigit(*cmdLine))
678         goto error;
679       varNumber = strtol(cmdLine, &digitend, 10);
680       cmdLine = digitend;
681       while (*cmdLine && isspace(*cmdLine))
682         cmdLine++;
683
684       var = hTabItemWithKey (vars, varNumber);
685
686       if (var)
687         {
688           notvol = notVolatileVariable (var, currPl, endPl);
689           if (!notvol)
690             return FALSE;
691         }
692       else
693         {
694           fprintf (stderr, "*** internal error: var %d not bound"
695                    " in peephole notVolatile rule.\n",
696                    varNumber);
697           return FALSE;
698         }
699     }
700
701   return TRUE;
702     
703     
704 error:
705   fprintf (stderr,
706            "*** internal error: notVolatile peephole restriction"
707            " malformed: %s\n", cmdLine);
708   return FALSE;
709 }
710     
711
712 /*-----------------------------------------------------------------*/
713 /* callFuncByName - calls a function as defined in the table       */
714 /*-----------------------------------------------------------------*/
715 int 
716 callFuncByName (char *fname,
717                 hTab * vars,
718                 lineNode * currPl,
719                 lineNode * endPl,
720                 lineNode * head)
721 {
722   struct ftab
723   {
724     char *fname;
725     int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
726   }
727   ftab[] =
728   {
729     {
730       "labelInRange", labelInRange
731     }
732     ,
733     {
734       "operandsNotSame", operandsNotSame
735     }
736     ,
737     {
738       "operandsNotSame3", operandsNotSame3
739     }
740     ,
741     {
742       "operandsNotSame4", operandsNotSame4
743     }
744     ,
745     {
746       "operandsNotSame5", operandsNotSame5
747     }
748     ,
749     {
750       "operandsNotSame6", operandsNotSame6
751     }
752     ,
753     {
754       "operandsNotSame7", operandsNotSame7
755     }
756     ,
757     {
758       "operandsNotSame8", operandsNotSame8
759     }
760     ,     
761     {
762       "24bitMode", flat24bitMode
763     }
764     ,
765     {
766       "xramMovcOption", xramMovcOption
767     }
768     ,
769     {
770       "labelRefCount", labelRefCount
771     }
772     ,
773     {
774       "portIsDS390", portIsDS390
775     },
776     {
777       "labelIsReturnOnly", labelIsReturnOnly
778     },
779     {
780       "okToRemoveSLOC", okToRemoveSLOC
781     },
782     {
783       "24bitModeAndPortDS390", flat24bitModeAndPortDS390
784     },
785     {
786       "notVolatile", notVolatile
787     }
788   };
789   int   i;
790   char  *cmdCopy, *funcName, *funcArgs;
791   int   rc = -1;
792     
793   /* Isolate the function name part (we are passed the full condition 
794    * string including arguments) 
795    */
796   cmdCopy = Safe_strdup(fname);
797   funcName = strtok(cmdCopy, " \t");
798   funcArgs = strtok(NULL, "");
799
800     for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
801     {
802         if (strcmp (ftab[i].fname, funcName) == 0)
803         {
804             rc = (*ftab[i].func) (vars, currPl, endPl, head,
805                                   funcArgs);
806         }
807     }
808     
809     if (rc == -1)
810     {
811         fprintf (stderr, 
812                  "could not find named function \"%s\" in "
813                  "peephole function table\n",
814                  funcName);
815         // If the function couldn't be found, let's assume it's
816         // a bad rule and refuse it.
817         rc = FALSE;
818     }
819
820     Safe_free(cmdCopy);
821     
822   return rc;
823 }
824
825 /*-----------------------------------------------------------------*/
826 /* printLine - prints a line chain into a given file               */
827 /*-----------------------------------------------------------------*/
828 void 
829 printLine (lineNode * head, FILE * of)
830 {
831   iCode *last_ic = NULL;
832   bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
833   
834   if (!of)
835     of = stdout;
836
837   while (head)
838     {
839       if (head->ic!=last_ic)
840         {
841           last_ic = head->ic;
842           if (debug_iCode_tracking)
843             {
844               if (head->ic)
845                 fprintf (of, "; block = %d, seq = %d\n",
846                          head->ic->block, head->ic->seq);
847               else
848                 fprintf (of, "; iCode lost\n");
849             }
850         }
851         
852       /* don't indent comments & labels */
853       if (head->line &&
854           (*head->line == ';' ||
855            head->line[strlen (head->line) - 1] == ':')) {
856         fprintf (of, "%s\n", head->line);
857       } else {
858         if (head->isInline && *head->line=='#') {
859           // comment out preprocessor directives in inline asm
860           fprintf (of, ";");
861         }
862         fprintf (of, "\t%s\n", head->line);
863       }
864       head = head->next;
865     }
866 }
867
868 /*-----------------------------------------------------------------*/
869 /* newPeepRule - creates a new peeprule and attach it to the root  */
870 /*-----------------------------------------------------------------*/
871 peepRule *
872 newPeepRule (lineNode * match,
873              lineNode * replace,
874              char *cond,
875              int restart)
876 {
877   peepRule *pr;
878
879   pr = Safe_alloc ( sizeof (peepRule));
880   pr->match = match;
881   pr->replace = replace;
882   pr->restart = restart;
883
884   if (cond && *cond)
885     {
886       pr->cond = Safe_strdup (cond);
887     }
888   else
889     pr->cond = NULL;
890
891   pr->vars = newHashTable (100);
892
893   /* if root is empty */
894   if (!rootRules)
895     rootRules = currRule = pr;
896   else
897     currRule = currRule->next = pr;
898
899   return pr;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* newLineNode - creates a new peep line                           */
904 /*-----------------------------------------------------------------*/
905 lineNode *
906 newLineNode (char *line)
907 {
908   lineNode *pl;
909
910   pl = Safe_alloc ( sizeof (lineNode));
911   pl->line = Safe_strdup (line);
912   pl->ic = NULL;
913   return pl;
914 }
915
916 /*-----------------------------------------------------------------*/
917 /* connectLine - connects two lines                                */
918 /*-----------------------------------------------------------------*/
919 lineNode *
920 connectLine (lineNode * pl1, lineNode * pl2)
921 {
922   if (!pl1 || !pl2)
923     {
924       fprintf (stderr, "trying to connect null line\n");
925       return NULL;
926     }
927
928   pl2->prev = pl1;
929   pl1->next = pl2;
930
931   return pl2;
932 }
933
934 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
935                          if (!*x) { fprintf(stderr,y); return ; } }
936
937 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
938                            if (!*x) { fprintf(stderr,z); return ; } }
939 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
940                            if (!*x) { fprintf(stderr,z); return ; } }
941
942 /*-----------------------------------------------------------------*/
943 /* getPeepLine - parses the peep lines                             */
944 /*-----------------------------------------------------------------*/
945 static void 
946 getPeepLine (lineNode ** head, char **bpp)
947 {
948   char lines[MAX_PATTERN_LEN];
949   char *lp;
950   int isComment;
951
952   lineNode *currL = NULL;
953   char *bp = *bpp;
954   while (1)
955     {
956
957       if (!*bp)
958         {
959           fprintf (stderr, "unexpected end of match pattern\n");
960           return;
961         }
962
963       if (*bp == '\n')
964         {
965           bp++;
966           while (isspace (*bp) ||
967                  *bp == '\n')
968             bp++;
969         }
970
971       if (*bp == '}')
972         {
973           bp++;
974           break;
975         }
976
977       /* read till end of line */
978       lp = lines;
979       while ((*bp != '\n' && *bp != '}') && *bp)
980         *lp++ = *bp++;
981       *lp = '\0';
982       
983       lp = lines;
984       while (*lp && isspace(*lp))
985         lp++;
986       isComment = (*lp == ';');
987         
988       if (!isComment || (isComment && !options.noPeepComments))
989         {
990           if (!currL)
991             *head = currL = newLineNode (lines);
992           else
993             currL = connectLine (currL, newLineNode (lines));
994           currL->isComment = isComment;
995         }
996
997     }
998
999   *bpp = bp;
1000 }
1001
1002 /*-----------------------------------------------------------------*/
1003 /* readRules - reads the rules from a string buffer                */
1004 /*-----------------------------------------------------------------*/
1005 static void 
1006 readRules (char *bp)
1007 {
1008   char restart = 0;
1009   char lines[MAX_PATTERN_LEN];
1010   char *lp;
1011   lineNode *match;
1012   lineNode *replace;
1013   lineNode *currL = NULL;
1014
1015   if (!bp)
1016     return;
1017 top:
1018   restart = 0;
1019   /* look for the token "replace" that is the
1020      start of a rule */
1021   while (*bp && strncmp (bp, "replace", 7))
1022     bp++;
1023
1024   /* if not found */
1025   if (!*bp)
1026     return;
1027
1028   /* then look for either "restart" or '{' */
1029   while (strncmp (bp, "restart", 7) &&
1030          *bp != '{' && bp)
1031     bp++;
1032
1033   /* not found */
1034   if (!*bp)
1035     {
1036       fprintf (stderr, "expected 'restart' or '{'\n");
1037       return;
1038     }
1039
1040   /* if brace */
1041   if (*bp == '{')
1042     bp++;
1043   else
1044     {                           /* must be restart */
1045       restart++;
1046       bp += strlen ("restart");
1047       /* look for '{' */
1048       EXPECT_CHR (bp, '{', "expected '{'\n");
1049       bp++;
1050     }
1051
1052   /* skip thru all the blank space */
1053   SKIP_SPACE (bp, "unexpected end of rule\n");
1054
1055   match = replace = currL = NULL;
1056   /* we are the start of a rule */
1057   getPeepLine (&match, &bp);
1058
1059   /* now look for by */
1060   EXPECT_STR (bp, "by", "expected 'by'\n");
1061
1062   /* then look for a '{' */
1063   EXPECT_CHR (bp, '{', "expected '{'\n");
1064   bp++;
1065
1066   SKIP_SPACE (bp, "unexpected end of rule\n");
1067   getPeepLine (&replace, &bp);
1068
1069   /* look for a 'if' */
1070   while ((isspace (*bp) || *bp == '\n') && *bp)
1071     bp++;
1072
1073   if (strncmp (bp, "if", 2) == 0)
1074     {
1075       bp += 2;
1076       while ((isspace (*bp) || *bp == '\n') && *bp)
1077         bp++;
1078       if (!*bp)
1079         {
1080           fprintf (stderr, "expected condition name\n");
1081           return;
1082         }
1083
1084       /* look for the condition */
1085       lp = lines;
1086       while (*bp && (*bp != '\n'))
1087         {
1088           *lp++ = *bp++;
1089         }
1090       *lp = '\0';
1091
1092       newPeepRule (match, replace, lines, restart);
1093     }
1094   else
1095     newPeepRule (match, replace, NULL, restart);
1096   goto top;
1097
1098 }
1099
1100 /*-----------------------------------------------------------------*/
1101 /* keyForVar - returns the numeric key for a var                   */
1102 /*-----------------------------------------------------------------*/
1103 static int 
1104 keyForVar (char *d)
1105 {
1106   int i = 0;
1107
1108   while (isdigit (*d))
1109     {
1110       i *= 10;
1111       i += (*d++ - '0');
1112     }
1113
1114   return i;
1115 }
1116
1117 /*-----------------------------------------------------------------*/
1118 /* bindVar - binds a value to a variable in the given hashtable    */
1119 /*-----------------------------------------------------------------*/
1120 static void 
1121 bindVar (int key, char **s, hTab ** vtab)
1122 {
1123   char vval[MAX_PATTERN_LEN];
1124   char *vvx;
1125   char *vv = vval;
1126
1127   /* first get the value of the variable */
1128   vvx = *s;
1129   /* the value is ended by a ',' or space or newline or null or ) */
1130   while (*vvx &&
1131          *vvx != ',' &&
1132          !isspace (*vvx) &&
1133          *vvx != '\n' &&
1134          *vvx != ':' &&
1135          *vvx != ')')
1136     {
1137       char ubb = 0;
1138       /* if we find a '(' then we need to balance it */
1139       if (*vvx == '(')
1140         {
1141           ubb++;
1142           while (ubb)
1143             {
1144               *vv++ = *vvx++;
1145               if (*vvx == '(')
1146                 ubb++;
1147               if (*vvx == ')')
1148                 ubb--;
1149             }
1150           // include the trailing ')'
1151           *vv++ = *vvx++;
1152         }
1153       else
1154         *vv++ = *vvx++;
1155     }
1156   *s = vvx;
1157   *vv = '\0';
1158   /* got value */
1159   vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1160
1161   hTabAddItem (vtab, key, vvx);
1162 }
1163
1164 /*-----------------------------------------------------------------*/
1165 /* matchLine - matches one line                                    */
1166 /*-----------------------------------------------------------------*/
1167 static bool 
1168 matchLine (char *s, char *d, hTab ** vars)
1169 {
1170
1171   if (!s || !(*s))
1172     return FALSE;
1173
1174   while (*s && *d)
1175     {
1176
1177       /* skip white space in both */
1178       while (isspace (*s))
1179         s++;
1180       while (isspace (*d))
1181         d++;
1182
1183       /* if the destination is a var */
1184       if (*d == '%' && isdigit (*(d + 1)) && vars)
1185         {
1186           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1187           /* if the variable is already bound
1188              then it MUST match with dest */
1189           if (v)
1190             {
1191               while (*v)
1192                 if (*v++ != *s++)
1193                   return FALSE;
1194             }
1195           else
1196             /* variable not bound we need to
1197                bind it */
1198             bindVar (keyForVar (d + 1), &s, vars);
1199
1200           /* in either case go past the variable */
1201           d++;
1202           while (isdigit (*d))
1203             d++;
1204
1205           while (isspace (*s))
1206             s++;
1207           while (isspace (*d))
1208             d++;
1209         }
1210
1211       /* they should be an exact match other wise */
1212       if (*s && *d)
1213         {
1214           if (*s++ != *d++)
1215             return FALSE;
1216         }
1217
1218     }
1219
1220   /* get rid of the trailing spaces
1221      in both source & destination */
1222   if (*s)
1223     while (isspace (*s))
1224       s++;
1225
1226   if (*d)
1227     while (isspace (*d))
1228       d++;
1229
1230   /* after all this if only one of them
1231      has something left over then no match */
1232   if (*s || *d)
1233     return FALSE;
1234
1235   return TRUE;
1236 }
1237
1238 /*-----------------------------------------------------------------*/
1239 /* matchRule - matches a all the rule lines                        */
1240 /*-----------------------------------------------------------------*/
1241 static bool 
1242 matchRule (lineNode * pl,
1243            lineNode ** mtail,
1244            peepRule * pr,
1245            lineNode * head)
1246 {
1247   lineNode *spl;                /* source pl */
1248   lineNode *rpl;                /* rule peep line */
1249
1250 /*     setToNull((void *) &pr->vars);    */
1251 /*     pr->vars = newHashTable(100); */
1252
1253   /* for all the lines defined in the rule */
1254   rpl = pr->match;
1255   spl = pl;
1256   while (spl && rpl)
1257     {
1258
1259       /* if the source line starts with a ';' then
1260          comment line don't process or the source line
1261          contains == . debugger information skip it */
1262       if (spl->line &&
1263           (*spl->line == ';' || spl->isDebug))
1264         {
1265           spl = spl->next;
1266           continue;
1267         }
1268
1269       if (!matchLine (spl->line, rpl->line, &pr->vars))
1270         return FALSE;
1271
1272       rpl = rpl->next;
1273       if (rpl)
1274         spl = spl->next;
1275     }
1276
1277   /* if rules ended */
1278   if (!rpl)
1279     {
1280       /* if this rule has additional conditions */
1281       if (pr->cond)
1282         {
1283           if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1284             {
1285               *mtail = spl;
1286               return TRUE;
1287             }
1288           else
1289             return FALSE;
1290         }
1291       else
1292         {
1293           *mtail = spl;
1294           return TRUE;
1295         }
1296     }
1297   else
1298     return FALSE;
1299 }
1300
1301 static void
1302 reassociate_ic_down (lineNode *shead, lineNode *stail,
1303                      lineNode *rhead, lineNode *rtail)
1304 {
1305   lineNode *csl;        /* current source line */
1306   lineNode *crl;        /* current replacement line */
1307
1308   csl = shead;
1309   crl = rhead;
1310   while (1)
1311     {
1312       /* skip over any comments */
1313       while (csl!=stail->next && csl->isComment)
1314         csl = csl->next;
1315       while (crl!=rtail->next && crl->isComment)
1316         crl = crl->next;
1317
1318       /* quit if we reach the end */
1319       if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1320         break;
1321
1322       if (matchLine(csl->line,crl->line,NULL))
1323         {
1324           crl->ic = csl->ic;
1325           csl = csl->next;
1326           crl = crl->next;
1327         }
1328       else
1329         break;
1330     }
1331 }
1332
1333 static void
1334 reassociate_ic_up (lineNode *shead, lineNode *stail,
1335                    lineNode *rhead, lineNode *rtail)
1336 {
1337   lineNode *csl;        /* current source line */
1338   lineNode *crl;        /* current replacement line */
1339
1340   csl = stail;
1341   crl = rtail;
1342   while (1)
1343     {
1344       /* skip over any comments */
1345       while (csl!=shead->prev && csl->isComment)
1346         csl = csl->prev;
1347       while (crl!=rhead->prev && crl->isComment)
1348         crl = crl->prev;
1349
1350       /* quit if we reach the end */
1351       if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1352         break;
1353
1354       if (matchLine(csl->line,crl->line,NULL))
1355         {
1356           crl->ic = csl->ic;
1357           csl = csl->prev;
1358           crl = crl->prev;
1359         }
1360       else
1361         break;
1362     }
1363 }
1364
1365 /*------------------------------------------------------------------*/
1366 /* reassociate_ic - reassociate replacement lines with origin iCode */
1367 /*------------------------------------------------------------------*/
1368 static void
1369 reassociate_ic (lineNode *shead, lineNode *stail,
1370                 lineNode *rhead, lineNode *rtail)
1371 {
1372   lineNode *csl;        /* current source line */
1373   lineNode *crl;        /* current replacement line */
1374   bool single_iCode;
1375   iCode *ic;
1376   
1377   /* Check to see if all the source lines (excluding comments) came
1378   ** for the same iCode
1379   */
1380   ic = NULL;
1381   for (csl=shead;csl!=stail->next;csl=csl->next)
1382     if (csl->ic && !csl->isComment)
1383       {
1384         ic = csl->ic;
1385         break;
1386       }
1387   single_iCode = (ic!=NULL);
1388   for (csl=shead;csl!=stail->next;csl=csl->next)
1389     if ((csl->ic != ic) && !csl->isComment)
1390       {
1391         /* More than one iCode was found. However, if it's just the
1392         ** last line with the different iCode and it was not changed
1393         ** in the replacement, everything else must be the first iCode.
1394         */
1395         if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1396           {
1397             rtail->ic = stail->ic;
1398             for (crl=rhead;crl!=rtail;crl=crl->next)
1399               crl->ic = ic;
1400             return;
1401           }
1402             
1403         single_iCode = FALSE;
1404         break;
1405       }
1406   
1407   /* If all of the source lines came from the same iCode, then so have
1408   ** all of the replacement lines too.
1409   */
1410   if (single_iCode)
1411     {
1412       for (crl=rhead;crl!=rtail->next;crl=crl->next)
1413         crl->ic = ic;
1414       return;
1415     }
1416   
1417   /* The source lines span iCodes, so we may end up with replacement
1418   ** lines that we don't know which iCode(s) to associate with. Do the
1419   ** best we can by using the following strategies:
1420   **    1) Start at the top and scan down. As long as the source line
1421   **       matches the replacement line, they have the same iCode.
1422   **    2) Start at the bottom and scan up. As long as the source line
1423   **       matches the replacement line, they have the same iCode.
1424   **    3) For any label in the source, look for a matching label in
1425   **       the replacment. If found, they have the same iCode. From
1426   **       these matching labels, scan down for additional matching
1427   **       lines; if found, they also have the same iCode.
1428   */
1429
1430   /* Strategy #1: Start at the top and scan down for matches
1431   */
1432   reassociate_ic_down(shead,stail,rhead,rtail);
1433   
1434   /* Strategy #2: Start at the bottom and scan up for matches
1435   */
1436   reassociate_ic_up(shead,stail,rhead,rtail);
1437
1438   /* Strategy #3: Try to match labels
1439   */
1440   csl = shead;
1441   while (1)
1442     {
1443       const char *labelStart;
1444       int labelLength;
1445       
1446       /* skip over any comments */
1447       while (csl!=stail->next && csl->isComment)
1448         csl = csl->next;
1449       if (csl==stail->next)
1450         break;
1451
1452       if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1453         {
1454           /* found a source line label; look for it in the replacment lines */
1455           crl = rhead;
1456           while (1)
1457             {
1458               while (crl!=rtail->next && crl->isComment)
1459                 crl = crl->next;
1460               if (crl==rtail->next)
1461                 break;
1462               if (matchLine(csl->line, crl->line, NULL))
1463                 {
1464                   reassociate_ic_down(csl,stail,crl,rtail);
1465                   break;
1466                 }
1467               else
1468                 crl = crl->next;
1469             }
1470         }
1471       csl = csl->next;
1472     }
1473   
1474   /* Try to assign a meaningful iCode to any comment that is missing
1475      one. Since they are comments, it's ok to make mistakes; we are just
1476      trying to improve continuity to simplify other tests.
1477   */
1478   ic = NULL;
1479   for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1480     {
1481       if (!crl->ic && ic && crl->isComment)
1482         crl->ic = ic;
1483       ic = crl->ic;
1484     }
1485 }
1486
1487                   
1488 /*-----------------------------------------------------------------*/
1489 /* replaceRule - does replacement of a matching pattern            */
1490 /*-----------------------------------------------------------------*/
1491 static void 
1492 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1493 {
1494   lineNode *cl = NULL;
1495   lineNode *pl = NULL, *lhead = NULL;
1496   /* a long function name and long variable name can evaluate to
1497      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1498   char lb[MAX_PATTERN_LEN*4];
1499   char *lbp;
1500   lineNode *comment = NULL;
1501
1502   /* collect all the comment lines in the source */
1503   for (cl = *shead; cl != stail; cl = cl->next)
1504     {
1505       if (cl->line && (*cl->line == ';' || cl->isDebug))
1506         {
1507           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1508                 (comment = newLineNode (cl->line)));
1509           pl->isDebug = cl->isDebug;
1510           pl->isComment = cl->isComment || (*cl->line == ';');
1511         }
1512     }
1513   cl = NULL;
1514
1515   /* for all the lines in the replacement pattern do */
1516   for (pl = pr->replace; pl; pl = pl->next)
1517     {
1518       char *v;
1519       char *l;
1520       lbp = lb;
1521
1522       l = pl->line;
1523
1524       while (*l)
1525         {
1526           /* if the line contains a variable */
1527           if (*l == '%' && isdigit (*(l + 1)))
1528             {
1529               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1530               if (!v)
1531                 {
1532                   fprintf (stderr, "used unbound variable in replacement\n");
1533                   l++;
1534                   continue;
1535                 }
1536               while (*v) {
1537                 *lbp++ = *v++;
1538               }
1539               l++;
1540               while (isdigit (*l)) {
1541                 l++;
1542               }
1543               continue;
1544             }
1545           *lbp++ = *l++;
1546         }
1547
1548       *lbp = '\0';
1549       if (cl)
1550         cl = connectLine (cl, newLineNode (lb));
1551       else
1552         lhead = cl = newLineNode (lb);
1553       cl->isComment = pl->isComment;
1554     }
1555
1556   /* add the comments if any to the head of list */
1557   if (comment)
1558     {
1559       lineNode *lc = comment;
1560       while (lc->next)
1561         lc = lc->next;
1562       lc->next = lhead;
1563       if (lhead)
1564         lhead->prev = lc;
1565       lhead = comment;
1566     }
1567
1568   if (lhead)
1569     {
1570       /* determine which iCodes the replacment lines relate to */
1571       reassociate_ic(*shead,stail,lhead,cl);
1572
1573       /* now we need to connect / replace the original chain */
1574       /* if there is a prev then change it */
1575       if ((*shead)->prev)
1576         {
1577           (*shead)->prev->next = lhead;
1578           lhead->prev = (*shead)->prev;
1579         }
1580       *shead = lhead;
1581       /* now for the tail */
1582       if (stail && stail->next)
1583         {
1584           stail->next->prev = cl;
1585           if (cl)
1586             cl->next = stail->next;
1587         }
1588     }
1589   else
1590     {
1591       /* the replacement is empty - delete the source lines */
1592       if ((*shead)->prev)
1593         (*shead)->prev->next = stail->next;
1594       if (stail->next)
1595         stail->next->prev = (*shead)->prev;
1596       *shead = stail->next;
1597     }
1598 }
1599
1600 /* Returns TRUE if this line is a label definition.
1601
1602  * If so, start will point to the start of the label name,
1603  * and len will be it's length.
1604  */
1605 bool 
1606 isLabelDefinition (const char *line, const char **start, int *len)
1607 {
1608   const char *cp = line;
1609
1610   /* This line is a label if if consists of:
1611    * [optional whitespace] followed by identifier chars
1612    * (alnum | $ | _ ) followed by a colon.
1613    */
1614
1615   while (*cp && isspace (*cp))
1616     {
1617       cp++;
1618     }
1619
1620   if (!*cp)
1621     {
1622       return FALSE;
1623     }
1624
1625   *start = cp;
1626
1627   while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1628     {
1629       cp++;
1630     }
1631
1632   if ((cp == *start) || (*cp != ':'))
1633     {
1634       return FALSE;
1635     }
1636
1637   *len = (cp - (*start));
1638   return TRUE;
1639 }
1640
1641 /* Quick & dirty string hash function. */
1642 static int 
1643 hashSymbolName (const char *name)
1644 {
1645   int hash = 0;
1646
1647   while (*name)
1648     {
1649       hash = (hash << 6) ^ *name;
1650       name++;
1651     }
1652
1653   if (hash < 0)
1654     {
1655       hash = -hash;
1656     }
1657
1658   return hash % HTAB_SIZE;
1659 }
1660
1661 /* Build a hash of all labels in the passed set of lines
1662  * and how many times they are referenced.
1663  */
1664 static void 
1665 buildLabelRefCountHash (lineNode * head)
1666 {
1667   lineNode *line;
1668   const char *label;
1669   int labelLen;
1670   int i;
1671
1672   assert (labelHash == NULL);
1673   labelHash = newHashTable (HTAB_SIZE);
1674
1675   /* First pass: locate all the labels. */
1676   line = head;
1677
1678   while (line)
1679     {
1680       if (isLabelDefinition (line->line, &label, &labelLen)
1681           && labelLen <= SDCC_NAME_MAX)
1682         {
1683           labelHashEntry *entry;
1684
1685           entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1686
1687           memcpy (entry->name, label, labelLen);
1688           entry->name[labelLen] = 0;
1689           entry->refCount = -1;
1690
1691           hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1692         }
1693       line = line->next;
1694     }
1695
1696
1697   /* Second pass: for each line, note all the referenced labels. */
1698   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1699   line = head;
1700   while (line)
1701     {
1702       for (i = 0; i < HTAB_SIZE; i++)
1703         {
1704           labelHashEntry *thisEntry;
1705
1706           thisEntry = hTabFirstItemWK (labelHash, i);
1707
1708           while (thisEntry)
1709             {
1710               if (strstr (line->line, thisEntry->name))
1711                 {
1712                   thisEntry->refCount++;
1713                 }
1714               thisEntry = hTabNextItemWK (labelHash);
1715             }
1716         }
1717       line = line->next;
1718     }
1719
1720 #if 0
1721   /* Spew the contents of the table. Debugging fun only. */
1722   for (i = 0; i < HTAB_SIZE; i++)
1723     {
1724       labelHashEntry *thisEntry;
1725
1726       thisEntry = hTabFirstItemWK (labelHash, i);
1727
1728       while (thisEntry)
1729         {
1730           fprintf (stderr, "label: %s ref %d\n",
1731                    thisEntry->name, thisEntry->refCount);
1732           thisEntry = hTabNextItemWK (labelHash);
1733         }
1734     }
1735 #endif
1736 }
1737
1738 /* How does this work?
1739    peepHole
1740     For each rule,
1741      For each line,
1742       Try to match
1743       If it matches,
1744        replace and restart.
1745
1746     matchRule
1747      matchLine
1748
1749   Where is stuff allocated?
1750   
1751 */
1752
1753 /*-----------------------------------------------------------------*/
1754 /* peepHole - matches & substitutes rules                          */
1755 /*-----------------------------------------------------------------*/
1756 void 
1757 peepHole (lineNode ** pls)
1758 {
1759   lineNode *spl;
1760   peepRule *pr;
1761   lineNode *mtail = NULL;
1762   bool restart;
1763
1764 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1765   /* The PIC port uses a different peep hole optimizer based on "pCode" */
1766   if (TARGET_IS_PIC || TARGET_IS_PIC16)
1767     return;
1768 #endif
1769
1770   assert(labelHash == NULL);
1771
1772   do
1773     {
1774       restart = FALSE;
1775
1776       /* for all rules */
1777       for (pr = rootRules; pr; pr = pr->next)
1778         {
1779           for (spl = *pls; spl; spl = spl->next)
1780             {
1781               /* if inline assembler then no peep hole */
1782               if (spl->isInline)
1783                 continue;
1784
1785               /* don't waste time starting a match on debug symbol
1786               ** or comment */
1787               if (spl->isDebug || spl->isComment || *(spl->line)==';')
1788                 continue;
1789               
1790               mtail = NULL;
1791
1792               /* Tidy up any data stored in the hTab */
1793               
1794               /* if it matches */
1795               if (matchRule (spl, &mtail, pr, *pls))
1796                 {
1797                   
1798                   /* then replace */
1799                   if (spl == *pls)
1800                     replaceRule (pls, mtail, pr);
1801                   else
1802                     replaceRule (&spl, mtail, pr);
1803                   
1804                   /* if restart rule type then
1805                      start at the top again */
1806                   if (pr->restart)
1807                     {
1808                       restart = TRUE;
1809                     }
1810                 }
1811               
1812               if (pr->vars)
1813                 {
1814                   hTabDeleteAll (pr->vars);
1815                   Safe_free (pr->vars);
1816                   pr->vars = NULL;
1817                 }
1818               
1819               freeTrace (&_G.values);
1820             }
1821         }
1822     } while (restart == TRUE);
1823
1824   if (labelHash)
1825     {
1826       hTabDeleteAll (labelHash);
1827       freeTrace (&_G.labels);
1828     }
1829   labelHash = NULL;
1830 }
1831
1832
1833 /*-----------------------------------------------------------------*/
1834 /* readFileIntoBuffer - reads a file into a string buffer          */
1835 /*-----------------------------------------------------------------*/
1836 static char *
1837 readFileIntoBuffer (char *fname)
1838 {
1839   FILE *f;
1840   char *rs = NULL;
1841   int nch = 0;
1842   int ch;
1843   char lb[MAX_PATTERN_LEN];
1844
1845   if (!(f = fopen (fname, "r")))
1846     {
1847       fprintf (stderr, "cannot open peep rule file\n");
1848       return NULL;
1849     }
1850
1851   while ((ch = fgetc (f)) != EOF)
1852     {
1853       lb[nch++] = ch;
1854
1855       /* if we maxed out our local buffer */
1856       if (nch >= (MAX_PATTERN_LEN - 2))
1857         {
1858           lb[nch] = '\0';
1859           /* copy it into allocated buffer */
1860           if (rs)
1861             {
1862               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1863               strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
1864             }
1865           else
1866             {
1867               rs = Safe_strdup (lb);
1868             }
1869           nch = 0;
1870         }
1871     }
1872
1873   /* if some charaters left over */
1874   if (nch)
1875     {
1876       lb[nch] = '\0';
1877       /* copy it into allocated buffer */
1878       if (rs)
1879         {
1880           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1881           strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1882         }
1883       else
1884         {
1885           rs = Safe_strdup (lb);
1886         }
1887     }
1888   return rs;
1889 }
1890
1891 /*-----------------------------------------------------------------*/
1892 /* initPeepHole - initialises the peep hole optimizer stuff        */
1893 /*-----------------------------------------------------------------*/
1894 void 
1895 initPeepHole ()
1896 {
1897   char *s;
1898
1899   /* read in the default rules */
1900   readRules (port->peep.default_rules);
1901
1902   /* if we have any additional file read it too */
1903   if (options.peep_file)
1904     {
1905       readRules (s = readFileIntoBuffer (options.peep_file));
1906       setToNull ((void *) &s);
1907     }
1908
1909
1910 #if !OPT_DISABLE_PIC
1911   /* Convert the peep rules into pcode.
1912      NOTE: this is only support in the PIC port (at the moment)
1913   */
1914         if (TARGET_IS_PIC)
1915                 peepRules2pCode(rootRules);
1916 #endif
1917
1918 #if !OPT_DISABLE_PIC16
1919   /* Convert the peep rules into pcode.
1920      NOTE: this is only support in the PIC port (at the moment)
1921        and the PIC16 port (VR 030601)
1922   */
1923         if (TARGET_IS_PIC16)
1924                 pic16_peepRules2pCode(rootRules);
1925
1926 #endif
1927
1928 }