1 /*-------------------------------------------------------------------------
2 SDCCpeeph.c - The peep hole optimizer: for interpreting the
5 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
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
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.
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.
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 -------------------------------------------------------------------------*/
28 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
29 #define ISCHARSPACE(c) isspace((unsigned char)c)
30 #define ISCHARALNUM(c) isalnum((unsigned char)c)
32 static peepRule *rootRules = NULL;
33 static peepRule *currRule = NULL;
38 char name[SDCC_NAME_MAX + 1];
43 static hTab *labelHash = NULL;
51 static int hashSymbolName (const char *name);
52 static void buildLabelRefCountHash (lineNode * head);
54 static bool matchLine (char *, char *, hTab **);
55 bool isLabelDefinition (const char *line, const char **start, int *len);
57 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
58 lineNode *head, char *cmdLine)
61 void peepRules2pCode(peepRule *);
64 #if !OPT_DISABLE_PIC16
65 void pic16_peepRules2pCode(peepRule *);
68 /*-----------------------------------------------------------------*/
69 /* pcDistance - afinds a label back ward or forward */
70 /*-----------------------------------------------------------------*/
73 pcDistance (lineNode * cpos, char *lbl, bool back)
76 char buff[MAX_PATTERN_LEN];
79 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
85 pl->line[strlen (pl->line) - 1] != ':' &&
87 if (port->peep.getSize) {
88 dist += port->peep.getSize(pl);
94 if (strncmp (pl->line, buff, strlen (buff)) == 0)
106 /*-----------------------------------------------------------------*/
107 /* flat24bitModeAndPortDS390 - */
108 /*-----------------------------------------------------------------*/
109 FBYNAME (flat24bitModeAndPortDS390)
111 return (((strcmp(port->target,"ds390") == 0) ||
112 (strcmp(port->target,"ds400") == 0)) &&
113 (options.model == MODEL_FLAT24));
116 /*-----------------------------------------------------------------*/
117 /* portIsDS390 - return true if port is DS390 */
118 /*-----------------------------------------------------------------*/
119 FBYNAME (portIsDS390)
121 return ((strcmp(port->target,"ds390") == 0) ||
122 (strcmp(port->target,"ds400") == 0));
125 /*-----------------------------------------------------------------*/
126 /* flat24bitMode - will check to see if we are in flat24 mode */
127 /*-----------------------------------------------------------------*/
128 FBYNAME (flat24bitMode)
130 return (options.model == MODEL_FLAT24);
133 /*-----------------------------------------------------------------*/
134 /* xramMovcOption - check if using movc to read xram */
135 /*-----------------------------------------------------------------*/
136 FBYNAME (xramMovcOption)
138 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
146 /*-----------------------------------------------------------------*/
147 /* labelInRange - will check to see if label %5 is within range */
148 /*-----------------------------------------------------------------*/
149 FBYNAME (labelInRange)
151 /* assumes that %5 pattern variable has the label name */
152 char *lbl = hTabItemWithKey (vars, 5);
158 /* Don't optimize jumps in a jump table; a more generic test */
159 if (currPl->ic && currPl->ic->op == JUMPTABLE)
162 /* if the previous two instructions are "ljmp"s then don't
163 do it since it can be part of a jump table */
164 if (currPl->prev && currPl->prev->prev &&
165 strstr (currPl->prev->line, "ljmp") &&
166 strstr (currPl->prev->prev->line, "ljmp"))
169 /* calculate the label distance : the jump for reladdr can be
170 +/- 127 bytes, here Iam assuming that an average 8051
171 instruction is 2 bytes long, so if the label is more than
172 63 intructions away, the label is considered out of range
173 for a relative jump. we could get more precise this will
174 suffice for now since it catches > 90% cases */
175 dist = (pcDistance (currPl, lbl, TRUE) +
176 pcDistance (currPl, lbl, FALSE));
178 /* changed to 127, now that pcDistance return actual number of bytes */
179 if (!dist || dist > 127)
186 /*-----------------------------------------------------------------*/
187 /* labelJTInRange - will check to see if label %5 and up are */
189 /* Specifically meant to optimize long (3-byte) jumps to short */
190 /* (2-byte) jumps in jumptables */
191 /*-----------------------------------------------------------------*/
192 FBYNAME (labelJTInRange)
197 if (!getenv("SDCC_SJMP_JUMPTABLE"))
200 /* Only optimize within a jump table */
201 if (currPl->ic && currPl->ic->op != JUMPTABLE)
204 count = elementsInSet( IC_JTLABELS (currPl->ic) );
206 /* check all labels (this is needed if the case statements are unsorted) */
207 for (i=0; i<count; i++)
209 /* assumes that the %5 pattern variable has the first ljmp label */
210 lbl = hTabItemWithKey (vars, 5+i);
214 dist = pcDistance (currPl, lbl, FALSE);
216 /* three terms used to calculate allowable distance */
217 // printf("\nlabel %s %i dist %i cdist 0x%02x 0x%02x\n", lbl, i, dist, dist -(count-i-1)-(7+3*i), 127+(count-i-1)+(7+3*i) - dist);
219 dist > 127+ /* range of sjmp */
220 (7+3*i)+ /* offset between this jump and currPl,
221 should use pcDistance instead? */
222 (count-i-1) /* if peephole applies distance is shortened */
230 /*-----------------------------------------------------------------*/
231 /* labelIsReturnOnly - Check if label %5 is followed by RET */
232 /*-----------------------------------------------------------------*/
233 FBYNAME (labelIsReturnOnly)
235 /* assumes that %5 pattern variable has the label name */
236 const char *label, *p;
241 label = hTabItemWithKey (vars, 5);
242 if (!label) return FALSE;
245 for(pl = currPl; pl; pl = pl->next) {
246 if (pl->line && !pl->isDebug && !pl->isComment &&
247 pl->line[strlen(pl->line)-1] == ':') {
248 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
249 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
250 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
251 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
252 *(pl->line+5) != '$') {
253 return FALSE; /* non-local label encountered */
257 if (!pl) return FALSE; /* did not find the label */
259 while (pl && (pl->isDebug || pl->isComment))
261 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
263 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
269 if (strcmp(p, retInst) == 0) return TRUE;
274 /*-----------------------------------------------------------------*/
275 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
276 /* usage of it in the code depends on a value from this section */
277 /*-----------------------------------------------------------------*/
278 FBYNAME (okToRemoveSLOC)
281 const char *sloc, *p;
282 int dummy1, dummy2, dummy3;
284 /* assumes that %1 as the SLOC name */
285 sloc = hTabItemWithKey (vars, 1);
286 if (sloc == NULL) return FALSE;
287 p = strstr(sloc, "sloc");
288 if (p == NULL) return FALSE;
290 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
291 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
292 /* the sloc name begins with that. Probably not really necessary */
294 /* Look for any occurance of this SLOC before the peephole match */
295 for (pl = currPl->prev; pl; pl = pl->prev) {
296 if (pl->line && !pl->isDebug && !pl->isComment
297 && *pl->line != ';' && strstr(pl->line, sloc))
300 /* Look for any occurance of this SLOC after the peephole match */
301 for (pl = endPl->next; pl; pl = pl->next) {
302 if (pl->line && !pl->isDebug && !pl->isComment
303 && *pl->line != ';' && strstr(pl->line, sloc))
306 return TRUE; /* safe for a peephole to remove it :) */
310 /*-----------------------------------------------------------------*/
311 /* operandsNotSame - check if %1 & %2 are the same */
312 /*-----------------------------------------------------------------*/
313 FBYNAME (operandsNotSame)
315 char *op1 = hTabItemWithKey (vars, 1);
316 char *op2 = hTabItemWithKey (vars, 2);
318 if (strcmp (op1, op2) == 0)
324 /*-----------------------------------------------------------------*/
325 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
326 /*-----------------------------------------------------------------*/
327 FBYNAME (operandsNotSame3)
329 char *op1 = hTabItemWithKey (vars, 1);
330 char *op2 = hTabItemWithKey (vars, 2);
331 char *op3 = hTabItemWithKey (vars, 3);
333 if ( (strcmp (op1, op2) == 0) ||
334 (strcmp (op1, op3) == 0) ||
335 (strcmp (op2, op3) == 0) )
341 /*-----------------------------------------------------------------*/
342 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
343 /*-----------------------------------------------------------------*/
344 FBYNAME (operandsNotSame4)
346 char *op1 = hTabItemWithKey (vars, 1);
347 char *op2 = hTabItemWithKey (vars, 2);
348 char *op3 = hTabItemWithKey (vars, 3);
349 char *op4 = hTabItemWithKey (vars, 4);
351 if ( (strcmp (op1, op2) == 0) ||
352 (strcmp (op1, op3) == 0) ||
353 (strcmp (op1, op4) == 0) ||
354 (strcmp (op2, op3) == 0) ||
355 (strcmp (op2, op4) == 0) ||
356 (strcmp (op3, op4) == 0) )
362 /*-----------------------------------------------------------------*/
363 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
364 /*-----------------------------------------------------------------*/
365 FBYNAME (operandsNotSame5)
367 char *op1 = hTabItemWithKey (vars, 1);
368 char *op2 = hTabItemWithKey (vars, 2);
369 char *op3 = hTabItemWithKey (vars, 3);
370 char *op4 = hTabItemWithKey (vars, 4);
371 char *op5 = hTabItemWithKey (vars, 5);
373 if ( (strcmp (op1, op2) == 0) ||
374 (strcmp (op1, op3) == 0) ||
375 (strcmp (op1, op4) == 0) ||
376 (strcmp (op1, op5) == 0) ||
377 (strcmp (op2, op3) == 0) ||
378 (strcmp (op2, op4) == 0) ||
379 (strcmp (op2, op5) == 0) ||
380 (strcmp (op3, op4) == 0) ||
381 (strcmp (op3, op5) == 0) ||
382 (strcmp (op4, op5) == 0) )
388 /*-----------------------------------------------------------------*/
389 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
390 /*-----------------------------------------------------------------*/
391 FBYNAME (operandsNotSame6)
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 char *op5 = hTabItemWithKey (vars, 5);
398 char *op6 = hTabItemWithKey (vars, 6);
400 if ( (strcmp (op1, op2) == 0) ||
401 (strcmp (op1, op3) == 0) ||
402 (strcmp (op1, op4) == 0) ||
403 (strcmp (op1, op5) == 0) ||
404 (strcmp (op1, op6) == 0) ||
405 (strcmp (op2, op3) == 0) ||
406 (strcmp (op2, op4) == 0) ||
407 (strcmp (op2, op5) == 0) ||
408 (strcmp (op2, op6) == 0) ||
409 (strcmp (op3, op4) == 0) ||
410 (strcmp (op3, op5) == 0) ||
411 (strcmp (op3, op6) == 0) ||
412 (strcmp (op4, op5) == 0) ||
413 (strcmp (op4, op6) == 0) ||
414 (strcmp (op5, op6) == 0) )
421 /*-----------------------------------------------------------------*/
422 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
423 /*-----------------------------------------------------------------*/
424 FBYNAME (operandsNotSame7)
426 char *op1 = hTabItemWithKey (vars, 1);
427 char *op2 = hTabItemWithKey (vars, 2);
428 char *op3 = hTabItemWithKey (vars, 3);
429 char *op4 = hTabItemWithKey (vars, 4);
430 char *op5 = hTabItemWithKey (vars, 5);
431 char *op6 = hTabItemWithKey (vars, 6);
432 char *op7 = hTabItemWithKey (vars, 7);
434 if ( (strcmp (op1, op2) == 0) ||
435 (strcmp (op1, op3) == 0) ||
436 (strcmp (op1, op4) == 0) ||
437 (strcmp (op1, op5) == 0) ||
438 (strcmp (op1, op6) == 0) ||
439 (strcmp (op1, op7) == 0) ||
440 (strcmp (op2, op3) == 0) ||
441 (strcmp (op2, op4) == 0) ||
442 (strcmp (op2, op5) == 0) ||
443 (strcmp (op2, op6) == 0) ||
444 (strcmp (op2, op7) == 0) ||
445 (strcmp (op3, op4) == 0) ||
446 (strcmp (op3, op5) == 0) ||
447 (strcmp (op3, op6) == 0) ||
448 (strcmp (op3, op7) == 0) ||
449 (strcmp (op4, op5) == 0) ||
450 (strcmp (op4, op6) == 0) ||
451 (strcmp (op4, op7) == 0) ||
452 (strcmp (op5, op6) == 0) ||
453 (strcmp (op5, op7) == 0) ||
454 (strcmp (op6, op7) == 0) )
460 /*-----------------------------------------------------------------*/
461 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
462 /*-----------------------------------------------------------------*/
463 FBYNAME (operandsNotSame8)
465 char *op1 = hTabItemWithKey (vars, 1);
466 char *op2 = hTabItemWithKey (vars, 2);
467 char *op3 = hTabItemWithKey (vars, 3);
468 char *op4 = hTabItemWithKey (vars, 4);
469 char *op5 = hTabItemWithKey (vars, 5);
470 char *op6 = hTabItemWithKey (vars, 6);
471 char *op7 = hTabItemWithKey (vars, 7);
472 char *op8 = hTabItemWithKey (vars, 8);
474 if ( (strcmp (op1, op2) == 0) ||
475 (strcmp (op1, op3) == 0) ||
476 (strcmp (op1, op4) == 0) ||
477 (strcmp (op1, op5) == 0) ||
478 (strcmp (op1, op6) == 0) ||
479 (strcmp (op1, op7) == 0) ||
480 (strcmp (op1, op8) == 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 (op2, op8) == 0) ||
487 (strcmp (op3, op4) == 0) ||
488 (strcmp (op3, op5) == 0) ||
489 (strcmp (op3, op6) == 0) ||
490 (strcmp (op3, op7) == 0) ||
491 (strcmp (op3, op8) == 0) ||
492 (strcmp (op4, op5) == 0) ||
493 (strcmp (op4, op6) == 0) ||
494 (strcmp (op4, op7) == 0) ||
495 (strcmp (op4, op8) == 0) ||
496 (strcmp (op5, op6) == 0) ||
497 (strcmp (op5, op7) == 0) ||
498 (strcmp (op5, op8) == 0) ||
499 (strcmp (op6, op7) == 0) ||
500 (strcmp (op6, op8) == 0) ||
501 (strcmp (op7, op8) == 0) )
510 * takes two parameters: a variable (bound to a label name)
511 * and an expected reference count.
513 * Returns TRUE if that label is defined and referenced exactly
514 * the given number of times.
516 FBYNAME (labelRefCount)
518 int varNumber, expectedRefCount;
521 /* If we don't have the label hash table yet, build it. */
524 buildLabelRefCountHash (head);
527 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
529 char *label = hTabItemWithKey (vars, varNumber);
533 labelHashEntry *entry;
535 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
539 if (!strcmp (label, entry->name))
543 entry = hTabNextItemWK (labelHash);
549 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
550 label, entry->refCount, expectedRefCount);
553 rc = (expectedRefCount == entry->refCount);
557 fprintf (stderr, "*** internal error: no label has entry for"
558 " %s in labelRefCount peephole.\n",
564 fprintf (stderr, "*** internal error: var %d not bound"
565 " in peephole labelRefCount rule.\n",
573 "*** internal error: labelRefCount peephole restriction"
574 " malformed: %s\n", cmdLine);
580 /* labelRefCountChange:
581 * takes two parameters: a variable (bound to a label name)
582 * and a signed int for changing the reference count.
584 * Please note, this function is not a conditional. It unconditionally
585 * changes the label. It should be passed as the 'last' function
586 * so it only is applied if all other conditions have been met.
588 * should always return TRUE
590 FBYNAME (labelRefCountChange)
592 int varNumber, RefCountDelta;
595 /* If we don't have the label hash table yet, build it. */
598 buildLabelRefCountHash (head);
601 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
603 char *label = hTabItemWithKey (vars, varNumber);
607 labelHashEntry *entry;
609 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
613 if (!strcmp (label, entry->name))
617 entry = hTabNextItemWK (labelHash);
621 if (0 <= entry->refCount + RefCountDelta)
623 entry->refCount += RefCountDelta;
628 fprintf (stderr, "*** internal error: label %s may not get"
629 " negative refCount in %s peephole.\n",
630 label, __FUNCTION__);
635 fprintf (stderr, "*** internal error: no label has entry for"
636 " %s in %s peephole.\n",
637 label, __FUNCTION__);
642 fprintf (stderr, "*** internal error: var %d not bound"
643 " in peephole %s rule.\n",
644 varNumber, __FUNCTION__);
650 "*** internal error: labelRefCount peephole restriction"
651 " malformed: %s\n", cmdLine);
657 /* Within the context of the lines currPl through endPl, determine
658 ** if the variable var contains a symbol that is volatile. Returns
659 ** TRUE only if it is certain that this was not volatile (the symbol
660 ** was found and not volatile, or var was a constant or CPU register).
661 ** Returns FALSE if the symbol was found and volatile, the symbol was
662 ** not found, or var was a indirect/pointer addressing mode.
665 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
667 char symname[SDCC_NAME_MAX + 1];
674 /* Can't tell if indirect accesses are volatile or not, so
675 ** assume they are, just to be safe.
677 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
682 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
684 if (strstr(var,"(bc)"))
686 if (strstr(var,"(de)"))
688 if (strstr(var,"(hl)"))
690 if (strstr(var,"(ix"))
692 if (strstr(var,"(iy"))
696 /* Extract a symbol name from the variable */
697 while (*vp && (*vp!='_'))
699 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
705 /* Nothing resembling a symbol name was found, so it can't
712 for (cl = currPl; cl!=endPl->next; cl = cl->next)
714 if (cl->ic && (cl->ic!=last_ic))
720 op = IC_COND (cl->ic);
721 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
722 return !op->isvolatile;
724 op = IC_JTCOND (cl->ic);
725 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
726 return !op->isvolatile;
728 op = IC_LEFT (cl->ic);
729 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
730 return !op->isvolatile;
731 op = IC_RIGHT (cl->ic);
732 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
733 return !op->isvolatile;
734 op = IC_RESULT (cl->ic);
735 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
736 return !op->isvolatile;
741 /* Couldn't find the symbol for some reason. Assume volatile. */
747 * This rule restriction has two different behaviours depending on
748 * the number of parameters given.
750 * if notVolatile (no parameters given)
751 * The rule is applied only if none of the iCodes originating
752 * the matched pattern reference a volatile operand.
754 * if notVolatile %1 ... (one or more parameters given)
755 * The rule is applied if the parameters are not expressions
756 * containing volatile symbols and are not pointer accesses.
759 FBYNAME (notVolatile)
770 /* If no parameters given, just scan the iCodes for volatile operands */
771 for (cl = currPl; cl!=endPl->next; cl = cl->next)
778 op = IC_COND (cl->ic);
779 if (IS_SYMOP (op) && op->isvolatile)
782 op = IC_JTCOND (cl->ic);
783 if (IS_SYMOP (op) && op->isvolatile)
786 op = IC_LEFT (cl->ic);
787 if (IS_SYMOP (op) && op->isvolatile)
789 op = IC_RIGHT (cl->ic);
790 if (IS_SYMOP (op) && op->isvolatile)
792 op = IC_RESULT (cl->ic);
793 if (IS_SYMOP (op) && op->isvolatile)
801 /* There were parameters; check the volatility of each */
802 while (*cmdLine && ISCHARSPACE(*cmdLine))
809 if (!ISCHARDIGIT(*cmdLine))
811 varNumber = strtol(cmdLine, &digitend, 10);
813 while (*cmdLine && ISCHARSPACE(*cmdLine))
816 var = hTabItemWithKey (vars, varNumber);
820 notvol = notVolatileVariable (var, currPl, endPl);
826 fprintf (stderr, "*** internal error: var %d not bound"
827 " in peephole notVolatile rule.\n",
838 "*** internal error: notVolatile peephole restriction"
839 " malformed: %s\n", cmdLine);
844 /*------------------------------------------------------------------*/
845 /* setFromConditionArgs - parse a peephole condition's arguments */
846 /* to produce a set of strings, one per argument. Variables %x will */
847 /* be replaced with their values. String literals (in single quotes)*/
848 /* are accepted and return in unquoted form. */
849 /*------------------------------------------------------------------*/
851 setFromConditionArgs (char *cmdLine, hTab * vars)
856 set *operands = NULL;
861 while (*cmdLine && ISCHARSPACE(*cmdLine))
869 if (!ISCHARDIGIT(*cmdLine))
871 varNumber = strtol(cmdLine, &digitend, 10);
874 var = hTabItemWithKey (vars, varNumber);
878 addSetHead (&operands, var);
883 else if (*cmdLine == '\'' )
885 char quote = *cmdLine;
888 while (*cmdLine && *cmdLine != quote)
890 if (*cmdLine == quote)
894 addSetHead (&operands, var);
899 while (*cmdLine && ISCHARSPACE(*cmdLine))
906 deleteSet (&operands);
911 operandBaseName (const char *op)
913 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
915 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
917 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
925 /*-------------------------------------------------------------------*/
926 /* operandsNotRelated - returns true of the condition's operands are */
927 /* not related (taking into account register name aliases). N-way */
928 /* comparison performed between all operands. */
929 /*-------------------------------------------------------------------*/
930 FBYNAME (operandsNotRelated)
933 const char *op1, *op2;
935 operands = setFromConditionArgs (cmdLine, vars);
940 "*** internal error: operandsNotRelated peephole restriction"
941 " malformed: %s\n", cmdLine);
945 while ((op1 = setFirstItem (operands)))
947 deleteSetItem (&operands, (void*)op1);
948 op1 = operandBaseName (op1);
950 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
952 op2 = operandBaseName (op2);
953 if (strcmp (op1, op2) == 0)
955 deleteSet (&operands);
961 deleteSet (&operands);
966 /*-----------------------------------------------------------------*/
967 /* callFuncByName - calls a function as defined in the table */
968 /*-----------------------------------------------------------------*/
970 callFuncByName (char *fname,
979 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
984 "labelInRange", labelInRange
988 "labelJTInRange", labelJTInRange
992 "operandsNotSame", operandsNotSame
996 "operandsNotSame3", operandsNotSame3
1000 "operandsNotSame4", operandsNotSame4
1004 "operandsNotSame5", operandsNotSame5
1008 "operandsNotSame6", operandsNotSame6
1012 "operandsNotSame7", operandsNotSame7
1016 "operandsNotSame8", operandsNotSame8
1020 "24bitMode", flat24bitMode
1024 "xramMovcOption", xramMovcOption
1028 "labelRefCount", labelRefCount
1032 "portIsDS390", portIsDS390
1035 "labelIsReturnOnly", labelIsReturnOnly
1038 "okToRemoveSLOC", okToRemoveSLOC
1041 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1044 "notVolatile", notVolatile
1047 "operandsNotRelated", operandsNotRelated
1050 "labelRefCountChange", labelRefCountChange
1054 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1058 /* Isolate the function name part (we are passed the full condition
1059 * string including arguments)
1061 cmdTerm = cmdCopy = Safe_strdup(fname);
1065 funcArgs = funcName = cmdTerm;
1066 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1068 *funcArgs = '\0'; /* terminate the function name */
1072 /* Find the start of the arguments */
1073 if (c == ' ' || c == '\t')
1074 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1077 /* If the arguments started with an opening parenthesis, */
1078 /* use the closing parenthesis for the end of the */
1079 /* arguments and look for the start of another condition */
1080 /* that can optionally follow. If there was no opening */
1081 /* parethesis, then everything that follows are arguments */
1082 /* and there can be no additional conditions. */
1086 while ((c = *cmdTerm) && c != ')')
1088 *cmdTerm = '\0'; /* terminate the arguments */
1092 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1098 cmdTerm = NULL; /* closing parenthesis missing */
1107 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1109 if (strcmp (ftab[i].fname, funcName) == 0)
1111 rc = (*ftab[i].func) (vars, currPl, endPl, head,
1120 "could not find named function \"%s\" in "
1121 "peephole function table\n",
1123 // If the function couldn't be found, let's assume it's
1124 // a bad rule and refuse it.
1129 while (rc && cmdTerm);
1136 /*-----------------------------------------------------------------*/
1137 /* printLine - prints a line chain into a given file */
1138 /*-----------------------------------------------------------------*/
1140 printLine (lineNode * head, FILE * of)
1142 iCode *last_ic = NULL;
1143 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1150 if (head->ic!=last_ic)
1153 if (debug_iCode_tracking)
1156 fprintf (of, "; block = %d, seq = %d\n",
1157 head->ic->block, head->ic->seq);
1159 fprintf (of, "; iCode lost\n");
1163 /* don't indent comments & labels */
1165 (*head->line == ';' ||
1166 head->line[strlen (head->line) - 1] == ':')) {
1167 fprintf (of, "%s\n", head->line);
1169 if (head->isInline && *head->line=='#') {
1170 // comment out preprocessor directives in inline asm
1173 fprintf (of, "\t%s\n", head->line);
1179 /*-----------------------------------------------------------------*/
1180 /* newPeepRule - creates a new peeprule and attach it to the root */
1181 /*-----------------------------------------------------------------*/
1183 newPeepRule (lineNode * match,
1190 pr = Safe_alloc ( sizeof (peepRule));
1192 pr->replace = replace;
1193 pr->restart = restart;
1197 pr->cond = Safe_strdup (cond);
1202 pr->vars = newHashTable (100);
1204 /* if root is empty */
1206 rootRules = currRule = pr;
1208 currRule = currRule->next = pr;
1213 /*-----------------------------------------------------------------*/
1214 /* newLineNode - creates a new peep line */
1215 /*-----------------------------------------------------------------*/
1217 newLineNode (char *line)
1221 pl = Safe_alloc ( sizeof (lineNode));
1222 pl->line = Safe_strdup (line);
1227 /*-----------------------------------------------------------------*/
1228 /* connectLine - connects two lines */
1229 /*-----------------------------------------------------------------*/
1231 connectLine (lineNode * pl1, lineNode * pl2)
1235 fprintf (stderr, "trying to connect null line\n");
1245 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1246 if (!*x) { fprintf(stderr,y); return ; } }
1248 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1249 if (!*x) { fprintf(stderr,z); return ; } }
1250 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1251 if (!*x) { fprintf(stderr,z); return ; } }
1253 /*-----------------------------------------------------------------*/
1254 /* getPeepLine - parses the peep lines */
1255 /*-----------------------------------------------------------------*/
1257 getPeepLine (lineNode ** head, char **bpp)
1259 char lines[MAX_PATTERN_LEN];
1263 lineNode *currL = NULL;
1270 fprintf (stderr, "unexpected end of match pattern\n");
1277 while (ISCHARSPACE (*bp) ||
1288 /* read till end of line */
1290 while ((*bp != '\n' && *bp != '}') && *bp)
1295 while (*lp && ISCHARSPACE(*lp))
1297 isComment = (*lp == ';');
1299 if (!isComment || (isComment && !options.noPeepComments))
1302 *head = currL = newLineNode (lines);
1304 currL = connectLine (currL, newLineNode (lines));
1305 currL->isComment = isComment;
1313 /*-----------------------------------------------------------------*/
1314 /* readRules - reads the rules from a string buffer */
1315 /*-----------------------------------------------------------------*/
1317 readRules (char *bp)
1320 char lines[MAX_PATTERN_LEN];
1324 lineNode *currL = NULL;
1330 /* look for the token "replace" that is the
1332 while (*bp && strncmp (bp, "replace", 7))
1339 /* then look for either "restart" or '{' */
1340 while (strncmp (bp, "restart", 7) &&
1347 fprintf (stderr, "expected 'restart' or '{'\n");
1355 { /* must be restart */
1357 bp += strlen ("restart");
1359 EXPECT_CHR (bp, '{', "expected '{'\n");
1363 /* skip thru all the blank space */
1364 SKIP_SPACE (bp, "unexpected end of rule\n");
1366 match = replace = currL = NULL;
1367 /* we are the start of a rule */
1368 getPeepLine (&match, &bp);
1370 /* now look for by */
1371 EXPECT_STR (bp, "by", "expected 'by'\n");
1373 /* then look for a '{' */
1374 EXPECT_CHR (bp, '{', "expected '{'\n");
1377 /* save char position (needed for generating error msg) */
1380 SKIP_SPACE (bp, "unexpected end of rule\n");
1381 getPeepLine (&replace, &bp);
1383 /* look for a 'if' */
1384 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1387 if (strncmp (bp, "if", 2) == 0)
1390 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1394 fprintf (stderr, "expected condition name\n");
1398 /* look for the condition */
1400 while (*bp && (*bp != '\n'))
1406 newPeepRule (match, replace, lines, restart);
1410 if (*bp && strncmp (bp, "replace", 7))
1412 /* not the start of a new peeprule, so "if" should be here */
1417 /* go to the start of the line following "{" of the "by" token */
1418 while (*rp && (*rp == '\n'))
1421 /* copy text of rule starting with line after "by {" */
1423 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1426 /* and now the rest of the line */
1427 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1431 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1434 newPeepRule (match, replace, NULL, restart);
1440 /*-----------------------------------------------------------------*/
1441 /* keyForVar - returns the numeric key for a var */
1442 /*-----------------------------------------------------------------*/
1448 while (ISCHARDIGIT (*d))
1457 /*-----------------------------------------------------------------*/
1458 /* bindVar - binds a value to a variable in the given hashtable */
1459 /*-----------------------------------------------------------------*/
1461 bindVar (int key, char **s, hTab ** vtab)
1463 char vval[MAX_PATTERN_LEN];
1467 /* first get the value of the variable */
1469 /* the value is ended by a ',' or space or newline or null or ) */
1472 !ISCHARSPACE (*vvx) &&
1478 /* if we find a '(' then we need to balance it */
1490 // include the trailing ')'
1499 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1501 hTabAddItem (vtab, key, vvx);
1504 /*-----------------------------------------------------------------*/
1505 /* matchLine - matches one line */
1506 /*-----------------------------------------------------------------*/
1508 matchLine (char *s, char *d, hTab ** vars)
1517 /* skip white space in both */
1518 while (ISCHARSPACE (*s))
1520 while (ISCHARSPACE (*d))
1523 /* if the destination is a var */
1524 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1526 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1527 /* if the variable is already bound
1528 then it MUST match with dest */
1536 /* variable not bound we need to
1538 bindVar (keyForVar (d + 1), &s, vars);
1540 /* in either case go past the variable */
1542 while (ISCHARDIGIT (*d))
1545 while (ISCHARSPACE (*s))
1547 while (ISCHARSPACE (*d))
1551 /* they should be an exact match other wise */
1560 /* get rid of the trailing spaces
1561 in both source & destination */
1563 while (ISCHARSPACE (*s))
1567 while (ISCHARSPACE (*d))
1570 /* after all this if only one of them
1571 has something left over then no match */
1578 /*-----------------------------------------------------------------*/
1579 /* matchRule - matches a all the rule lines */
1580 /*-----------------------------------------------------------------*/
1582 matchRule (lineNode * pl,
1587 lineNode *spl; /* source pl */
1588 lineNode *rpl; /* rule peep line */
1590 /* setToNull((void *) &pr->vars); */
1591 /* pr->vars = newHashTable(100); */
1593 /* for all the lines defined in the rule */
1599 /* if the source line starts with a ';' then
1600 comment line don't process or the source line
1601 contains == . debugger information skip it */
1603 (*spl->line == ';' || spl->isDebug))
1609 if (!matchLine (spl->line, rpl->line, &pr->vars))
1617 /* if rules ended */
1620 /* if this rule has additional conditions */
1623 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1642 reassociate_ic_down (lineNode *shead, lineNode *stail,
1643 lineNode *rhead, lineNode *rtail)
1645 lineNode *csl; /* current source line */
1646 lineNode *crl; /* current replacement line */
1652 /* skip over any comments */
1653 while (csl!=stail->next && csl->isComment)
1655 while (crl!=rtail->next && crl->isComment)
1658 /* quit if we reach the end */
1659 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1662 if (matchLine(csl->line,crl->line,NULL))
1674 reassociate_ic_up (lineNode *shead, lineNode *stail,
1675 lineNode *rhead, lineNode *rtail)
1677 lineNode *csl; /* current source line */
1678 lineNode *crl; /* current replacement line */
1684 /* skip over any comments */
1685 while (csl!=shead->prev && csl->isComment)
1687 while (crl!=rhead->prev && crl->isComment)
1690 /* quit if we reach the end */
1691 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1694 if (matchLine(csl->line,crl->line,NULL))
1705 /*------------------------------------------------------------------*/
1706 /* reassociate_ic - reassociate replacement lines with origin iCode */
1707 /*------------------------------------------------------------------*/
1709 reassociate_ic (lineNode *shead, lineNode *stail,
1710 lineNode *rhead, lineNode *rtail)
1712 lineNode *csl; /* current source line */
1713 lineNode *crl; /* current replacement line */
1717 /* Check to see if all the source lines (excluding comments) came
1718 ** for the same iCode
1721 for (csl=shead;csl!=stail->next;csl=csl->next)
1722 if (csl->ic && !csl->isComment)
1727 single_iCode = (ic!=NULL);
1728 for (csl=shead;csl!=stail->next;csl=csl->next)
1729 if ((csl->ic != ic) && !csl->isComment)
1731 /* More than one iCode was found. However, if it's just the
1732 ** last line with the different iCode and it was not changed
1733 ** in the replacement, everything else must be the first iCode.
1735 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1737 rtail->ic = stail->ic;
1738 for (crl=rhead;crl!=rtail;crl=crl->next)
1743 single_iCode = FALSE;
1747 /* If all of the source lines came from the same iCode, then so have
1748 ** all of the replacement lines too.
1752 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1757 /* The source lines span iCodes, so we may end up with replacement
1758 ** lines that we don't know which iCode(s) to associate with. Do the
1759 ** best we can by using the following strategies:
1760 ** 1) Start at the top and scan down. As long as the source line
1761 ** matches the replacement line, they have the same iCode.
1762 ** 2) Start at the bottom and scan up. As long as the source line
1763 ** matches the replacement line, they have the same iCode.
1764 ** 3) For any label in the source, look for a matching label in
1765 ** the replacment. If found, they have the same iCode. From
1766 ** these matching labels, scan down for additional matching
1767 ** lines; if found, they also have the same iCode.
1770 /* Strategy #1: Start at the top and scan down for matches
1772 reassociate_ic_down(shead,stail,rhead,rtail);
1774 /* Strategy #2: Start at the bottom and scan up for matches
1776 reassociate_ic_up(shead,stail,rhead,rtail);
1778 /* Strategy #3: Try to match labels
1783 const char *labelStart;
1786 /* skip over any comments */
1787 while (csl!=stail->next && csl->isComment)
1789 if (csl==stail->next)
1792 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1794 /* found a source line label; look for it in the replacment lines */
1798 while (crl!=rtail->next && crl->isComment)
1800 if (crl==rtail->next)
1802 if (matchLine(csl->line, crl->line, NULL))
1804 reassociate_ic_down(csl,stail,crl,rtail);
1814 /* Try to assign a meaningful iCode to any comment that is missing
1815 one. Since they are comments, it's ok to make mistakes; we are just
1816 trying to improve continuity to simplify other tests.
1819 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1821 if (!crl->ic && ic && crl->isComment)
1828 /*-----------------------------------------------------------------*/
1829 /* replaceRule - does replacement of a matching pattern */
1830 /*-----------------------------------------------------------------*/
1832 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1834 lineNode *cl = NULL;
1835 lineNode *pl = NULL, *lhead = NULL;
1836 /* a long function name and long variable name can evaluate to
1837 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1838 char lb[MAX_PATTERN_LEN*4];
1840 lineNode *comment = NULL;
1842 /* collect all the comment lines in the source */
1843 for (cl = *shead; cl != stail; cl = cl->next)
1845 if (cl->line && (*cl->line == ';' || cl->isDebug))
1847 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1848 (comment = newLineNode (cl->line)));
1849 pl->isDebug = cl->isDebug;
1850 pl->isComment = cl->isComment || (*cl->line == ';');
1855 /* for all the lines in the replacement pattern do */
1856 for (pl = pr->replace; pl; pl = pl->next)
1866 /* if the line contains a variable */
1867 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
1869 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1872 fprintf (stderr, "used unbound variable in replacement\n");
1880 while (ISCHARDIGIT (*l)) {
1890 cl = connectLine (cl, newLineNode (lb));
1892 lhead = cl = newLineNode (lb);
1893 cl->isComment = pl->isComment;
1896 /* add the comments if any to the head of list */
1899 lineNode *lc = comment;
1910 /* determine which iCodes the replacment lines relate to */
1911 reassociate_ic(*shead,stail,lhead,cl);
1913 /* now we need to connect / replace the original chain */
1914 /* if there is a prev then change it */
1917 (*shead)->prev->next = lhead;
1918 lhead->prev = (*shead)->prev;
1921 /* now for the tail */
1922 if (stail && stail->next)
1924 stail->next->prev = cl;
1926 cl->next = stail->next;
1931 /* the replacement is empty - delete the source lines */
1933 (*shead)->prev->next = stail->next;
1935 stail->next->prev = (*shead)->prev;
1936 *shead = stail->next;
1940 /* Returns TRUE if this line is a label definition.
1942 * If so, start will point to the start of the label name,
1943 * and len will be it's length.
1946 isLabelDefinition (const char *line, const char **start, int *len)
1948 const char *cp = line;
1950 /* This line is a label if if consists of:
1951 * [optional whitespace] followed by identifier chars
1952 * (alnum | $ | _ ) followed by a colon.
1955 while (*cp && ISCHARSPACE (*cp))
1967 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_'))
1972 if ((cp == *start) || (*cp != ':'))
1977 *len = (cp - (*start));
1981 /* Quick & dirty string hash function. */
1983 hashSymbolName (const char *name)
1989 hash = (hash << 6) ^ *name;
1998 return hash % HTAB_SIZE;
2001 /* Build a hash of all labels in the passed set of lines
2002 * and how many times they are referenced.
2005 buildLabelRefCountHash (lineNode * head)
2012 assert (labelHash == NULL);
2013 labelHash = newHashTable (HTAB_SIZE);
2015 /* First pass: locate all the labels. */
2020 if (isLabelDefinition (line->line, &label, &labelLen)
2021 && labelLen <= SDCC_NAME_MAX)
2023 labelHashEntry *entry;
2025 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2027 memcpy (entry->name, label, labelLen);
2028 entry->name[labelLen] = 0;
2029 entry->refCount = -1;
2031 /* Assume function entry points are referenced somewhere, */
2032 /* even if we can't find a reference (might be from outside */
2034 if (line->ic && (line->ic->op == FUNCTION))
2037 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2043 /* Second pass: for each line, note all the referenced labels. */
2044 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2048 for (i = 0; i < HTAB_SIZE; i++)
2050 labelHashEntry *thisEntry;
2052 thisEntry = hTabFirstItemWK (labelHash, i);
2056 if (strstr (line->line, thisEntry->name))
2058 thisEntry->refCount++;
2060 thisEntry = hTabNextItemWK (labelHash);
2067 /* Spew the contents of the table. Debugging fun only. */
2068 for (i = 0; i < HTAB_SIZE; i++)
2070 labelHashEntry *thisEntry;
2072 thisEntry = hTabFirstItemWK (labelHash, i);
2076 fprintf (stderr, "label: %s ref %d\n",
2077 thisEntry->name, thisEntry->refCount);
2078 thisEntry = hTabNextItemWK (labelHash);
2084 /* How does this work?
2090 replace and restart.
2095 Where is stuff allocated?
2099 /*-----------------------------------------------------------------*/
2100 /* peepHole - matches & substitutes rules */
2101 /*-----------------------------------------------------------------*/
2103 peepHole (lineNode ** pls)
2107 lineNode *mtail = NULL;
2110 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2111 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2112 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2116 assert(labelHash == NULL);
2123 for (pr = rootRules; pr; pr = pr->next)
2125 for (spl = *pls; spl; spl = spl->next)
2127 /* if inline assembler then no peep hole */
2131 /* don't waste time starting a match on debug symbol
2133 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2138 /* Tidy up any data stored in the hTab */
2141 if (matchRule (spl, &mtail, pr, *pls))
2146 replaceRule (pls, mtail, pr);
2148 replaceRule (&spl, mtail, pr);
2150 /* if restart rule type then
2151 start at the top again */
2160 hTabDeleteAll (pr->vars);
2161 Safe_free (pr->vars);
2165 freeTrace (&_G.values);
2168 } while (restart == TRUE);
2172 hTabDeleteAll (labelHash);
2173 freeTrace (&_G.labels);
2179 /*-----------------------------------------------------------------*/
2180 /* readFileIntoBuffer - reads a file into a string buffer */
2181 /*-----------------------------------------------------------------*/
2183 readFileIntoBuffer (char *fname)
2189 char lb[MAX_PATTERN_LEN];
2191 if (!(f = fopen (fname, "r")))
2193 fprintf (stderr, "cannot open peep rule file\n");
2197 while ((ch = fgetc (f)) != EOF)
2201 /* if we maxed out our local buffer */
2202 if (nch >= (MAX_PATTERN_LEN - 2))
2205 /* copy it into allocated buffer */
2208 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2209 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2213 rs = Safe_strdup (lb);
2219 /* if some charaters left over */
2223 /* copy it into allocated buffer */
2226 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2227 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2231 rs = Safe_strdup (lb);
2237 /*-----------------------------------------------------------------*/
2238 /* initPeepHole - initialises the peep hole optimizer stuff */
2239 /*-----------------------------------------------------------------*/
2245 /* read in the default rules */
2246 readRules (port->peep.default_rules);
2248 /* if we have any additional file read it too */
2249 if (options.peep_file)
2251 readRules (s = readFileIntoBuffer (options.peep_file));
2252 setToNull ((void *) &s);
2256 #if !OPT_DISABLE_PIC
2257 /* Convert the peep rules into pcode.
2258 NOTE: this is only support in the PIC port (at the moment)
2261 peepRules2pCode(rootRules);
2264 #if !OPT_DISABLE_PIC16
2265 /* Convert the peep rules into pcode.
2266 NOTE: this is only support in the PIC port (at the moment)
2267 and the PIC16 port (VR 030601)
2269 if (TARGET_IS_PIC16)
2270 pic16_peepRules2pCode(rootRules);