0a263f41d6d4732e3f4320824e86e6de70bfc54d
[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
52 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
53         lineNode *head, const char *cmdLine)
54
55 #if !OPT_DISABLE_PIC
56 void peepRules2pCode(peepRule *);
57 #endif
58
59 #if !OPT_DISABLE_PIC16
60 void pic16_peepRules2pCode(peepRule *);
61 #endif
62
63 /*-----------------------------------------------------------------*/
64 /* pcDistance - afinds a label back ward or forward                */
65 /*-----------------------------------------------------------------*/
66 int
67 mcs51_instruction_size(const char *inst)
68 {
69         char *op, op1[256], op2[256];
70         int opsize;
71         const char *p;
72
73         while (*inst && isspace(*inst)) inst++;
74
75         #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
76         if (ISINST("lcall")) return 3;
77         if (ISINST("ret")) return 1;
78         if (ISINST("ljmp")) return 3;
79         if (ISINST("sjmp")) return 2;
80         if (ISINST("rlc")) return 1;
81         if (ISINST("rrc")) return 1;
82         if (ISINST("rl")) return 1;
83         if (ISINST("rr")) return 1;
84         if (ISINST("swap")) return 1;
85         if (ISINST("movx")) return 1;
86         if (ISINST("movc")) return 1;
87         if (ISINST("push")) return 2;
88         if (ISINST("pop")) return 2;
89         if (ISINST("jc")) return 2;
90         if (ISINST("jnc")) return 2;
91         if (ISINST("jb")) return 3;
92         if (ISINST("jnb")) return 3;
93         if (ISINST("jbc")) return 3;
94         if (ISINST("jmp")) return 1;    // always jmp @a+dptr
95         if (ISINST("jz")) return 2;
96         if (ISINST("jnz")) return 2;
97         if (ISINST("cjne")) return 3;
98         if (ISINST("mul")) return 1;
99         if (ISINST("div")) return 1;
100         if (ISINST("da")) return 1;
101         if (ISINST("xchd")) return 1;
102         if (ISINST("reti")) return 1;
103         if (ISINST("nop")) return 1;
104         if (ISINST("acall")) return 1;
105         if (ISINST("ajmp")) return 2;
106
107         p = inst;
108         while (*p && isalnum(*p)) p++;
109         for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
110                 if (!isspace(*p)) *op++ = *p, opsize++;
111         }
112         *op = '\0';
113         if (*p == ',') p++;
114         for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
115                 if (!isspace(*p)) *op++ = *p, opsize++;
116         }
117         *op = '\0';
118
119         #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
120         #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
121         #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
122         #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
123
124         if (ISINST("mov")) {
125                 if (IS_C(op1) || IS_C(op2)) return 2;
126                 if (IS_A(op1)) {
127                         if (IS_Rn(op2) || IS_atRi(op2)) return 1;
128                         return 2;
129                 }
130                 if (IS_Rn(op1) || IS_atRi(op1)) {
131                         if (IS_A(op2)) return 1;
132                         return 2;
133                 }
134                 if (strcmp(op1, "dptr") == 0) return 3;
135                 if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
136                 return 3;
137         }
138         if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
139                 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
140                 return 2;
141         }
142         if (ISINST("inc") || ISINST("dec")) {
143                 if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
144                 if (strcmp(op1, "dptr") == 0) return 1;
145                 return 2;
146         }
147         if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
148                 if (IS_C(op1)) return 2;
149                 if (IS_A(op1)) {
150                         if (IS_Rn(op2) || IS_atRi(op2)) return 1;
151                         return 2;
152                 } else {
153                         if (IS_A(op2)) return 2;
154                         return 3;
155                 }
156         }
157         if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
158                 if (IS_A(op1) || IS_C(op1)) return 1;
159                 return 2;
160         }
161         if (ISINST("djnz")) {
162                 if (IS_Rn(op1)) return 2;
163                 return 3;
164         }
165
166         if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
167                 /* ignore ar0 = 0x00 type definitions */
168                 return 0;
169         }
170
171         fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
172         return 3;
173 }
174
175 int 
176 pcDistance (lineNode * cpos, char *lbl, bool back)
177 {
178   lineNode *pl = cpos;
179   char buff[MAX_PATTERN_LEN];
180   int dist = 0;
181
182   SNPRINTF (buff, sizeof(buff), "%s:", lbl);
183   while (pl)
184     {
185
186       if (pl->line &&
187           *pl->line != ';' &&
188           pl->line[strlen (pl->line) - 1] != ':' &&
189           !pl->isDebug) {
190                 if (strcmp(port->target,"mcs51") == 0) {
191                         dist += mcs51_instruction_size(pl->line);
192                 } else {
193                         dist += 3;
194                 }
195         }
196
197       if (strncmp (pl->line, buff, strlen (buff)) == 0)
198         return dist;
199
200       if (back)
201         pl = pl->prev;
202       else
203         pl = pl->next;
204
205     }
206   return 0;
207 }
208
209 /*-----------------------------------------------------------------*/
210 /* flat24bitModeAndPortDS390 -                                     */
211 /*-----------------------------------------------------------------*/
212 FBYNAME (flat24bitModeAndPortDS390)
213 {
214     return ((strcmp(port->target,"ds390") == 0) && 
215             (options.model == MODEL_FLAT24));
216 }
217
218 /*-----------------------------------------------------------------*/
219 /* portIsDS390 - return true if port is DS390                      */
220 /*-----------------------------------------------------------------*/
221 FBYNAME (portIsDS390)
222 {
223     return (strcmp(port->target,"ds390") == 0);
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* flat24bitMode - will check to see if we are in flat24 mode      */
228 /*-----------------------------------------------------------------*/
229 FBYNAME (flat24bitMode)
230 {
231   return (options.model == MODEL_FLAT24);
232 }
233
234 /*-----------------------------------------------------------------*/
235 /* xramMovcOption - check if using movc to read xram               */
236 /*-----------------------------------------------------------------*/
237 FBYNAME (xramMovcOption)
238 {
239   return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
240 }
241
242
243
244
245
246
247 /*-----------------------------------------------------------------*/
248 /* labelInRange - will check to see if label %5 is within range    */
249 /*-----------------------------------------------------------------*/
250 FBYNAME (labelInRange)
251 {
252   /* assumes that %5 pattern variable has the label name */
253   char *lbl = hTabItemWithKey (vars, 5);
254   int dist = 0;
255
256   if (!lbl)
257     return FALSE;
258
259   /* if the previous two instructions are "ljmp"s then don't
260      do it since it can be part of a jump table */
261   if (currPl->prev && currPl->prev->prev &&
262       strstr (currPl->prev->line, "ljmp") &&
263       strstr (currPl->prev->prev->line, "ljmp"))
264     return FALSE;
265
266   /* calculate the label distance : the jump for reladdr can be
267      +/- 127 bytes, here Iam assuming that an average 8051
268      instruction is 2 bytes long, so if the label is more than
269      63 intructions away, the label is considered out of range
270      for a relative jump. we could get more precise this will
271      suffice for now since it catches > 90% cases */
272   dist = (pcDistance (currPl, lbl, TRUE) +
273           pcDistance (currPl, lbl, FALSE));
274
275 /*    changed to 127, now that pcDistance return actual number of bytes */
276   if (!dist || dist > 127)
277     return FALSE;
278
279   return TRUE;
280 }
281
282 /*-----------------------------------------------------------------*/
283 /* labelIsReturnOnly - Check if label %5 is followed by RET        */
284 /*-----------------------------------------------------------------*/
285 FBYNAME (labelIsReturnOnly)
286 {
287   /* assumes that %5 pattern variable has the label name */
288   const char *label, *p;
289   const lineNode *pl;
290   int len;
291
292   label = hTabItemWithKey (vars, 5);
293   if (!label) return FALSE;
294   len = strlen(label);
295
296   for(pl = currPl; pl; pl = pl->next) {
297         if (pl->line && !pl->isDebug &&
298           pl->line[strlen(pl->line)-1] == ':') {
299                 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
300                 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
301                   !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
302                   !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
303                   *(pl->line+5) != '$') {
304                         return FALSE; /* non-local label encountered */
305                 }
306         }
307   }
308   if (!pl) return FALSE; /* did not find the label */
309   pl = pl->next;
310   if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
311   p = pl->line;
312   for (p = pl->line; *p && isspace(*p); p++)
313           ;
314   if (strcmp(p, "ret") == 0) return TRUE;
315   return FALSE;
316 }
317
318
319 /*-----------------------------------------------------------------*/
320 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other      */
321 /* usage of it in the code depends on a value from this section    */
322 /*-----------------------------------------------------------------*/
323 FBYNAME (okToRemoveSLOC)
324 {
325   const lineNode *pl;
326   const char *sloc, *p;
327   int dummy1, dummy2, dummy3;
328
329   /* assumes that %1 as the SLOC name */
330   sloc = hTabItemWithKey (vars, 1);
331   if (sloc == NULL) return FALSE;
332   p = strstr(sloc, "sloc");
333   if (p == NULL) return FALSE;
334   p += 4;
335   if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
336   /*TODO: ultra-paranoid: get funtion name from "head" and check that */
337   /* the sloc name begins with that.  Probably not really necessary */
338
339   /* Look for any occurance of this SLOC before the peephole match */
340   for (pl = currPl->prev; pl; pl = pl->prev) {
341         if (pl->line && !pl->isDebug && !pl->isComment
342           && *pl->line != ';' && strstr(pl->line, sloc))
343                 return FALSE;
344   }
345   /* Look for any occurance of this SLOC after the peephole match */
346   for (pl = endPl->next; pl; pl = pl->next) {
347         if (pl->line && !pl->isDebug && !pl->isComment
348           && *pl->line != ';' && strstr(pl->line, sloc))
349                 return FALSE;
350   }
351   return TRUE; /* safe for a peephole to remove it :) */
352 }
353
354
355 /*-----------------------------------------------------------------*/
356 /* operandsNotSame - check if %1 & %2 are the same                 */
357 /*-----------------------------------------------------------------*/
358 FBYNAME (operandsNotSame)
359 {
360   char *op1 = hTabItemWithKey (vars, 1);
361   char *op2 = hTabItemWithKey (vars, 2);
362
363   if (strcmp (op1, op2) == 0)
364     return FALSE;
365   else
366     return TRUE;
367 }
368
369 /*-----------------------------------------------------------------*/
370 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same    */
371 /*-----------------------------------------------------------------*/
372 FBYNAME (operandsNotSame3)
373 {
374   char *op1 = hTabItemWithKey (vars, 1);
375   char *op2 = hTabItemWithKey (vars, 2);
376   char *op3 = hTabItemWithKey (vars, 3);
377
378   if ( (strcmp (op1, op2) == 0) ||
379        (strcmp (op1, op3) == 0) ||
380        (strcmp (op2, op3) == 0) )
381     return FALSE;
382   else
383     return TRUE;
384 }
385
386 /*-----------------------------------------------------------------*/
387 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
388 /*-----------------------------------------------------------------*/
389 FBYNAME (operandsNotSame4)
390 {
391   char *op1 = hTabItemWithKey (vars, 1);
392   char *op2 = hTabItemWithKey (vars, 2);
393   char *op3 = hTabItemWithKey (vars, 3);
394   char *op4 = hTabItemWithKey (vars, 4);
395
396   if ( (strcmp (op1, op2) == 0) ||
397        (strcmp (op1, op3) == 0) ||
398        (strcmp (op1, op4) == 0) ||
399        (strcmp (op2, op3) == 0) ||
400        (strcmp (op2, op4) == 0) ||
401        (strcmp (op3, op4) == 0) )
402     return FALSE;
403   else
404     return TRUE;
405 }
406
407 /*-----------------------------------------------------------------*/
408 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
409 /*-----------------------------------------------------------------*/
410 FBYNAME (operandsNotSame5)
411 {
412   char *op1 = hTabItemWithKey (vars, 1);
413   char *op2 = hTabItemWithKey (vars, 2);
414   char *op3 = hTabItemWithKey (vars, 3);
415   char *op4 = hTabItemWithKey (vars, 4);
416   char *op5 = hTabItemWithKey (vars, 5);
417
418   if ( (strcmp (op1, op2) == 0) ||
419        (strcmp (op1, op3) == 0) ||
420        (strcmp (op1, op4) == 0) ||
421        (strcmp (op1, op5) == 0) ||
422        (strcmp (op2, op3) == 0) ||
423        (strcmp (op2, op4) == 0) ||
424        (strcmp (op2, op5) == 0) ||
425        (strcmp (op3, op4) == 0) ||
426        (strcmp (op3, op5) == 0) ||
427        (strcmp (op4, op5) == 0) )
428     return FALSE;
429   else
430     return TRUE;
431 }
432
433 /*-----------------------------------------------------------------*/
434 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
435 /*-----------------------------------------------------------------*/
436 FBYNAME (operandsNotSame6)
437 {
438   char *op1 = hTabItemWithKey (vars, 1);
439   char *op2 = hTabItemWithKey (vars, 2);
440   char *op3 = hTabItemWithKey (vars, 3);
441   char *op4 = hTabItemWithKey (vars, 4);
442   char *op5 = hTabItemWithKey (vars, 5);
443   char *op6 = hTabItemWithKey (vars, 6);
444
445   if ( (strcmp (op1, op2) == 0) ||
446        (strcmp (op1, op3) == 0) ||
447        (strcmp (op1, op4) == 0) ||
448        (strcmp (op1, op5) == 0) ||
449        (strcmp (op1, op6) == 0) ||
450        (strcmp (op2, op3) == 0) ||
451        (strcmp (op2, op4) == 0) ||
452        (strcmp (op2, op5) == 0) ||
453        (strcmp (op2, op6) == 0) ||
454        (strcmp (op3, op4) == 0) ||
455        (strcmp (op3, op5) == 0) ||
456        (strcmp (op3, op6) == 0) ||
457        (strcmp (op4, op5) == 0) ||
458        (strcmp (op4, op6) == 0) ||
459        (strcmp (op5, op6) == 0) )
460     return FALSE;
461   else
462     return TRUE;
463 }
464
465
466 /*-----------------------------------------------------------------*/
467 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
468 /*-----------------------------------------------------------------*/
469 FBYNAME (operandsNotSame7)
470 {
471   char *op1 = hTabItemWithKey (vars, 1);
472   char *op2 = hTabItemWithKey (vars, 2);
473   char *op3 = hTabItemWithKey (vars, 3);
474   char *op4 = hTabItemWithKey (vars, 4);
475   char *op5 = hTabItemWithKey (vars, 5);
476   char *op6 = hTabItemWithKey (vars, 6);
477   char *op7 = hTabItemWithKey (vars, 7);
478
479   if ( (strcmp (op1, op2) == 0) ||
480        (strcmp (op1, op3) == 0) ||
481        (strcmp (op1, op4) == 0) ||
482        (strcmp (op1, op5) == 0) ||
483        (strcmp (op1, op6) == 0) ||
484        (strcmp (op1, op7) == 0) ||
485        (strcmp (op2, op3) == 0) ||
486        (strcmp (op2, op4) == 0) ||
487        (strcmp (op2, op5) == 0) ||
488        (strcmp (op2, op6) == 0) ||
489        (strcmp (op2, op7) == 0) ||
490        (strcmp (op3, op4) == 0) ||
491        (strcmp (op3, op5) == 0) ||
492        (strcmp (op3, op6) == 0) ||
493        (strcmp (op3, op7) == 0) ||
494        (strcmp (op4, op5) == 0) ||
495        (strcmp (op4, op6) == 0) ||
496        (strcmp (op4, op7) == 0) ||
497        (strcmp (op5, op6) == 0) ||
498        (strcmp (op5, op7) == 0) ||
499        (strcmp (op6, op7) == 0) )
500     return FALSE;
501   else
502     return TRUE;
503 }
504
505 /*-----------------------------------------------------------------*/
506 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
507 /*-----------------------------------------------------------------*/
508 FBYNAME (operandsNotSame8)
509 {
510   char *op1 = hTabItemWithKey (vars, 1);
511   char *op2 = hTabItemWithKey (vars, 2);
512   char *op3 = hTabItemWithKey (vars, 3);
513   char *op4 = hTabItemWithKey (vars, 4);
514   char *op5 = hTabItemWithKey (vars, 5);
515   char *op6 = hTabItemWithKey (vars, 6);
516   char *op7 = hTabItemWithKey (vars, 7);
517   char *op8 = hTabItemWithKey (vars, 8);
518
519   if ( (strcmp (op1, op2) == 0) ||
520        (strcmp (op1, op3) == 0) ||
521        (strcmp (op1, op4) == 0) ||
522        (strcmp (op1, op5) == 0) ||
523        (strcmp (op1, op6) == 0) ||
524        (strcmp (op1, op7) == 0) ||
525        (strcmp (op1, op8) == 0) ||
526        (strcmp (op2, op3) == 0) ||
527        (strcmp (op2, op4) == 0) ||
528        (strcmp (op2, op5) == 0) ||
529        (strcmp (op2, op6) == 0) ||
530        (strcmp (op2, op7) == 0) ||
531        (strcmp (op2, op8) == 0) ||
532        (strcmp (op3, op4) == 0) ||
533        (strcmp (op3, op5) == 0) ||
534        (strcmp (op3, op6) == 0) ||
535        (strcmp (op3, op7) == 0) ||
536        (strcmp (op3, op8) == 0) ||
537        (strcmp (op4, op5) == 0) ||
538        (strcmp (op4, op6) == 0) ||
539        (strcmp (op4, op7) == 0) ||
540        (strcmp (op4, op8) == 0) ||
541        (strcmp (op5, op6) == 0) ||
542        (strcmp (op5, op7) == 0) ||
543        (strcmp (op5, op8) == 0) ||
544        (strcmp (op6, op7) == 0) ||
545        (strcmp (op6, op8) == 0) ||
546        (strcmp (op7, op8) == 0) )
547     return FALSE;
548   else
549     return TRUE;
550 }
551
552
553 /* labelRefCount:
554
555  * takes two parameters: a variable (bound to a label name)
556  * and an expected reference count.
557  *
558  * Returns TRUE if that label is defined and referenced exactly
559  * the given number of times.
560  */
561 FBYNAME (labelRefCount)
562 {
563   int varNumber, expectedRefCount;
564   bool rc = FALSE;
565
566   /* If we don't have the label hash table yet, build it. */
567   if (!labelHash)
568     {
569       buildLabelRefCountHash (head);
570     }
571
572   if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
573     {
574       char *label = hTabItemWithKey (vars, varNumber);
575
576       if (label)
577         {
578           labelHashEntry *entry;
579
580           entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
581
582           while (entry)
583             {
584               if (!strcmp (label, entry->name))
585                 {
586                   break;
587                 }
588               entry = hTabNextItemWK (labelHash);
589             }
590           if (entry)
591             {
592 #if 0
593               /* debug spew. */
594               fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
595                        label, entry->refCount, expectedRefCount);
596 #endif
597
598               rc = (expectedRefCount == entry->refCount);
599             }
600           else
601             {
602               fprintf (stderr, "*** internal error: no label has entry for"
603                        " %s in labelRefCount peephole.\n",
604                        label);
605             }
606         }
607       else
608         {
609           fprintf (stderr, "*** internal error: var %d not bound"
610                    " in peephole labelRefCount rule.\n",
611                    varNumber);
612         }
613
614     }
615   else
616     {
617       fprintf (stderr,
618                "*** internal error: labelRefCount peephole restriction"
619                " malformed: %s\n", cmdLine);
620     }
621   return rc;
622 }
623
624 /*-----------------------------------------------------------------*/
625 /* callFuncByName - calls a function as defined in the table       */
626 /*-----------------------------------------------------------------*/
627 int 
628 callFuncByName (char *fname,
629                 hTab * vars,
630                 lineNode * currPl,
631                 lineNode * endPl,
632                 lineNode * head)
633 {
634   struct ftab
635   {
636     char *fname;
637     int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
638   }
639   ftab[] =
640   {
641     {
642       "labelInRange", labelInRange
643     }
644     ,
645     {
646       "operandsNotSame", operandsNotSame
647     }
648     ,
649     {
650       "operandsNotSame3", operandsNotSame3
651     }
652     ,
653     {
654       "operandsNotSame4", operandsNotSame4
655     }
656     ,
657     {
658       "operandsNotSame5", operandsNotSame5
659     }
660     ,
661     {
662       "operandsNotSame6", operandsNotSame6
663     }
664     ,
665     {
666       "operandsNotSame7", operandsNotSame7
667     }
668     ,
669     {
670       "operandsNotSame8", operandsNotSame8
671     }
672     ,     
673     {
674       "24bitMode", flat24bitMode
675     }
676     ,
677     {
678       "xramMovcOption", xramMovcOption
679     }
680     ,
681     {
682       "labelRefCount", labelRefCount
683     }
684     ,
685     {
686       "portIsDS390", portIsDS390
687     },
688     {
689       "labelIsReturnOnly", labelIsReturnOnly
690     },
691     {
692       "okToRemoveSLOC", okToRemoveSLOC
693     },
694     {
695       "24bitModeAndPortDS390", flat24bitModeAndPortDS390
696     }
697   };
698   int   i;
699   char  *cmdCopy, *funcName, *funcArgs;
700   int   rc = -1;
701     
702   /* Isolate the function name part (we are passed the full condition 
703    * string including arguments) 
704    */
705   cmdCopy = Safe_strdup(fname);
706   funcName = strtok(cmdCopy, " \t");
707   funcArgs = strtok(NULL, "");
708
709     for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
710     {
711         if (strcmp (ftab[i].fname, funcName) == 0)
712         {
713             rc = (*ftab[i].func) (vars, currPl, endPl, head,
714                                   funcArgs);
715         }
716     }
717     
718     Safe_free(cmdCopy);
719     
720     if (rc == -1)
721     {
722         fprintf (stderr, 
723                  "could not find named function \"%s\" in "
724                  "peephole function table\n",
725                  funcName);
726         // If the function couldn't be found, let's assume it's
727         // a bad rule and refuse it.
728         rc = FALSE;
729     }
730     
731   return rc;
732 }
733
734 /*-----------------------------------------------------------------*/
735 /* printLine - prints a line chain into a given file               */
736 /*-----------------------------------------------------------------*/
737 void 
738 printLine (lineNode * head, FILE * of)
739 {
740   if (!of)
741     of = stdout;
742
743   while (head)
744     {
745       /* don't indent comments & labels */
746       if (head->line &&
747           (*head->line == ';' ||
748            head->line[strlen (head->line) - 1] == ':')) {
749         fprintf (of, "%s\n", head->line);
750       } else {
751         if (head->isInline && *head->line=='#') {
752           // comment out preprocessor directives in inline asm
753           fprintf (of, ";");
754         }
755         fprintf (of, "\t%s\n", head->line);
756       }
757       head = head->next;
758     }
759 }
760
761 /*-----------------------------------------------------------------*/
762 /* newPeepRule - creates a new peeprule and attach it to the root  */
763 /*-----------------------------------------------------------------*/
764 peepRule *
765 newPeepRule (lineNode * match,
766              lineNode * replace,
767              char *cond,
768              int restart)
769 {
770   peepRule *pr;
771
772   pr = Safe_alloc ( sizeof (peepRule));
773   pr->match = match;
774   pr->replace = replace;
775   pr->restart = restart;
776
777   if (cond && *cond)
778     {
779       pr->cond = Safe_strdup (cond);
780     }
781   else
782     pr->cond = NULL;
783
784   pr->vars = newHashTable (100);
785
786   /* if root is empty */
787   if (!rootRules)
788     rootRules = currRule = pr;
789   else
790     currRule = currRule->next = pr;
791
792   return pr;
793 }
794
795 /*-----------------------------------------------------------------*/
796 /* newLineNode - creates a new peep line                           */
797 /*-----------------------------------------------------------------*/
798 lineNode *
799 newLineNode (char *line)
800 {
801   lineNode *pl;
802
803   pl = Safe_alloc ( sizeof (lineNode));
804   pl->line = Safe_strdup (line);
805   return pl;
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* connectLine - connects two lines                                */
810 /*-----------------------------------------------------------------*/
811 lineNode *
812 connectLine (lineNode * pl1, lineNode * pl2)
813 {
814   if (!pl1 || !pl2)
815     {
816       fprintf (stderr, "trying to connect null line\n");
817       return NULL;
818     }
819
820   pl2->prev = pl1;
821   pl1->next = pl2;
822
823   return pl2;
824 }
825
826 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
827                          if (!*x) { fprintf(stderr,y); return ; } }
828
829 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ;   \
830                            if (!*x) { fprintf(stderr,z); return ; } }
831 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ;   \
832                            if (!*x) { fprintf(stderr,z); return ; } }
833
834 /*-----------------------------------------------------------------*/
835 /* getPeepLine - parses the peep lines                             */
836 /*-----------------------------------------------------------------*/
837 static void 
838 getPeepLine (lineNode ** head, char **bpp)
839 {
840   char lines[MAX_PATTERN_LEN];
841   char *lp;
842
843   lineNode *currL = NULL;
844   char *bp = *bpp;
845   while (1)
846     {
847
848       if (!*bp)
849         {
850           fprintf (stderr, "unexpected end of match pattern\n");
851           return;
852         }
853
854       if (*bp == '\n')
855         {
856           bp++;
857           while (isspace (*bp) ||
858                  *bp == '\n')
859             bp++;
860         }
861
862       if (*bp == '}')
863         {
864           bp++;
865           break;
866         }
867
868       /* read till end of line */
869       lp = lines;
870       while ((*bp != '\n' && *bp != '}') && *bp)
871         *lp++ = *bp++;
872
873       *lp = '\0';
874       if (!currL)
875         *head = currL = newLineNode (lines);
876       else
877         currL = connectLine (currL, newLineNode (lines));
878     }
879
880   *bpp = bp;
881 }
882
883 /*-----------------------------------------------------------------*/
884 /* readRules - reads the rules from a string buffer                */
885 /*-----------------------------------------------------------------*/
886 static void 
887 readRules (char *bp)
888 {
889   char restart = 0;
890   char lines[MAX_PATTERN_LEN];
891   char *lp;
892   lineNode *match;
893   lineNode *replace;
894   lineNode *currL = NULL;
895
896   if (!bp)
897     return;
898 top:
899   restart = 0;
900   /* look for the token "replace" that is the
901      start of a rule */
902   while (*bp && strncmp (bp, "replace", 7))
903     bp++;
904
905   /* if not found */
906   if (!*bp)
907     return;
908
909   /* then look for either "restart" or '{' */
910   while (strncmp (bp, "restart", 7) &&
911          *bp != '{' && bp)
912     bp++;
913
914   /* not found */
915   if (!*bp)
916     {
917       fprintf (stderr, "expected 'restart' or '{'\n");
918       return;
919     }
920
921   /* if brace */
922   if (*bp == '{')
923     bp++;
924   else
925     {                           /* must be restart */
926       restart++;
927       bp += strlen ("restart");
928       /* look for '{' */
929       EXPECT_CHR (bp, '{', "expected '{'\n");
930       bp++;
931     }
932
933   /* skip thru all the blank space */
934   SKIP_SPACE (bp, "unexpected end of rule\n");
935
936   match = replace = currL = NULL;
937   /* we are the start of a rule */
938   getPeepLine (&match, &bp);
939
940   /* now look for by */
941   EXPECT_STR (bp, "by", "expected 'by'\n");
942
943   /* then look for a '{' */
944   EXPECT_CHR (bp, '{', "expected '{'\n");
945   bp++;
946
947   SKIP_SPACE (bp, "unexpected end of rule\n");
948   getPeepLine (&replace, &bp);
949
950   /* look for a 'if' */
951   while ((isspace (*bp) || *bp == '\n') && *bp)
952     bp++;
953
954   if (strncmp (bp, "if", 2) == 0)
955     {
956       bp += 2;
957       while ((isspace (*bp) || *bp == '\n') && *bp)
958         bp++;
959       if (!*bp)
960         {
961           fprintf (stderr, "expected condition name\n");
962           return;
963         }
964
965       /* look for the condition */
966       lp = lines;
967       while (*bp && (*bp != '\n'))
968         {
969           *lp++ = *bp++;
970         }
971       *lp = '\0';
972
973       newPeepRule (match, replace, lines, restart);
974     }
975   else
976     newPeepRule (match, replace, NULL, restart);
977   goto top;
978
979 }
980
981 /*-----------------------------------------------------------------*/
982 /* keyForVar - returns the numeric key for a var                   */
983 /*-----------------------------------------------------------------*/
984 static int 
985 keyForVar (char *d)
986 {
987   int i = 0;
988
989   while (isdigit (*d))
990     {
991       i *= 10;
992       i += (*d++ - '0');
993     }
994
995   return i;
996 }
997
998 /*-----------------------------------------------------------------*/
999 /* bindVar - binds a value to a variable in the given hashtable    */
1000 /*-----------------------------------------------------------------*/
1001 static void 
1002 bindVar (int key, char **s, hTab ** vtab)
1003 {
1004   char vval[MAX_PATTERN_LEN];
1005   char *vvx;
1006   char *vv = vval;
1007
1008   /* first get the value of the variable */
1009   vvx = *s;
1010   /* the value is ended by a ',' or space or newline or null or ) */
1011   while (*vvx &&
1012          *vvx != ',' &&
1013          !isspace (*vvx) &&
1014          *vvx != '\n' &&
1015          *vvx != ':' &&
1016          *vvx != ')')
1017     {
1018       char ubb = 0;
1019       /* if we find a '(' then we need to balance it */
1020       if (*vvx == '(')
1021         {
1022           ubb++;
1023           while (ubb)
1024             {
1025               *vv++ = *vvx++;
1026               if (*vvx == '(')
1027                 ubb++;
1028               if (*vvx == ')')
1029                 ubb--;
1030             }
1031           // include the trailing ')'
1032           *vv++ = *vvx++;
1033         }
1034       else
1035         *vv++ = *vvx++;
1036     }
1037   *s = vvx;
1038   *vv = '\0';
1039   /* got value */
1040   vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1041
1042   hTabAddItem (vtab, key, vvx);
1043 }
1044
1045 /*-----------------------------------------------------------------*/
1046 /* matchLine - matches one line                                    */
1047 /*-----------------------------------------------------------------*/
1048 static bool 
1049 matchLine (char *s, char *d, hTab ** vars)
1050 {
1051
1052   if (!s || !(*s))
1053     return FALSE;
1054
1055   while (*s && *d)
1056     {
1057
1058       /* skip white space in both */
1059       while (isspace (*s))
1060         s++;
1061       while (isspace (*d))
1062         d++;
1063
1064       /* if the destination is a var */
1065       if (*d == '%' && isdigit (*(d + 1)))
1066         {
1067           char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1068           /* if the variable is already bound
1069              then it MUST match with dest */
1070           if (v)
1071             {
1072               while (*v)
1073                 if (*v++ != *s++)
1074                   return FALSE;
1075             }
1076           else
1077             /* variable not bound we need to
1078                bind it */
1079             bindVar (keyForVar (d + 1), &s, vars);
1080
1081           /* in either case go past the variable */
1082           d++;
1083           while (isdigit (*d))
1084             d++;
1085         }
1086
1087       /* they should be an exact match other wise */
1088       if (*s && *d)
1089         {
1090           while (isspace (*s))
1091             s++;
1092           while (isspace (*d))
1093             d++;
1094           if (*s++ != *d++)
1095             return FALSE;
1096         }
1097
1098     }
1099
1100   /* get rid of the trailing spaces
1101      in both source & destination */
1102   if (*s)
1103     while (isspace (*s))
1104       s++;
1105
1106   if (*d)
1107     while (isspace (*d))
1108       d++;
1109
1110   /* after all this if only one of them
1111      has something left over then no match */
1112   if (*s || *d)
1113     return FALSE;
1114
1115   return TRUE;
1116 }
1117
1118 /*-----------------------------------------------------------------*/
1119 /* matchRule - matches a all the rule lines                        */
1120 /*-----------------------------------------------------------------*/
1121 static bool 
1122 matchRule (lineNode * pl,
1123            lineNode ** mtail,
1124            peepRule * pr,
1125            lineNode * head)
1126 {
1127   lineNode *spl;                /* source pl */
1128   lineNode *rpl;                /* rule peep line */
1129
1130 /*     setToNull((void **) &pr->vars);    */
1131 /*     pr->vars = newHashTable(100); */
1132
1133   /* for all the lines defined in the rule */
1134   rpl = pr->match;
1135   spl = pl;
1136   while (spl && rpl)
1137     {
1138
1139       /* if the source line starts with a ';' then
1140          comment line don't process or the source line
1141          contains == . debugger information skip it */
1142       if (spl->line &&
1143           (*spl->line == ';' || spl->isDebug))
1144         {
1145           spl = spl->next;
1146           continue;
1147         }
1148
1149       if (!matchLine (spl->line, rpl->line, &pr->vars))
1150         return FALSE;
1151
1152       rpl = rpl->next;
1153       if (rpl)
1154         spl = spl->next;
1155     }
1156
1157   /* if rules ended */
1158   if (!rpl)
1159     {
1160       /* if this rule has additional conditions */
1161       if (pr->cond)
1162         {
1163           if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1164             {
1165               *mtail = spl;
1166               return TRUE;
1167             }
1168           else
1169             return FALSE;
1170         }
1171       else
1172         {
1173           *mtail = spl;
1174           return TRUE;
1175         }
1176     }
1177   else
1178     return FALSE;
1179 }
1180
1181 /*-----------------------------------------------------------------*/
1182 /* replaceRule - does replacement of a matching pattern            */
1183 /*-----------------------------------------------------------------*/
1184 static void 
1185 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1186 {
1187   lineNode *cl = NULL;
1188   lineNode *pl = NULL, *lhead = NULL;
1189   /* a long function name and long variable name can evaluate to
1190      4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1191   char lb[MAX_PATTERN_LEN*4];
1192   char *lbp;
1193   lineNode *comment = NULL;
1194
1195   /* collect all the comment lines in the source */
1196   for (cl = *shead; cl != stail; cl = cl->next)
1197     {
1198       if (cl->line && (*cl->line == ';' || cl->isDebug))
1199         {
1200           pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1201                 (comment = newLineNode (cl->line)));
1202           pl->isDebug = cl->isDebug;
1203         }
1204     }
1205   cl = NULL;
1206
1207   /* for all the lines in the replacement pattern do */
1208   for (pl = pr->replace; pl; pl = pl->next)
1209     {
1210       char *v;
1211       char *l;
1212       lbp = lb;
1213
1214       l = pl->line;
1215
1216       while (*l)
1217         {
1218           /* if the line contains a variable */
1219           if (*l == '%' && isdigit (*(l + 1)))
1220             {
1221               v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1222               if (!v)
1223                 {
1224                   fprintf (stderr, "used unbound variable in replacement\n");
1225                   l++;
1226                   continue;
1227                 }
1228               while (*v) {
1229                 *lbp++ = *v++;
1230               }
1231               l++;
1232               while (isdigit (*l)) {
1233                 l++;
1234               }
1235               continue;
1236             }
1237           *lbp++ = *l++;
1238         }
1239
1240       *lbp = '\0';
1241       if (cl)
1242         cl = connectLine (cl, newLineNode (lb));
1243       else
1244         lhead = cl = newLineNode (lb);
1245     }
1246
1247   /* add the comments if any to the head of list */
1248   if (comment)
1249     {
1250       lineNode *lc = comment;
1251       while (lc->next)
1252         lc = lc->next;
1253       lc->next = lhead;
1254       if (lhead)
1255         lhead->prev = lc;
1256       lhead = comment;
1257     }
1258
1259   /* now we need to connect / replace the original chain */
1260   /* if there is a prev then change it */
1261   if ((*shead)->prev)
1262     {
1263       (*shead)->prev->next = lhead;
1264       lhead->prev = (*shead)->prev;
1265     }
1266   *shead = lhead;
1267   /* now for the tail */
1268   if (stail && stail->next)
1269     {
1270       stail->next->prev = cl;
1271       if (cl)
1272         cl->next = stail->next;
1273     }
1274 }
1275
1276 /* Returns TRUE if this line is a label definition.
1277
1278  * If so, start will point to the start of the label name,
1279  * and len will be it's length.
1280  */
1281 bool 
1282 isLabelDefinition (const char *line, const char **start, int *len)
1283 {
1284   const char *cp = line;
1285
1286   /* This line is a label if if consists of:
1287    * [optional whitespace] followed by identifier chars
1288    * (alnum | $ | _ ) followed by a colon.
1289    */
1290
1291   while (*cp && isspace (*cp))
1292     {
1293       cp++;
1294     }
1295
1296   if (!*cp)
1297     {
1298       return FALSE;
1299     }
1300
1301   *start = cp;
1302
1303   while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1304     {
1305       cp++;
1306     }
1307
1308   if ((cp == *start) || (*cp != ':'))
1309     {
1310       return FALSE;
1311     }
1312
1313   *len = (cp - (*start));
1314   return TRUE;
1315 }
1316
1317 /* Quick & dirty string hash function. */
1318 static int 
1319 hashSymbolName (const char *name)
1320 {
1321   int hash = 0;
1322
1323   while (*name)
1324     {
1325       hash = (hash << 6) ^ *name;
1326       name++;
1327     }
1328
1329   if (hash < 0)
1330     {
1331       hash = -hash;
1332     }
1333
1334   return hash % HTAB_SIZE;
1335 }
1336
1337 /* Build a hash of all labels in the passed set of lines
1338  * and how many times they are referenced.
1339  */
1340 static void 
1341 buildLabelRefCountHash (lineNode * head)
1342 {
1343   lineNode *line;
1344   const char *label;
1345   int labelLen;
1346   int i;
1347
1348   assert (labelHash == NULL);
1349   labelHash = newHashTable (HTAB_SIZE);
1350
1351   /* First pass: locate all the labels. */
1352   line = head;
1353
1354   while (line)
1355     {
1356       if (isLabelDefinition (line->line, &label, &labelLen)
1357           && labelLen <= SDCC_NAME_MAX)
1358         {
1359           labelHashEntry *entry;
1360
1361           entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1362
1363           memcpy (entry->name, label, labelLen);
1364           entry->name[labelLen] = 0;
1365           entry->refCount = -1;
1366
1367           hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1368         }
1369       line = line->next;
1370     }
1371
1372
1373   /* Second pass: for each line, note all the referenced labels. */
1374   /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1375   line = head;
1376   while (line)
1377     {
1378       for (i = 0; i < HTAB_SIZE; i++)
1379         {
1380           labelHashEntry *thisEntry;
1381
1382           thisEntry = hTabFirstItemWK (labelHash, i);
1383
1384           while (thisEntry)
1385             {
1386               if (strstr (line->line, thisEntry->name))
1387                 {
1388                   thisEntry->refCount++;
1389                 }
1390               thisEntry = hTabNextItemWK (labelHash);
1391             }
1392         }
1393       line = line->next;
1394     }
1395
1396 #if 0
1397   /* Spew the contents of the table. Debugging fun only. */
1398   for (i = 0; i < HTAB_SIZE; i++)
1399     {
1400       labelHashEntry *thisEntry;
1401
1402       thisEntry = hTabFirstItemWK (labelHash, i);
1403
1404       while (thisEntry)
1405         {
1406           fprintf (stderr, "label: %s ref %d\n",
1407                    thisEntry->name, thisEntry->refCount);
1408           thisEntry = hTabNextItemWK (labelHash);
1409         }
1410     }
1411 #endif
1412 }
1413
1414 /* How does this work?
1415    peepHole
1416     For each rule,
1417      For each line,
1418       Try to match
1419       If it matches,
1420        replace and restart.
1421
1422     matchRule
1423      matchLine
1424
1425   Where is stuff allocated?
1426   
1427 */
1428
1429 /*-----------------------------------------------------------------*/
1430 /* peepHole - matches & substitutes rules                          */
1431 /*-----------------------------------------------------------------*/
1432 void 
1433 peepHole (lineNode ** pls)
1434 {
1435   lineNode *spl;
1436   peepRule *pr;
1437   lineNode *mtail = NULL;
1438   bool restart;
1439
1440 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1441   /* The PIC port uses a different peep hole optimizer based on "pCode" */
1442   if (TARGET_IS_PIC || TARGET_IS_PIC16)
1443     return;
1444 #endif
1445
1446   assert(labelHash == NULL);
1447
1448   do
1449     {
1450       restart = FALSE;
1451
1452       /* for all rules */
1453       for (pr = rootRules; pr; pr = pr->next)
1454         {
1455           for (spl = *pls; spl; spl = spl->next)
1456             {
1457               /* if inline assembler then no peep hole */
1458               if (spl->isInline)
1459                 continue;
1460               
1461               mtail = NULL;
1462
1463               /* Tidy up any data stored in the hTab */
1464               
1465               /* if it matches */
1466               if (matchRule (spl, &mtail, pr, *pls))
1467                 {
1468                   
1469                   /* then replace */
1470                   if (spl == *pls)
1471                     replaceRule (pls, mtail, pr);
1472                   else
1473                     replaceRule (&spl, mtail, pr);
1474                   
1475                   /* if restart rule type then
1476                      start at the top again */
1477                   if (pr->restart)
1478                     {
1479                       restart = TRUE;
1480                     }
1481                 }
1482               
1483               if (pr->vars)
1484                 {
1485                   hTabDeleteAll (pr->vars);
1486                   Safe_free (pr->vars);
1487                   pr->vars = NULL;
1488                 }
1489               
1490               freeTrace (&_G.values);
1491             }
1492         }
1493     } while (restart == TRUE);
1494
1495   if (labelHash)
1496     {
1497       hTabDeleteAll (labelHash);
1498       freeTrace (&_G.labels);
1499     }
1500   labelHash = NULL;
1501 }
1502
1503
1504 /*-----------------------------------------------------------------*/
1505 /* readFileIntoBuffer - reads a file into a string buffer          */
1506 /*-----------------------------------------------------------------*/
1507 static char *
1508 readFileIntoBuffer (char *fname)
1509 {
1510   FILE *f;
1511   char *rs = NULL;
1512   int nch = 0;
1513   int ch;
1514   char lb[MAX_PATTERN_LEN];
1515
1516   if (!(f = fopen (fname, "r")))
1517     {
1518       fprintf (stderr, "cannot open peep rule file\n");
1519       return NULL;
1520     }
1521
1522   while ((ch = fgetc (f)) != EOF)
1523     {
1524       lb[nch++] = ch;
1525
1526       /* if we maxed out our local buffer */
1527       if (nch >= (MAX_PATTERN_LEN - 2))
1528         {
1529           lb[nch] = '\0';
1530           /* copy it into allocated buffer */
1531           if (rs)
1532             {
1533               rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1534               strncatz (rs, lb,  strlen (rs) + strlen (lb) + 1);
1535             }
1536           else
1537             {
1538               rs = Safe_strdup (lb);
1539             }
1540           nch = 0;
1541         }
1542     }
1543
1544   /* if some charaters left over */
1545   if (nch)
1546     {
1547       lb[nch] = '\0';
1548       /* copy it into allocated buffer */
1549       if (rs)
1550         {
1551           rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1552           strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1553         }
1554       else
1555         {
1556           rs = Safe_strdup (lb);
1557         }
1558     }
1559   return rs;
1560 }
1561
1562 /*-----------------------------------------------------------------*/
1563 /* initPeepHole - initialises the peep hole optimizer stuff        */
1564 /*-----------------------------------------------------------------*/
1565 void 
1566 initPeepHole ()
1567 {
1568   char *s;
1569
1570   /* read in the default rules */
1571   readRules (port->peep.default_rules);
1572
1573   /* if we have any additional file read it too */
1574   if (options.peep_file)
1575     {
1576       readRules (s = readFileIntoBuffer (options.peep_file));
1577       setToNull ((void **) &s);
1578     }
1579
1580
1581 #if !OPT_DISABLE_PIC
1582   /* Convert the peep rules into pcode.
1583      NOTE: this is only support in the PIC port (at the moment)
1584   */
1585         if (TARGET_IS_PIC)
1586                 peepRules2pCode(rootRules);
1587 #endif
1588
1589 #if !OPT_DISABLE_PIC16
1590   /* Convert the peep rules into pcode.
1591      NOTE: this is only support in the PIC port (at the moment)
1592        and the PIC16 port (VR 030601)
1593   */
1594         if (TARGET_IS_PIC16)
1595                 pic16_peepRules2pCode(rootRules);
1596
1597 #endif
1598
1599 }