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