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