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;
37 hTab *labelHash = NULL;
45 static int hashSymbolName (const char *name);
46 static void buildLabelRefCountHash (lineNode * head);
48 static bool matchLine (char *, char *, hTab **);
50 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
51 lineNode *head, char *cmdLine)
54 void peepRules2pCode(peepRule *);
57 #if !OPT_DISABLE_PIC16
58 void pic16_peepRules2pCode(peepRule *);
61 /*-----------------------------------------------------------------*/
62 /* pcDistance - afinds a label back ward or forward */
63 /*-----------------------------------------------------------------*/
66 pcDistance (lineNode * cpos, char *lbl, bool back)
69 char buff[MAX_PATTERN_LEN];
72 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
80 if (port->peep.getSize) {
81 dist += port->peep.getSize(pl);
87 if (strncmp (pl->line, buff, strlen (buff)) == 0)
99 /*-----------------------------------------------------------------*/
100 /* flat24bitModeAndPortDS390 - */
101 /*-----------------------------------------------------------------*/
102 FBYNAME (flat24bitModeAndPortDS390)
104 return (((strcmp(port->target,"ds390") == 0) ||
105 (strcmp(port->target,"ds400") == 0)) &&
106 (options.model == MODEL_FLAT24));
109 /*-----------------------------------------------------------------*/
110 /* portIsDS390 - return true if port is DS390 */
111 /*-----------------------------------------------------------------*/
112 FBYNAME (portIsDS390)
114 return ((strcmp(port->target,"ds390") == 0) ||
115 (strcmp(port->target,"ds400") == 0));
118 /*-----------------------------------------------------------------*/
119 /* flat24bitMode - will check to see if we are in flat24 mode */
120 /*-----------------------------------------------------------------*/
121 FBYNAME (flat24bitMode)
123 return (options.model == MODEL_FLAT24);
126 /*-----------------------------------------------------------------*/
127 /* xramMovcOption - check if using movc to read xram */
128 /*-----------------------------------------------------------------*/
129 FBYNAME (xramMovcOption)
131 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
139 /*-----------------------------------------------------------------*/
140 /* labelInRange - will check to see if label %5 is within range */
141 /*-----------------------------------------------------------------*/
142 FBYNAME (labelInRange)
144 /* assumes that %5 pattern variable has the label name */
145 char *lbl = hTabItemWithKey (vars, 5);
151 /* Don't optimize jumps in a jump table; a more generic test */
152 if (currPl->ic && currPl->ic->op == JUMPTABLE)
155 /* if the previous two instructions are "ljmp"s then don't
156 do it since it can be part of a jump table */
157 if (currPl->prev && currPl->prev->prev &&
158 strstr (currPl->prev->line, "ljmp") &&
159 strstr (currPl->prev->prev->line, "ljmp"))
162 /* calculate the label distance : the jump for reladdr can be
163 +/- 127 bytes, here Iam assuming that an average 8051
164 instruction is 2 bytes long, so if the label is more than
165 63 intructions away, the label is considered out of range
166 for a relative jump. we could get more precise this will
167 suffice for now since it catches > 90% cases */
168 dist = (pcDistance (currPl, lbl, TRUE) +
169 pcDistance (currPl, lbl, FALSE));
171 /* changed to 127, now that pcDistance return actual number of bytes */
172 if (!dist || dist > 127)
179 /*-----------------------------------------------------------------*/
180 /* labelJTInRange - will check to see if label %5 and up are */
182 /* Specifically meant to optimize long (3-byte) jumps to short */
183 /* (2-byte) jumps in jumptables */
184 /*-----------------------------------------------------------------*/
185 FBYNAME (labelJTInRange)
190 if (!getenv("SDCC_SJMP_JUMPTABLE"))
193 /* Only optimize within a jump table */
194 if (currPl->ic && currPl->ic->op != JUMPTABLE)
197 count = elementsInSet( IC_JTLABELS (currPl->ic) );
199 /* check all labels (this is needed if the case statements are unsorted) */
200 for (i=0; i<count; i++)
202 /* assumes that the %5 pattern variable has the first ljmp label */
203 lbl = hTabItemWithKey (vars, 5+i);
207 dist = pcDistance (currPl, lbl, FALSE);
209 /* three terms used to calculate allowable distance */
210 // 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);
212 dist > 127+ /* range of sjmp */
213 (7+3*i)+ /* offset between this jump and currPl,
214 should use pcDistance instead? */
215 (count-i-1) /* if peephole applies distance is shortened */
223 /*-----------------------------------------------------------------*/
224 /* labelIsReturnOnly - Check if label %5 is followed by RET */
225 /*-----------------------------------------------------------------*/
226 FBYNAME (labelIsReturnOnly)
228 /* assumes that %5 pattern variable has the label name */
229 const char *label, *p;
234 /* Don't optimize jumps in a jump table; a more generic test */
235 if (currPl->ic && currPl->ic->op == JUMPTABLE)
238 label = hTabItemWithKey (vars, 5);
239 if (!label) return FALSE;
242 for(pl = currPl; pl; pl = pl->next) {
243 if (pl->line && !pl->isDebug && !pl->isComment &&
245 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
246 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
247 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
248 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
249 *(pl->line+5) != '$') {
250 return FALSE; /* non-local label encountered */
254 if (!pl) return FALSE; /* did not find the label */
256 while (pl && (pl->isDebug || pl->isComment))
258 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
260 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
266 if (strcmp(p, retInst) == 0) return TRUE;
271 /*-----------------------------------------------------------------*/
272 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
273 /* usage of it in the code depends on a value from this section */
274 /*-----------------------------------------------------------------*/
275 FBYNAME (okToRemoveSLOC)
278 const char *sloc, *p;
279 int dummy1, dummy2, dummy3;
281 /* assumes that %1 as the SLOC name */
282 sloc = hTabItemWithKey (vars, 1);
283 if (sloc == NULL) return FALSE;
284 p = strstr(sloc, "sloc");
285 if (p == NULL) return FALSE;
287 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
288 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
289 /* the sloc name begins with that. Probably not really necessary */
291 /* Look for any occurance of this SLOC before the peephole match */
292 for (pl = currPl->prev; pl; pl = pl->prev) {
293 if (pl->line && !pl->isDebug && !pl->isComment
294 && *pl->line != ';' && strstr(pl->line, sloc))
297 /* Look for any occurance of this SLOC after the peephole match */
298 for (pl = endPl->next; pl; pl = pl->next) {
299 if (pl->line && !pl->isDebug && !pl->isComment
300 && *pl->line != ';' && strstr(pl->line, sloc))
303 return TRUE; /* safe for a peephole to remove it :) */
306 /*-----------------------------------------------------------------*/
307 /* deadMove - Check, if a pop/push pair can be removed */
308 /*-----------------------------------------------------------------*/
311 const char *reg = hTabItemWithKey (vars, 1);
313 if (port->peep.deadMove)
314 return port->peep.deadMove (reg, currPl, head);
316 fprintf (stderr, "Function deadMove not initialized in port structure\n");
320 /*-----------------------------------------------------------------*/
321 /* operandsNotSame - check if %1 & %2 are the same */
322 /*-----------------------------------------------------------------*/
323 FBYNAME (operandsNotSame)
325 char *op1 = hTabItemWithKey (vars, 1);
326 char *op2 = hTabItemWithKey (vars, 2);
328 if (strcmp (op1, op2) == 0)
334 /*-----------------------------------------------------------------*/
335 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
336 /*-----------------------------------------------------------------*/
337 FBYNAME (operandsNotSame3)
339 char *op1 = hTabItemWithKey (vars, 1);
340 char *op2 = hTabItemWithKey (vars, 2);
341 char *op3 = hTabItemWithKey (vars, 3);
343 if ( (strcmp (op1, op2) == 0) ||
344 (strcmp (op1, op3) == 0) ||
345 (strcmp (op2, op3) == 0) )
351 /*-----------------------------------------------------------------*/
352 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
353 /*-----------------------------------------------------------------*/
354 FBYNAME (operandsNotSame4)
356 char *op1 = hTabItemWithKey (vars, 1);
357 char *op2 = hTabItemWithKey (vars, 2);
358 char *op3 = hTabItemWithKey (vars, 3);
359 char *op4 = hTabItemWithKey (vars, 4);
361 if ( (strcmp (op1, op2) == 0) ||
362 (strcmp (op1, op3) == 0) ||
363 (strcmp (op1, op4) == 0) ||
364 (strcmp (op2, op3) == 0) ||
365 (strcmp (op2, op4) == 0) ||
366 (strcmp (op3, op4) == 0) )
372 /*-----------------------------------------------------------------*/
373 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
374 /*-----------------------------------------------------------------*/
375 FBYNAME (operandsNotSame5)
377 char *op1 = hTabItemWithKey (vars, 1);
378 char *op2 = hTabItemWithKey (vars, 2);
379 char *op3 = hTabItemWithKey (vars, 3);
380 char *op4 = hTabItemWithKey (vars, 4);
381 char *op5 = hTabItemWithKey (vars, 5);
383 if ( (strcmp (op1, op2) == 0) ||
384 (strcmp (op1, op3) == 0) ||
385 (strcmp (op1, op4) == 0) ||
386 (strcmp (op1, op5) == 0) ||
387 (strcmp (op2, op3) == 0) ||
388 (strcmp (op2, op4) == 0) ||
389 (strcmp (op2, op5) == 0) ||
390 (strcmp (op3, op4) == 0) ||
391 (strcmp (op3, op5) == 0) ||
392 (strcmp (op4, op5) == 0) )
398 /*-----------------------------------------------------------------*/
399 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
400 /*-----------------------------------------------------------------*/
401 FBYNAME (operandsNotSame6)
403 char *op1 = hTabItemWithKey (vars, 1);
404 char *op2 = hTabItemWithKey (vars, 2);
405 char *op3 = hTabItemWithKey (vars, 3);
406 char *op4 = hTabItemWithKey (vars, 4);
407 char *op5 = hTabItemWithKey (vars, 5);
408 char *op6 = hTabItemWithKey (vars, 6);
410 if ( (strcmp (op1, op2) == 0) ||
411 (strcmp (op1, op3) == 0) ||
412 (strcmp (op1, op4) == 0) ||
413 (strcmp (op1, op5) == 0) ||
414 (strcmp (op1, op6) == 0) ||
415 (strcmp (op2, op3) == 0) ||
416 (strcmp (op2, op4) == 0) ||
417 (strcmp (op2, op5) == 0) ||
418 (strcmp (op2, op6) == 0) ||
419 (strcmp (op3, op4) == 0) ||
420 (strcmp (op3, op5) == 0) ||
421 (strcmp (op3, op6) == 0) ||
422 (strcmp (op4, op5) == 0) ||
423 (strcmp (op4, op6) == 0) ||
424 (strcmp (op5, op6) == 0) )
431 /*-----------------------------------------------------------------*/
432 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
433 /*-----------------------------------------------------------------*/
434 FBYNAME (operandsNotSame7)
436 char *op1 = hTabItemWithKey (vars, 1);
437 char *op2 = hTabItemWithKey (vars, 2);
438 char *op3 = hTabItemWithKey (vars, 3);
439 char *op4 = hTabItemWithKey (vars, 4);
440 char *op5 = hTabItemWithKey (vars, 5);
441 char *op6 = hTabItemWithKey (vars, 6);
442 char *op7 = hTabItemWithKey (vars, 7);
444 if ( (strcmp (op1, op2) == 0) ||
445 (strcmp (op1, op3) == 0) ||
446 (strcmp (op1, op4) == 0) ||
447 (strcmp (op1, op5) == 0) ||
448 (strcmp (op1, op6) == 0) ||
449 (strcmp (op1, op7) == 0) ||
450 (strcmp (op2, op3) == 0) ||
451 (strcmp (op2, op4) == 0) ||
452 (strcmp (op2, op5) == 0) ||
453 (strcmp (op2, op6) == 0) ||
454 (strcmp (op2, op7) == 0) ||
455 (strcmp (op3, op4) == 0) ||
456 (strcmp (op3, op5) == 0) ||
457 (strcmp (op3, op6) == 0) ||
458 (strcmp (op3, op7) == 0) ||
459 (strcmp (op4, op5) == 0) ||
460 (strcmp (op4, op6) == 0) ||
461 (strcmp (op4, op7) == 0) ||
462 (strcmp (op5, op6) == 0) ||
463 (strcmp (op5, op7) == 0) ||
464 (strcmp (op6, op7) == 0) )
470 /*-----------------------------------------------------------------*/
471 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
472 /*-----------------------------------------------------------------*/
473 FBYNAME (operandsNotSame8)
475 char *op1 = hTabItemWithKey (vars, 1);
476 char *op2 = hTabItemWithKey (vars, 2);
477 char *op3 = hTabItemWithKey (vars, 3);
478 char *op4 = hTabItemWithKey (vars, 4);
479 char *op5 = hTabItemWithKey (vars, 5);
480 char *op6 = hTabItemWithKey (vars, 6);
481 char *op7 = hTabItemWithKey (vars, 7);
482 char *op8 = hTabItemWithKey (vars, 8);
484 if ( (strcmp (op1, op2) == 0) ||
485 (strcmp (op1, op3) == 0) ||
486 (strcmp (op1, op4) == 0) ||
487 (strcmp (op1, op5) == 0) ||
488 (strcmp (op1, op6) == 0) ||
489 (strcmp (op1, op7) == 0) ||
490 (strcmp (op1, op8) == 0) ||
491 (strcmp (op2, op3) == 0) ||
492 (strcmp (op2, op4) == 0) ||
493 (strcmp (op2, op5) == 0) ||
494 (strcmp (op2, op6) == 0) ||
495 (strcmp (op2, op7) == 0) ||
496 (strcmp (op2, op8) == 0) ||
497 (strcmp (op3, op4) == 0) ||
498 (strcmp (op3, op5) == 0) ||
499 (strcmp (op3, op6) == 0) ||
500 (strcmp (op3, op7) == 0) ||
501 (strcmp (op3, op8) == 0) ||
502 (strcmp (op4, op5) == 0) ||
503 (strcmp (op4, op6) == 0) ||
504 (strcmp (op4, op7) == 0) ||
505 (strcmp (op4, op8) == 0) ||
506 (strcmp (op5, op6) == 0) ||
507 (strcmp (op5, op7) == 0) ||
508 (strcmp (op5, op8) == 0) ||
509 (strcmp (op6, op7) == 0) ||
510 (strcmp (op6, op8) == 0) ||
511 (strcmp (op7, op8) == 0) )
517 /*-----------------------------------------------------------------*/
518 /* labelHashEntry- searches for a label in the list labelHash */
519 /* Builds labelHash, if it does not yet exist. */
520 /* Returns the labelHashEntry or NULL */
521 /*-----------------------------------------------------------------*/
523 getLabelRef (const char *label, lineNode *head)
525 labelHashEntry *entry;
527 /* If we don't have the label hash table yet, build it. */
530 buildLabelRefCountHash (head);
533 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
537 if (!strcmp (label, entry->name))
541 entry = hTabNextItemWK (labelHash);
548 * takes two parameters: a variable (bound to a label name)
549 * and an expected reference count.
551 * Returns TRUE if that label is defined and referenced exactly
552 * the given number of times.
554 FBYNAME (labelRefCount)
556 int varNumber, expectedRefCount;
559 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
561 char *label = hTabItemWithKey (vars, varNumber);
565 labelHashEntry *entry = getLabelRef (label, head);
571 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
572 label, entry->refCount, expectedRefCount);
575 rc = (expectedRefCount == entry->refCount);
579 fprintf (stderr, "*** internal error: no label has entry for"
580 " %s in labelRefCount peephole.\n",
586 fprintf (stderr, "*** internal error: var %d not bound"
587 " in peephole labelRefCount rule.\n",
595 "*** internal error: labelRefCount peephole restriction"
596 " malformed: %s\n", cmdLine);
602 /* labelRefCountChange:
603 * takes two parameters: a variable (bound to a label name)
604 * and a signed int for changing the reference count.
606 * Please note, this function is not a conditional. It unconditionally
607 * changes the label. It should be passed as the 'last' function
608 * so it only is applied if all other conditions have been met.
610 * should always return TRUE
612 FBYNAME (labelRefCountChange)
614 int varNumber, RefCountDelta;
617 /* If we don't have the label hash table yet, build it. */
620 buildLabelRefCountHash (head);
623 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
625 char *label = hTabItemWithKey (vars, varNumber);
629 labelHashEntry *entry;
631 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
635 if (!strcmp (label, entry->name))
639 entry = hTabNextItemWK (labelHash);
643 if (0 <= entry->refCount + RefCountDelta)
645 entry->refCount += RefCountDelta;
650 fprintf (stderr, "*** internal error: label %s may not get"
651 " negative refCount in %s peephole.\n",
652 label, __FUNCTION__);
657 fprintf (stderr, "*** internal error: no label has entry for"
658 " %s in %s peephole.\n",
659 label, __FUNCTION__);
664 fprintf (stderr, "*** internal error: var %d not bound"
665 " in peephole %s rule.\n",
666 varNumber, __FUNCTION__);
672 "*** internal error: labelRefCount peephole restriction"
673 " malformed: %s\n", cmdLine);
679 /* Within the context of the lines currPl through endPl, determine
680 ** if the variable var contains a symbol that is volatile. Returns
681 ** TRUE only if it is certain that this was not volatile (the symbol
682 ** was found and not volatile, or var was a constant or CPU register).
683 ** Returns FALSE if the symbol was found and volatile, the symbol was
684 ** not found, or var was a indirect/pointer addressing mode.
687 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
689 char symname[SDCC_NAME_MAX + 1];
696 /* Can't tell if indirect accesses are volatile or not, so
697 ** assume they are, just to be safe.
699 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
704 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
706 if (strstr(var,"(bc)"))
708 if (strstr(var,"(de)"))
710 if (strstr(var,"(hl)"))
712 if (strstr(var,"(ix"))
714 if (strstr(var,"(iy"))
718 /* Extract a symbol name from the variable */
719 while (*vp && (*vp!='_'))
721 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
727 /* Nothing resembling a symbol name was found, so it can't
734 for (cl = currPl; cl!=endPl->next; cl = cl->next)
736 if (cl->ic && (cl->ic!=last_ic))
742 op = IC_COND (cl->ic);
743 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
744 return !op->isvolatile;
746 op = IC_JTCOND (cl->ic);
747 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
748 return !op->isvolatile;
750 op = IC_LEFT (cl->ic);
751 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
752 return !op->isvolatile;
753 op = IC_RIGHT (cl->ic);
754 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
755 return !op->isvolatile;
756 op = IC_RESULT (cl->ic);
757 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
758 return !op->isvolatile;
763 /* Couldn't find the symbol for some reason. Assume volatile. */
769 * This rule restriction has two different behaviours depending on
770 * the number of parameters given.
772 * if notVolatile (no parameters given)
773 * The rule is applied only if none of the iCodes originating
774 * the matched pattern reference a volatile operand.
776 * if notVolatile %1 ... (one or more parameters given)
777 * The rule is applied if the parameters are not expressions
778 * containing volatile symbols and are not pointer accesses.
781 FBYNAME (notVolatile)
792 /* If no parameters given, just scan the iCodes for volatile operands */
793 for (cl = currPl; cl!=endPl->next; cl = cl->next)
800 op = IC_COND (cl->ic);
801 if (IS_SYMOP (op) && op->isvolatile)
804 op = IC_JTCOND (cl->ic);
805 if (IS_SYMOP (op) && op->isvolatile)
808 op = IC_LEFT (cl->ic);
809 if (IS_SYMOP (op) && op->isvolatile)
811 op = IC_RIGHT (cl->ic);
812 if (IS_SYMOP (op) && op->isvolatile)
814 op = IC_RESULT (cl->ic);
815 if (IS_SYMOP (op) && op->isvolatile)
823 /* There were parameters; check the volatility of each */
824 while (*cmdLine && ISCHARSPACE(*cmdLine))
831 if (!ISCHARDIGIT(*cmdLine))
833 varNumber = strtol(cmdLine, &digitend, 10);
835 while (*cmdLine && ISCHARSPACE(*cmdLine))
838 var = hTabItemWithKey (vars, varNumber);
842 notvol = notVolatileVariable (var, currPl, endPl);
848 fprintf (stderr, "*** internal error: var %d not bound"
849 " in peephole notVolatile rule.\n",
860 "*** internal error: notVolatile peephole restriction"
861 " malformed: %s\n", cmdLine);
866 /*------------------------------------------------------------------*/
867 /* setFromConditionArgs - parse a peephole condition's arguments */
868 /* to produce a set of strings, one per argument. Variables %x will */
869 /* be replaced with their values. String literals (in single quotes)*/
870 /* are accepted and return in unquoted form. */
871 /*------------------------------------------------------------------*/
873 setFromConditionArgs (char *cmdLine, hTab * vars)
878 set *operands = NULL;
883 while (*cmdLine && ISCHARSPACE(*cmdLine))
891 if (!ISCHARDIGIT(*cmdLine))
893 varNumber = strtol(cmdLine, &digitend, 10);
896 var = hTabItemWithKey (vars, varNumber);
900 addSetHead (&operands, var);
905 else if (*cmdLine == '\'' )
907 char quote = *cmdLine;
910 while (*cmdLine && *cmdLine != quote)
912 if (*cmdLine == quote)
916 addSetHead (&operands, var);
921 while (*cmdLine && ISCHARSPACE(*cmdLine))
928 deleteSet (&operands);
933 operandBaseName (const char *op)
935 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
937 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
939 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
947 /*-------------------------------------------------------------------*/
948 /* operandsNotRelated - returns true of the condition's operands are */
949 /* not related (taking into account register name aliases). N-way */
950 /* comparison performed between all operands. */
951 /*-------------------------------------------------------------------*/
952 FBYNAME (operandsNotRelated)
955 const char *op1, *op2;
957 operands = setFromConditionArgs (cmdLine, vars);
962 "*** internal error: operandsNotRelated peephole restriction"
963 " malformed: %s\n", cmdLine);
967 while ((op1 = setFirstItem (operands)))
969 deleteSetItem (&operands, (void*)op1);
970 op1 = operandBaseName (op1);
972 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
974 op2 = operandBaseName (op2);
975 if (strcmp (op1, op2) == 0)
977 deleteSet (&operands);
983 deleteSet (&operands);
988 /*-------------------------------------------------------------------*/
989 /* operandsLiteral - returns true of the condition's operands are */
991 /*-------------------------------------------------------------------*/
992 FBYNAME (operandsLiteral)
997 operands = setFromConditionArgs (cmdLine, vars);
1002 "*** internal error: operandsLiteral peephole restriction"
1003 " malformed: %s\n", cmdLine);
1007 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1011 deleteSet (&operands);
1016 deleteSet (&operands);
1021 /*-----------------------------------------------------------------*/
1022 /* callFuncByName - calls a function as defined in the table */
1023 /*-----------------------------------------------------------------*/
1025 callFuncByName (char *fname,
1034 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1039 "labelInRange", labelInRange
1043 "labelJTInRange", labelJTInRange
1047 "operandsNotSame", operandsNotSame
1051 "operandsNotSame3", operandsNotSame3
1055 "operandsNotSame4", operandsNotSame4
1059 "operandsNotSame5", operandsNotSame5
1063 "operandsNotSame6", operandsNotSame6
1067 "operandsNotSame7", operandsNotSame7
1071 "operandsNotSame8", operandsNotSame8
1075 "24bitMode", flat24bitMode
1079 "xramMovcOption", xramMovcOption
1083 "labelRefCount", labelRefCount
1087 "portIsDS390", portIsDS390
1090 "labelIsReturnOnly", labelIsReturnOnly
1093 "okToRemoveSLOC", okToRemoveSLOC
1096 "deadMove", deadMove
1099 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1102 "notVolatile", notVolatile
1105 "operandsNotRelated", operandsNotRelated
1108 "operandsLiteral", operandsLiteral
1111 "labelRefCountChange", labelRefCountChange
1115 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1119 /* Isolate the function name part (we are passed the full condition
1120 * string including arguments)
1122 cmdTerm = cmdCopy = Safe_strdup(fname);
1126 funcArgs = funcName = cmdTerm;
1127 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1129 *funcArgs = '\0'; /* terminate the function name */
1133 /* Find the start of the arguments */
1134 if (c == ' ' || c == '\t')
1135 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1138 /* If the arguments started with an opening parenthesis, */
1139 /* use the closing parenthesis for the end of the */
1140 /* arguments and look for the start of another condition */
1141 /* that can optionally follow. If there was no opening */
1142 /* parethesis, then everything that follows are arguments */
1143 /* and there can be no additional conditions. */
1147 while ((c = *cmdTerm) && c != ')')
1149 *cmdTerm = '\0'; /* terminate the arguments */
1153 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1159 cmdTerm = NULL; /* closing parenthesis missing */
1168 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1170 if (strcmp (ftab[i].fname, funcName) == 0)
1172 rc = (*ftab[i].func) (vars, currPl, endPl, head,
1181 "could not find named function \"%s\" in "
1182 "peephole function table\n",
1184 // If the function couldn't be found, let's assume it's
1185 // a bad rule and refuse it.
1190 while (rc && cmdTerm);
1197 /*-----------------------------------------------------------------*/
1198 /* printLine - prints a line chain into a given file */
1199 /*-----------------------------------------------------------------*/
1201 printLine (lineNode * head, FILE * of)
1203 iCode *last_ic = NULL;
1204 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1211 if (head->ic!=last_ic)
1214 if (debug_iCode_tracking)
1217 fprintf (of, "; block = %d, seq = %d\n",
1218 head->ic->block, head->ic->seq);
1220 fprintf (of, "; iCode lost\n");
1224 /* don't indent comments & labels */
1226 (head->isComment || head->isLabel)) {
1227 fprintf (of, "%s\n", head->line);
1229 if (head->isInline && *head->line=='#') {
1230 // comment out preprocessor directives in inline asm
1233 fprintf (of, "\t%s\n", head->line);
1239 /*-----------------------------------------------------------------*/
1240 /* newPeepRule - creates a new peeprule and attach it to the root */
1241 /*-----------------------------------------------------------------*/
1243 newPeepRule (lineNode * match,
1250 pr = Safe_alloc ( sizeof (peepRule));
1252 pr->replace = replace;
1253 pr->restart = restart;
1257 pr->cond = Safe_strdup (cond);
1262 pr->vars = newHashTable (100);
1264 /* if root is empty */
1266 rootRules = currRule = pr;
1268 currRule = currRule->next = pr;
1273 /*-----------------------------------------------------------------*/
1274 /* newLineNode - creates a new peep line */
1275 /*-----------------------------------------------------------------*/
1277 newLineNode (char *line)
1281 pl = Safe_alloc ( sizeof (lineNode));
1282 pl->line = Safe_strdup (line);
1287 /*-----------------------------------------------------------------*/
1288 /* connectLine - connects two lines */
1289 /*-----------------------------------------------------------------*/
1291 connectLine (lineNode * pl1, lineNode * pl2)
1295 fprintf (stderr, "trying to connect null line\n");
1305 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1306 if (!*x) { fprintf(stderr,y); return ; } }
1308 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1309 if (!*x) { fprintf(stderr,z); return ; } }
1310 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1311 if (!*x) { fprintf(stderr,z); return ; } }
1313 /*-----------------------------------------------------------------*/
1314 /* getPeepLine - parses the peep lines */
1315 /*-----------------------------------------------------------------*/
1317 getPeepLine (lineNode ** head, char **bpp)
1319 char lines[MAX_PATTERN_LEN];
1323 lineNode *currL = NULL;
1330 fprintf (stderr, "unexpected end of match pattern\n");
1337 while (ISCHARSPACE (*bp) ||
1348 /* read till end of line */
1350 while ((*bp != '\n' && *bp != '}') && *bp)
1355 while (*lp && ISCHARSPACE(*lp))
1357 isComment = (*lp == ';');
1359 if (!isComment || (isComment && !options.noPeepComments))
1365 *head = currL = newLineNode (lines);
1367 currL = connectLine (currL, newLineNode (lines));
1368 currL->isComment = isComment;
1369 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1378 /*-----------------------------------------------------------------*/
1379 /* readRules - reads the rules from a string buffer */
1380 /*-----------------------------------------------------------------*/
1382 readRules (char *bp)
1385 char lines[MAX_PATTERN_LEN];
1389 lineNode *currL = NULL;
1395 /* look for the token "replace" that is the
1397 while (*bp && strncmp (bp, "replace", 7))
1404 /* then look for either "restart" or '{' */
1405 while (strncmp (bp, "restart", 7) &&
1412 fprintf (stderr, "expected 'restart' or '{'\n");
1420 { /* must be restart */
1422 bp += strlen ("restart");
1424 EXPECT_CHR (bp, '{', "expected '{'\n");
1428 /* skip thru all the blank space */
1429 SKIP_SPACE (bp, "unexpected end of rule\n");
1431 match = replace = currL = NULL;
1432 /* we are the start of a rule */
1433 getPeepLine (&match, &bp);
1435 /* now look for by */
1436 EXPECT_STR (bp, "by", "expected 'by'\n");
1438 /* then look for a '{' */
1439 EXPECT_CHR (bp, '{', "expected '{'\n");
1442 /* save char position (needed for generating error msg) */
1445 SKIP_SPACE (bp, "unexpected end of rule\n");
1446 getPeepLine (&replace, &bp);
1448 /* look for a 'if' */
1449 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1452 if (strncmp (bp, "if", 2) == 0)
1455 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1459 fprintf (stderr, "expected condition name\n");
1463 /* look for the condition */
1465 while (*bp && (*bp != '\n'))
1471 newPeepRule (match, replace, lines, restart);
1475 if (*bp && strncmp (bp, "replace", 7))
1477 /* not the start of a new peeprule, so "if" should be here */
1482 /* go to the start of the line following "{" of the "by" token */
1483 while (*rp && (*rp == '\n'))
1486 /* copy text of rule starting with line after "by {" */
1488 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1491 /* and now the rest of the line */
1492 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1496 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1499 newPeepRule (match, replace, NULL, restart);
1505 /*-----------------------------------------------------------------*/
1506 /* keyForVar - returns the numeric key for a var */
1507 /*-----------------------------------------------------------------*/
1513 while (ISCHARDIGIT (*d))
1522 /*-----------------------------------------------------------------*/
1523 /* bindVar - binds a value to a variable in the given hashtable */
1524 /*-----------------------------------------------------------------*/
1526 bindVar (int key, char **s, hTab ** vtab)
1528 char vval[MAX_PATTERN_LEN];
1532 /* first get the value of the variable */
1534 /* the value is ended by a ',' or space or newline or null or ) */
1537 !ISCHARSPACE (*vvx) &&
1543 /* if we find a '(' then we need to balance it */
1555 // include the trailing ')'
1564 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1566 hTabAddItem (vtab, key, vvx);
1569 /*-----------------------------------------------------------------*/
1570 /* matchLine - matches one line */
1571 /*-----------------------------------------------------------------*/
1573 matchLine (char *s, char *d, hTab ** vars)
1582 /* skip white space in both */
1583 while (ISCHARSPACE (*s))
1585 while (ISCHARSPACE (*d))
1588 /* if the destination is a var */
1589 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1591 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1592 /* if the variable is already bound
1593 then it MUST match with dest */
1601 /* variable not bound we need to
1603 bindVar (keyForVar (d + 1), &s, vars);
1605 /* in either case go past the variable */
1607 while (ISCHARDIGIT (*d))
1610 while (ISCHARSPACE (*s))
1612 while (ISCHARSPACE (*d))
1616 /* they should be an exact match other wise */
1625 /* get rid of the trailing spaces
1626 in both source & destination */
1628 while (ISCHARSPACE (*s))
1632 while (ISCHARSPACE (*d))
1635 /* after all this if only one of them
1636 has something left over then no match */
1643 /*-----------------------------------------------------------------*/
1644 /* matchRule - matches a all the rule lines */
1645 /*-----------------------------------------------------------------*/
1647 matchRule (lineNode * pl,
1652 lineNode *spl; /* source pl */
1653 lineNode *rpl; /* rule peep line */
1655 /* setToNull((void *) &pr->vars); */
1656 /* pr->vars = newHashTable(100); */
1658 /* for all the lines defined in the rule */
1664 /* if the source line starts with a ';' then
1665 comment line don't process or the source line
1666 contains == . debugger information skip it */
1668 (*spl->line == ';' || spl->isDebug))
1674 if (!matchLine (spl->line, rpl->line, &pr->vars))
1682 /* if rules ended */
1685 /* if this rule has additional conditions */
1688 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1707 reassociate_ic_down (lineNode *shead, lineNode *stail,
1708 lineNode *rhead, lineNode *rtail)
1710 lineNode *csl; /* current source line */
1711 lineNode *crl; /* current replacement line */
1717 /* skip over any comments */
1718 while (csl!=stail->next && csl->isComment)
1720 while (crl!=rtail->next && crl->isComment)
1723 /* quit if we reach the end */
1724 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1727 if (matchLine(csl->line,crl->line,NULL))
1739 reassociate_ic_up (lineNode *shead, lineNode *stail,
1740 lineNode *rhead, lineNode *rtail)
1742 lineNode *csl; /* current source line */
1743 lineNode *crl; /* current replacement line */
1749 /* skip over any comments */
1750 while (csl!=shead->prev && csl->isComment)
1752 while (crl!=rhead->prev && crl->isComment)
1755 /* quit if we reach the end */
1756 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1759 if (matchLine(csl->line,crl->line,NULL))
1770 /*------------------------------------------------------------------*/
1771 /* reassociate_ic - reassociate replacement lines with origin iCode */
1772 /*------------------------------------------------------------------*/
1774 reassociate_ic (lineNode *shead, lineNode *stail,
1775 lineNode *rhead, lineNode *rtail)
1777 lineNode *csl; /* current source line */
1778 lineNode *crl; /* current replacement line */
1782 /* Check to see if all the source lines (excluding comments) came
1783 ** for the same iCode
1786 for (csl=shead;csl!=stail->next;csl=csl->next)
1787 if (csl->ic && !csl->isComment)
1792 single_iCode = (ic!=NULL);
1793 for (csl=shead;csl!=stail->next;csl=csl->next)
1794 if ((csl->ic != ic) && !csl->isComment)
1796 /* More than one iCode was found. However, if it's just the
1797 ** last line with the different iCode and it was not changed
1798 ** in the replacement, everything else must be the first iCode.
1800 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1802 rtail->ic = stail->ic;
1803 for (crl=rhead;crl!=rtail;crl=crl->next)
1808 single_iCode = FALSE;
1812 /* If all of the source lines came from the same iCode, then so have
1813 ** all of the replacement lines too.
1817 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1822 /* The source lines span iCodes, so we may end up with replacement
1823 ** lines that we don't know which iCode(s) to associate with. Do the
1824 ** best we can by using the following strategies:
1825 ** 1) Start at the top and scan down. As long as the source line
1826 ** matches the replacement line, they have the same iCode.
1827 ** 2) Start at the bottom and scan up. As long as the source line
1828 ** matches the replacement line, they have the same iCode.
1829 ** 3) For any label in the source, look for a matching label in
1830 ** the replacment. If found, they have the same iCode. From
1831 ** these matching labels, scan down for additional matching
1832 ** lines; if found, they also have the same iCode.
1835 /* Strategy #1: Start at the top and scan down for matches
1837 reassociate_ic_down(shead,stail,rhead,rtail);
1839 /* Strategy #2: Start at the bottom and scan up for matches
1841 reassociate_ic_up(shead,stail,rhead,rtail);
1843 /* Strategy #3: Try to match labels
1848 /* skip over any comments */
1849 while (csl!=stail->next && csl->isComment)
1851 if (csl==stail->next)
1856 /* found a source line label; look for it in the replacment lines */
1860 while (crl!=rtail->next && crl->isComment)
1862 if (crl==rtail->next)
1864 if (matchLine(csl->line, crl->line, NULL))
1866 reassociate_ic_down(csl,stail,crl,rtail);
1876 /* Try to assign a meaningful iCode to any comment that is missing
1877 one. Since they are comments, it's ok to make mistakes; we are just
1878 trying to improve continuity to simplify other tests.
1881 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1883 if (!crl->ic && ic && crl->isComment)
1890 /*-----------------------------------------------------------------*/
1891 /* replaceRule - does replacement of a matching pattern */
1892 /*-----------------------------------------------------------------*/
1894 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1896 lineNode *cl = NULL;
1897 lineNode *pl = NULL, *lhead = NULL;
1898 /* a long function name and long variable name can evaluate to
1899 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1900 char lb[MAX_PATTERN_LEN*4];
1902 lineNode *comment = NULL;
1904 /* collect all the comment lines in the source */
1905 for (cl = *shead; cl != stail; cl = cl->next)
1907 if (cl->line && (*cl->line == ';' || cl->isDebug))
1909 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1910 (comment = newLineNode (cl->line)));
1911 pl->isDebug = cl->isDebug;
1912 pl->isComment = cl->isComment || (*cl->line == ';');
1917 /* for all the lines in the replacement pattern do */
1918 for (pl = pr->replace; pl; pl = pl->next)
1928 /* if the line contains a variable */
1929 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
1931 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1934 fprintf (stderr, "used unbound variable in replacement\n");
1942 while (ISCHARDIGIT (*l)) {
1952 cl = connectLine (cl, newLineNode (lb));
1954 lhead = cl = newLineNode (lb);
1955 cl->isComment = pl->isComment;
1956 cl->isLabel = pl->isLabel;
1959 /* add the comments if any to the head of list */
1962 lineNode *lc = comment;
1973 /* determine which iCodes the replacment lines relate to */
1974 reassociate_ic(*shead,stail,lhead,cl);
1976 /* now we need to connect / replace the original chain */
1977 /* if there is a prev then change it */
1980 (*shead)->prev->next = lhead;
1981 lhead->prev = (*shead)->prev;
1984 /* now for the tail */
1985 if (stail && stail->next)
1987 stail->next->prev = cl;
1989 cl->next = stail->next;
1994 /* the replacement is empty - delete the source lines */
1996 (*shead)->prev->next = stail->next;
1998 stail->next->prev = (*shead)->prev;
1999 *shead = stail->next;
2003 /* Returns TRUE if this line is a label definition.
2005 * If so, start will point to the start of the label name,
2006 * and len will be it's length.
2009 isLabelDefinition (const char *line, const char **start, int *len,
2012 const char *cp = line;
2014 /* This line is a label if if consists of:
2015 * [optional whitespace] followed by identifier chars
2016 * (alnum | $ | _ ) followed by a colon.
2019 while (*cp && ISCHARSPACE (*cp))
2031 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2032 (isPeepRule && (*cp == '%')))
2037 if ((cp == *start) || (*cp != ':'))
2042 *len = (cp - (*start));
2046 /* Quick & dirty string hash function. */
2048 hashSymbolName (const char *name)
2054 hash = (hash << 6) ^ *name;
2063 return hash % HTAB_SIZE;
2066 /* Build a hash of all labels in the passed set of lines
2067 * and how many times they are referenced.
2070 buildLabelRefCountHash (lineNode * head)
2077 assert (labelHash == NULL);
2078 labelHash = newHashTable (HTAB_SIZE);
2080 /* First pass: locate all the labels. */
2081 for (line = head; line; line = line->next)
2083 if (line->isLabel ||
2086 /* run isLabelDefinition to:
2087 - look for labels in inline assembler
2088 - calculate labelLen
2090 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2091 labelLen <= SDCC_NAME_MAX)
2093 labelHashEntry *entry;
2095 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2097 memcpy (entry->name, label, labelLen);
2098 entry->name[labelLen] = 0;
2099 entry->refCount = -1;
2101 /* Assume function entry points are referenced somewhere, */
2102 /* even if we can't find a reference (might be from outside */
2104 if (line->ic && (line->ic->op == FUNCTION))
2107 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2113 /* Second pass: for each line, note all the referenced labels. */
2114 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2118 for (i = 0; i < HTAB_SIZE; i++)
2120 labelHashEntry *thisEntry;
2122 thisEntry = hTabFirstItemWK (labelHash, i);
2126 if (strstr (line->line, thisEntry->name))
2128 thisEntry->refCount++;
2130 thisEntry = hTabNextItemWK (labelHash);
2137 /* Spew the contents of the table. Debugging fun only. */
2138 for (i = 0; i < HTAB_SIZE; i++)
2140 labelHashEntry *thisEntry;
2142 thisEntry = hTabFirstItemWK (labelHash, i);
2146 fprintf (stderr, "label: %s ref %d\n",
2147 thisEntry->name, thisEntry->refCount);
2148 thisEntry = hTabNextItemWK (labelHash);
2154 /* How does this work?
2160 replace and restart.
2165 Where is stuff allocated?
2169 /*-----------------------------------------------------------------*/
2170 /* peepHole - matches & substitutes rules */
2171 /*-----------------------------------------------------------------*/
2173 peepHole (lineNode ** pls)
2177 lineNode *mtail = NULL;
2180 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2181 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2182 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2186 assert(labelHash == NULL);
2193 for (pr = rootRules; pr; pr = pr->next)
2195 for (spl = *pls; spl; spl = spl->next)
2197 /* if inline assembler then no peep hole */
2201 /* don't waste time starting a match on debug symbol
2203 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2208 /* Tidy up any data stored in the hTab */
2211 if (matchRule (spl, &mtail, pr, *pls))
2216 replaceRule (pls, mtail, pr);
2218 replaceRule (&spl, mtail, pr);
2220 /* if restart rule type then
2221 start at the top again */
2230 hTabDeleteAll (pr->vars);
2231 Safe_free (pr->vars);
2235 freeTrace (&_G.values);
2238 } while (restart == TRUE);
2242 hTabDeleteAll (labelHash);
2243 freeTrace (&_G.labels);
2249 /*-----------------------------------------------------------------*/
2250 /* readFileIntoBuffer - reads a file into a string buffer */
2251 /*-----------------------------------------------------------------*/
2253 readFileIntoBuffer (char *fname)
2259 char lb[MAX_PATTERN_LEN];
2261 if (!(f = fopen (fname, "r")))
2263 fprintf (stderr, "cannot open peep rule file\n");
2267 while ((ch = fgetc (f)) != EOF)
2271 /* if we maxed out our local buffer */
2272 if (nch >= (MAX_PATTERN_LEN - 2))
2275 /* copy it into allocated buffer */
2278 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2279 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2283 rs = Safe_strdup (lb);
2289 /* if some charaters left over */
2293 /* copy it into allocated buffer */
2296 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2297 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2301 rs = Safe_strdup (lb);
2307 /*-----------------------------------------------------------------*/
2308 /* initPeepHole - initialises the peep hole optimizer stuff */
2309 /*-----------------------------------------------------------------*/
2315 /* read in the default rules */
2316 if (!options.nopeep)
2318 readRules (port->peep.default_rules);
2321 /* if we have any additional file read it too */
2322 if (options.peep_file)
2324 readRules (s = readFileIntoBuffer (options.peep_file));
2325 setToNull ((void *) &s);
2326 /* override nopeep setting, default rules have not been read */
2331 #if !OPT_DISABLE_PIC
2332 /* Convert the peep rules into pcode.
2333 NOTE: this is only support in the PIC port (at the moment)
2336 peepRules2pCode(rootRules);
2339 #if !OPT_DISABLE_PIC16
2340 /* Convert the peep rules into pcode.
2341 NOTE: this is only support in the PIC port (at the moment)
2342 and the PIC16 port (VR 030601)
2344 if (TARGET_IS_PIC16)
2345 pic16_peepRules2pCode(rootRules);