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 -------------------------------------------------------------------------*/
27 #include "dbuf_string.h"
29 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
30 #define ISCHARSPACE(c) isspace((unsigned char)c)
31 #define ISCHARALNUM(c) isalnum((unsigned char)c)
33 static peepRule *rootRules = NULL;
34 static peepRule *currRule = NULL;
38 hTab *labelHash = NULL;
46 static int hashSymbolName (const char *name);
47 static void buildLabelRefCountHash (lineNode * head);
49 static bool matchLine (char *, char *, hTab **);
51 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
52 lineNode *head, char *cmdLine)
55 void peepRules2pCode(peepRule *);
58 #if !OPT_DISABLE_PIC16
59 void pic16_peepRules2pCode(peepRule *);
62 /*-----------------------------------------------------------------*/
63 /* pcDistance - afinds a label back ward or forward */
64 /*-----------------------------------------------------------------*/
67 pcDistance (lineNode * cpos, char *lbl, bool back)
70 char buff[MAX_PATTERN_LEN];
73 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
81 if (port->peep.getSize) {
82 dist += port->peep.getSize(pl);
88 if (strncmp (pl->line, buff, strlen (buff)) == 0)
100 /*-----------------------------------------------------------------*/
101 /* flat24bitModeAndPortDS390 - */
102 /*-----------------------------------------------------------------*/
103 FBYNAME (flat24bitModeAndPortDS390)
105 return (((strcmp(port->target,"ds390") == 0) ||
106 (strcmp(port->target,"ds400") == 0)) &&
107 (options.model == MODEL_FLAT24));
110 /*-----------------------------------------------------------------*/
111 /* portIsDS390 - return true if port is DS390 */
112 /*-----------------------------------------------------------------*/
113 FBYNAME (portIsDS390)
115 return ((strcmp(port->target,"ds390") == 0) ||
116 (strcmp(port->target,"ds400") == 0));
119 /*-----------------------------------------------------------------*/
120 /* flat24bitMode - will check to see if we are in flat24 mode */
121 /*-----------------------------------------------------------------*/
122 FBYNAME (flat24bitMode)
124 return (options.model == MODEL_FLAT24);
127 /*-----------------------------------------------------------------*/
128 /* xramMovcOption - check if using movc to read xram */
129 /*-----------------------------------------------------------------*/
130 FBYNAME (xramMovcOption)
132 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
140 /*-----------------------------------------------------------------*/
141 /* labelInRange - will check to see if label %5 is within range */
142 /*-----------------------------------------------------------------*/
143 FBYNAME (labelInRange)
145 /* assumes that %5 pattern variable has the label name */
146 char *lbl = hTabItemWithKey (vars, 5);
152 /* Don't optimize jumps in a jump table; a more generic test */
153 if (currPl->ic && currPl->ic->op == JUMPTABLE)
156 /* if the previous two instructions are "ljmp"s then don't
157 do it since it can be part of a jump table */
158 if (currPl->prev && currPl->prev->prev &&
159 strstr (currPl->prev->line, "ljmp") &&
160 strstr (currPl->prev->prev->line, "ljmp"))
163 /* calculate the label distance : the jump for reladdr can be
164 +/- 127 bytes, here Iam assuming that an average 8051
165 instruction is 2 bytes long, so if the label is more than
166 63 intructions away, the label is considered out of range
167 for a relative jump. we could get more precise this will
168 suffice for now since it catches > 90% cases */
169 dist = (pcDistance (currPl, lbl, TRUE) +
170 pcDistance (currPl, lbl, FALSE));
172 /* changed to 127, now that pcDistance return actual number of bytes */
173 if (!dist || dist > 127)
180 /*-----------------------------------------------------------------*/
181 /* labelJTInRange - will check to see if label %5 and up are */
183 /* Specifically meant to optimize long (3-byte) jumps to short */
184 /* (2-byte) jumps in jumptables */
185 /*-----------------------------------------------------------------*/
186 FBYNAME (labelJTInRange)
191 if (!getenv("SDCC_SJMP_JUMPTABLE"))
194 /* Only optimize within a jump table */
195 if (currPl->ic && currPl->ic->op != JUMPTABLE)
198 count = elementsInSet( IC_JTLABELS (currPl->ic) );
200 /* check all labels (this is needed if the case statements are unsorted) */
201 for (i=0; i<count; i++)
203 /* assumes that the %5 pattern variable has the first ljmp label */
204 lbl = hTabItemWithKey (vars, 5+i);
208 dist = pcDistance (currPl, lbl, FALSE);
210 /* three terms used to calculate allowable distance */
211 // 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);
213 dist > 127+ /* range of sjmp */
214 (7+3*i)+ /* offset between this jump and currPl,
215 should use pcDistance instead? */
216 (count-i-1) /* if peephole applies distance is shortened */
224 /*-----------------------------------------------------------------*/
225 /* labelIsReturnOnly - Check if label %5 is followed by RET */
226 /*-----------------------------------------------------------------*/
227 FBYNAME (labelIsReturnOnly)
229 /* assumes that %5 pattern variable has the label name */
230 const char *label, *p;
235 /* Don't optimize jumps in a jump table; a more generic test */
236 if (currPl->ic && currPl->ic->op == JUMPTABLE)
239 label = hTabItemWithKey (vars, 5);
240 if (!label) return FALSE;
243 for(pl = currPl; pl; pl = pl->next) {
244 if (pl->line && !pl->isDebug && !pl->isComment &&
246 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
247 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
248 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
249 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
250 *(pl->line+5) != '$') {
251 return FALSE; /* non-local label encountered */
255 if (!pl) return FALSE; /* did not find the label */
257 while (pl && (pl->isDebug || pl->isComment))
259 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
261 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
267 if (strcmp(p, retInst) == 0) return TRUE;
272 /*-----------------------------------------------------------------*/
273 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
274 /* usage of it in the code depends on a value from this section */
275 /*-----------------------------------------------------------------*/
276 FBYNAME (okToRemoveSLOC)
279 const char *sloc, *p;
280 int dummy1, dummy2, dummy3;
282 /* assumes that %1 as the SLOC name */
283 sloc = hTabItemWithKey (vars, 1);
284 if (sloc == NULL) return FALSE;
285 p = strstr(sloc, "sloc");
286 if (p == NULL) return FALSE;
288 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
289 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
290 /* the sloc name begins with that. Probably not really necessary */
292 /* Look for any occurance of this SLOC before the peephole match */
293 for (pl = currPl->prev; pl; pl = pl->prev) {
294 if (pl->line && !pl->isDebug && !pl->isComment
295 && *pl->line != ';' && strstr(pl->line, sloc))
298 /* Look for any occurance of this SLOC after the peephole match */
299 for (pl = endPl->next; pl; pl = pl->next) {
300 if (pl->line && !pl->isDebug && !pl->isComment
301 && *pl->line != ';' && strstr(pl->line, sloc))
304 return TRUE; /* safe for a peephole to remove it :) */
307 /*-----------------------------------------------------------------*/
308 /* deadMove - Check, if a pop/push pair can be removed */
309 /*-----------------------------------------------------------------*/
312 const char *reg = hTabItemWithKey (vars, 1);
314 if (port->peep.deadMove)
315 return port->peep.deadMove (reg, currPl, head);
317 fprintf (stderr, "Function deadMove not initialized in port structure\n");
321 /*-----------------------------------------------------------------*/
322 /* operandsNotSame - check if %1 & %2 are the same */
323 /*-----------------------------------------------------------------*/
324 FBYNAME (operandsNotSame)
326 char *op1 = hTabItemWithKey (vars, 1);
327 char *op2 = hTabItemWithKey (vars, 2);
329 if (strcmp (op1, op2) == 0)
335 /*-----------------------------------------------------------------*/
336 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
337 /*-----------------------------------------------------------------*/
338 FBYNAME (operandsNotSame3)
340 char *op1 = hTabItemWithKey (vars, 1);
341 char *op2 = hTabItemWithKey (vars, 2);
342 char *op3 = hTabItemWithKey (vars, 3);
344 if ( (strcmp (op1, op2) == 0) ||
345 (strcmp (op1, op3) == 0) ||
346 (strcmp (op2, op3) == 0) )
352 /*-----------------------------------------------------------------*/
353 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
354 /*-----------------------------------------------------------------*/
355 FBYNAME (operandsNotSame4)
357 char *op1 = hTabItemWithKey (vars, 1);
358 char *op2 = hTabItemWithKey (vars, 2);
359 char *op3 = hTabItemWithKey (vars, 3);
360 char *op4 = hTabItemWithKey (vars, 4);
362 if ( (strcmp (op1, op2) == 0) ||
363 (strcmp (op1, op3) == 0) ||
364 (strcmp (op1, op4) == 0) ||
365 (strcmp (op2, op3) == 0) ||
366 (strcmp (op2, op4) == 0) ||
367 (strcmp (op3, op4) == 0) )
373 /*-----------------------------------------------------------------*/
374 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
375 /*-----------------------------------------------------------------*/
376 FBYNAME (operandsNotSame5)
378 char *op1 = hTabItemWithKey (vars, 1);
379 char *op2 = hTabItemWithKey (vars, 2);
380 char *op3 = hTabItemWithKey (vars, 3);
381 char *op4 = hTabItemWithKey (vars, 4);
382 char *op5 = hTabItemWithKey (vars, 5);
384 if ( (strcmp (op1, op2) == 0) ||
385 (strcmp (op1, op3) == 0) ||
386 (strcmp (op1, op4) == 0) ||
387 (strcmp (op1, op5) == 0) ||
388 (strcmp (op2, op3) == 0) ||
389 (strcmp (op2, op4) == 0) ||
390 (strcmp (op2, op5) == 0) ||
391 (strcmp (op3, op4) == 0) ||
392 (strcmp (op3, op5) == 0) ||
393 (strcmp (op4, op5) == 0) )
399 /*-----------------------------------------------------------------*/
400 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
401 /*-----------------------------------------------------------------*/
402 FBYNAME (operandsNotSame6)
404 char *op1 = hTabItemWithKey (vars, 1);
405 char *op2 = hTabItemWithKey (vars, 2);
406 char *op3 = hTabItemWithKey (vars, 3);
407 char *op4 = hTabItemWithKey (vars, 4);
408 char *op5 = hTabItemWithKey (vars, 5);
409 char *op6 = hTabItemWithKey (vars, 6);
411 if ( (strcmp (op1, op2) == 0) ||
412 (strcmp (op1, op3) == 0) ||
413 (strcmp (op1, op4) == 0) ||
414 (strcmp (op1, op5) == 0) ||
415 (strcmp (op1, op6) == 0) ||
416 (strcmp (op2, op3) == 0) ||
417 (strcmp (op2, op4) == 0) ||
418 (strcmp (op2, op5) == 0) ||
419 (strcmp (op2, op6) == 0) ||
420 (strcmp (op3, op4) == 0) ||
421 (strcmp (op3, op5) == 0) ||
422 (strcmp (op3, op6) == 0) ||
423 (strcmp (op4, op5) == 0) ||
424 (strcmp (op4, op6) == 0) ||
425 (strcmp (op5, op6) == 0) )
432 /*-----------------------------------------------------------------*/
433 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
434 /*-----------------------------------------------------------------*/
435 FBYNAME (operandsNotSame7)
437 char *op1 = hTabItemWithKey (vars, 1);
438 char *op2 = hTabItemWithKey (vars, 2);
439 char *op3 = hTabItemWithKey (vars, 3);
440 char *op4 = hTabItemWithKey (vars, 4);
441 char *op5 = hTabItemWithKey (vars, 5);
442 char *op6 = hTabItemWithKey (vars, 6);
443 char *op7 = hTabItemWithKey (vars, 7);
445 if ( (strcmp (op1, op2) == 0) ||
446 (strcmp (op1, op3) == 0) ||
447 (strcmp (op1, op4) == 0) ||
448 (strcmp (op1, op5) == 0) ||
449 (strcmp (op1, op6) == 0) ||
450 (strcmp (op1, op7) == 0) ||
451 (strcmp (op2, op3) == 0) ||
452 (strcmp (op2, op4) == 0) ||
453 (strcmp (op2, op5) == 0) ||
454 (strcmp (op2, op6) == 0) ||
455 (strcmp (op2, op7) == 0) ||
456 (strcmp (op3, op4) == 0) ||
457 (strcmp (op3, op5) == 0) ||
458 (strcmp (op3, op6) == 0) ||
459 (strcmp (op3, op7) == 0) ||
460 (strcmp (op4, op5) == 0) ||
461 (strcmp (op4, op6) == 0) ||
462 (strcmp (op4, op7) == 0) ||
463 (strcmp (op5, op6) == 0) ||
464 (strcmp (op5, op7) == 0) ||
465 (strcmp (op6, op7) == 0) )
471 /*-----------------------------------------------------------------*/
472 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
473 /*-----------------------------------------------------------------*/
474 FBYNAME (operandsNotSame8)
476 char *op1 = hTabItemWithKey (vars, 1);
477 char *op2 = hTabItemWithKey (vars, 2);
478 char *op3 = hTabItemWithKey (vars, 3);
479 char *op4 = hTabItemWithKey (vars, 4);
480 char *op5 = hTabItemWithKey (vars, 5);
481 char *op6 = hTabItemWithKey (vars, 6);
482 char *op7 = hTabItemWithKey (vars, 7);
483 char *op8 = hTabItemWithKey (vars, 8);
485 if ( (strcmp (op1, op2) == 0) ||
486 (strcmp (op1, op3) == 0) ||
487 (strcmp (op1, op4) == 0) ||
488 (strcmp (op1, op5) == 0) ||
489 (strcmp (op1, op6) == 0) ||
490 (strcmp (op1, op7) == 0) ||
491 (strcmp (op1, op8) == 0) ||
492 (strcmp (op2, op3) == 0) ||
493 (strcmp (op2, op4) == 0) ||
494 (strcmp (op2, op5) == 0) ||
495 (strcmp (op2, op6) == 0) ||
496 (strcmp (op2, op7) == 0) ||
497 (strcmp (op2, op8) == 0) ||
498 (strcmp (op3, op4) == 0) ||
499 (strcmp (op3, op5) == 0) ||
500 (strcmp (op3, op6) == 0) ||
501 (strcmp (op3, op7) == 0) ||
502 (strcmp (op3, op8) == 0) ||
503 (strcmp (op4, op5) == 0) ||
504 (strcmp (op4, op6) == 0) ||
505 (strcmp (op4, op7) == 0) ||
506 (strcmp (op4, op8) == 0) ||
507 (strcmp (op5, op6) == 0) ||
508 (strcmp (op5, op7) == 0) ||
509 (strcmp (op5, op8) == 0) ||
510 (strcmp (op6, op7) == 0) ||
511 (strcmp (op6, op8) == 0) ||
512 (strcmp (op7, op8) == 0) )
518 /*-----------------------------------------------------------------*/
519 /* labelHashEntry- searches for a label in the list labelHash */
520 /* Builds labelHash, if it does not yet exist. */
521 /* Returns the labelHashEntry or NULL */
522 /*-----------------------------------------------------------------*/
524 getLabelRef (const char *label, lineNode *head)
526 labelHashEntry *entry;
528 /* If we don't have the label hash table yet, build it. */
531 buildLabelRefCountHash (head);
534 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
538 if (!strcmp (label, entry->name))
542 entry = hTabNextItemWK (labelHash);
549 * takes two parameters: a variable (bound to a label name)
550 * and an expected reference count.
552 * Returns TRUE if that label is defined and referenced exactly
553 * the given number of times.
555 FBYNAME (labelRefCount)
557 int varNumber, expectedRefCount;
560 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
562 char *label = hTabItemWithKey (vars, varNumber);
566 labelHashEntry *entry = getLabelRef (label, head);
572 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
573 label, entry->refCount, expectedRefCount);
576 rc = (expectedRefCount == entry->refCount);
580 fprintf (stderr, "*** internal error: no label has entry for"
581 " %s in labelRefCount peephole.\n",
587 fprintf (stderr, "*** internal error: var %d not bound"
588 " in peephole labelRefCount rule.\n",
596 "*** internal error: labelRefCount peephole restriction"
597 " malformed: %s\n", cmdLine);
603 /* labelRefCountChange:
604 * takes two parameters: a variable (bound to a label name)
605 * and a signed int for changing the reference count.
607 * Please note, this function is not a conditional. It unconditionally
608 * changes the label. It should be passed as the 'last' function
609 * so it only is applied if all other conditions have been met.
611 * should always return TRUE
613 FBYNAME (labelRefCountChange)
615 int varNumber, RefCountDelta;
618 /* If we don't have the label hash table yet, build it. */
621 buildLabelRefCountHash (head);
624 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
626 char *label = hTabItemWithKey (vars, varNumber);
630 labelHashEntry *entry;
632 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
636 if (!strcmp (label, entry->name))
640 entry = hTabNextItemWK (labelHash);
644 if (0 <= entry->refCount + RefCountDelta)
646 entry->refCount += RefCountDelta;
651 fprintf (stderr, "*** internal error: label %s may not get"
652 " negative refCount in %s peephole.\n",
653 label, __FUNCTION__);
658 fprintf (stderr, "*** internal error: no label has entry for"
659 " %s in %s peephole.\n",
660 label, __FUNCTION__);
665 fprintf (stderr, "*** internal error: var %d not bound"
666 " in peephole %s rule.\n",
667 varNumber, __FUNCTION__);
673 "*** internal error: labelRefCount peephole restriction"
674 " malformed: %s\n", cmdLine);
680 /* Within the context of the lines currPl through endPl, determine
681 ** if the variable var contains a symbol that is volatile. Returns
682 ** TRUE only if it is certain that this was not volatile (the symbol
683 ** was found and not volatile, or var was a constant or CPU register).
684 ** Returns FALSE if the symbol was found and volatile, the symbol was
685 ** not found, or var was a indirect/pointer addressing mode.
688 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
690 char symname[SDCC_NAME_MAX + 1];
697 /* Can't tell if indirect accesses are volatile or not, so
698 ** assume they are, just to be safe.
700 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
705 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
707 if (strstr(var,"(bc)"))
709 if (strstr(var,"(de)"))
711 if (strstr(var,"(hl)"))
713 if (strstr(var,"(ix"))
715 if (strstr(var,"(iy"))
719 /* Extract a symbol name from the variable */
720 while (*vp && (*vp!='_'))
722 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
728 /* Nothing resembling a symbol name was found, so it can't
735 for (cl = currPl; cl!=endPl->next; cl = cl->next)
737 if (cl->ic && (cl->ic!=last_ic))
743 op = IC_COND (cl->ic);
744 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
745 return !op->isvolatile;
747 op = IC_JTCOND (cl->ic);
748 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
749 return !op->isvolatile;
751 op = IC_LEFT (cl->ic);
752 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
753 return !op->isvolatile;
754 op = IC_RIGHT (cl->ic);
755 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
756 return !op->isvolatile;
757 op = IC_RESULT (cl->ic);
758 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
759 return !op->isvolatile;
764 /* Couldn't find the symbol for some reason. Assume volatile. */
770 * This rule restriction has two different behaviours depending on
771 * the number of parameters given.
773 * if notVolatile (no parameters given)
774 * The rule is applied only if none of the iCodes originating
775 * the matched pattern reference a volatile operand.
777 * if notVolatile %1 ... (one or more parameters given)
778 * The rule is applied if the parameters are not expressions
779 * containing volatile symbols and are not pointer accesses.
782 FBYNAME (notVolatile)
793 /* If no parameters given, just scan the iCodes for volatile operands */
794 for (cl = currPl; cl!=endPl->next; cl = cl->next)
801 op = IC_COND (cl->ic);
802 if (IS_SYMOP (op) && op->isvolatile)
805 op = IC_JTCOND (cl->ic);
806 if (IS_SYMOP (op) && op->isvolatile)
809 op = IC_LEFT (cl->ic);
810 if (IS_SYMOP (op) && op->isvolatile)
812 op = IC_RIGHT (cl->ic);
813 if (IS_SYMOP (op) && op->isvolatile)
815 op = IC_RESULT (cl->ic);
816 if (IS_SYMOP (op) && op->isvolatile)
824 /* There were parameters; check the volatility of each */
825 while (*cmdLine && ISCHARSPACE(*cmdLine))
832 if (!ISCHARDIGIT(*cmdLine))
834 varNumber = strtol(cmdLine, &digitend, 10);
836 while (*cmdLine && ISCHARSPACE(*cmdLine))
839 var = hTabItemWithKey (vars, varNumber);
843 notvol = notVolatileVariable (var, currPl, endPl);
849 fprintf (stderr, "*** internal error: var %d not bound"
850 " in peephole notVolatile rule.\n",
861 "*** internal error: notVolatile peephole restriction"
862 " malformed: %s\n", cmdLine);
867 /*------------------------------------------------------------------*/
868 /* setFromConditionArgs - parse a peephole condition's arguments */
869 /* to produce a set of strings, one per argument. Variables %x will */
870 /* be replaced with their values. String literals (in single quotes)*/
871 /* are accepted and return in unquoted form. */
872 /*------------------------------------------------------------------*/
874 setFromConditionArgs (char *cmdLine, hTab * vars)
879 set *operands = NULL;
884 while (*cmdLine && ISCHARSPACE(*cmdLine))
892 if (!ISCHARDIGIT(*cmdLine))
894 varNumber = strtol(cmdLine, &digitend, 10);
897 var = hTabItemWithKey (vars, varNumber);
901 addSetHead (&operands, var);
906 else if (*cmdLine == '\'' )
908 char quote = *cmdLine;
911 while (*cmdLine && *cmdLine != quote)
913 if (*cmdLine == quote)
917 addSetHead (&operands, var);
922 while (*cmdLine && ISCHARSPACE(*cmdLine))
929 deleteSet (&operands);
934 operandBaseName (const char *op)
936 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
938 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
940 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
948 /*-------------------------------------------------------------------*/
949 /* operandsNotRelated - returns true of the condition's operands are */
950 /* not related (taking into account register name aliases). N-way */
951 /* comparison performed between all operands. */
952 /*-------------------------------------------------------------------*/
953 FBYNAME (operandsNotRelated)
956 const char *op1, *op2;
958 operands = setFromConditionArgs (cmdLine, vars);
963 "*** internal error: operandsNotRelated peephole restriction"
964 " malformed: %s\n", cmdLine);
968 while ((op1 = setFirstItem (operands)))
970 deleteSetItem (&operands, (void*)op1);
971 op1 = operandBaseName (op1);
973 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
975 op2 = operandBaseName (op2);
976 if (strcmp (op1, op2) == 0)
978 deleteSet (&operands);
984 deleteSet (&operands);
989 /*-------------------------------------------------------------------*/
990 /* operandsLiteral - returns true of the condition's operands are */
992 /*-------------------------------------------------------------------*/
993 FBYNAME (operandsLiteral)
998 operands = setFromConditionArgs (cmdLine, vars);
1003 "*** internal error: operandsLiteral peephole restriction"
1004 " malformed: %s\n", cmdLine);
1008 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1012 deleteSet (&operands);
1017 deleteSet (&operands);
1022 /*-----------------------------------------------------------------*/
1023 /* callFuncByName - calls a function as defined in the table */
1024 /*-----------------------------------------------------------------*/
1026 callFuncByName (char *fname,
1035 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1040 "labelInRange", labelInRange
1044 "labelJTInRange", labelJTInRange
1048 "operandsNotSame", operandsNotSame
1052 "operandsNotSame3", operandsNotSame3
1056 "operandsNotSame4", operandsNotSame4
1060 "operandsNotSame5", operandsNotSame5
1064 "operandsNotSame6", operandsNotSame6
1068 "operandsNotSame7", operandsNotSame7
1072 "operandsNotSame8", operandsNotSame8
1076 "24bitMode", flat24bitMode
1080 "xramMovcOption", xramMovcOption
1084 "labelRefCount", labelRefCount
1088 "portIsDS390", portIsDS390
1091 "labelIsReturnOnly", labelIsReturnOnly
1094 "okToRemoveSLOC", okToRemoveSLOC
1097 "deadMove", deadMove
1100 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1103 "notVolatile", notVolatile
1106 "operandsNotRelated", operandsNotRelated
1109 "operandsLiteral", operandsLiteral
1112 "labelRefCountChange", labelRefCountChange
1116 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1120 /* Isolate the function name part (we are passed the full condition
1121 * string including arguments)
1123 cmdTerm = cmdCopy = Safe_strdup(fname);
1127 funcArgs = funcName = cmdTerm;
1128 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1130 *funcArgs = '\0'; /* terminate the function name */
1134 /* Find the start of the arguments */
1135 if (c == ' ' || c == '\t')
1136 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1139 /* If the arguments started with an opening parenthesis, */
1140 /* use the closing parenthesis for the end of the */
1141 /* arguments and look for the start of another condition */
1142 /* that can optionally follow. If there was no opening */
1143 /* parethesis, then everything that follows are arguments */
1144 /* and there can be no additional conditions. */
1148 while ((c = *cmdTerm) && c != ')')
1150 *cmdTerm = '\0'; /* terminate the arguments */
1154 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1160 cmdTerm = NULL; /* closing parenthesis missing */
1169 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1171 if (strcmp (ftab[i].fname, funcName) == 0)
1173 rc = (*ftab[i].func) (vars, currPl, endPl, head,
1182 "could not find named function \"%s\" in "
1183 "peephole function table\n",
1185 // If the function couldn't be found, let's assume it's
1186 // a bad rule and refuse it.
1191 while (rc && cmdTerm);
1198 /*-----------------------------------------------------------------*/
1199 /* printLine - prints a line chain into a given file */
1200 /*-----------------------------------------------------------------*/
1202 printLine (lineNode * head, struct dbuf_s * oBuf)
1204 iCode *last_ic = NULL;
1205 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1209 if (head->ic!=last_ic)
1212 if (debug_iCode_tracking)
1215 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1216 head->ic->block, head->ic->seq);
1218 dbuf_append_str (oBuf, "; iCode lost\n");
1222 /* don't indent comments & labels */
1224 (head->isComment || head->isLabel)) {
1225 dbuf_printf (oBuf, "%s\n", head->line);
1227 if (head->isInline && *head->line=='#') {
1228 // comment out preprocessor directives in inline asm
1229 dbuf_append_char (oBuf, ';');
1231 dbuf_printf (oBuf, "\t%s\n", head->line);
1237 /*-----------------------------------------------------------------*/
1238 /* newPeepRule - creates a new peeprule and attach it to the root */
1239 /*-----------------------------------------------------------------*/
1241 newPeepRule (lineNode * match,
1248 pr = Safe_alloc ( sizeof (peepRule));
1250 pr->replace = replace;
1251 pr->restart = restart;
1255 pr->cond = Safe_strdup (cond);
1260 pr->vars = newHashTable (100);
1262 /* if root is empty */
1264 rootRules = currRule = pr;
1266 currRule = currRule->next = pr;
1271 /*-----------------------------------------------------------------*/
1272 /* newLineNode - creates a new peep line */
1273 /*-----------------------------------------------------------------*/
1275 newLineNode (const char *line)
1279 pl = Safe_alloc ( sizeof (lineNode));
1280 pl->line = Safe_strdup (line);
1285 /*-----------------------------------------------------------------*/
1286 /* connectLine - connects two lines */
1287 /*-----------------------------------------------------------------*/
1289 connectLine (lineNode * pl1, lineNode * pl2)
1293 fprintf (stderr, "trying to connect null line\n");
1303 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1304 if (!*x) { fprintf(stderr,y); return ; } }
1306 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1307 if (!*x) { fprintf(stderr,z); return ; } }
1308 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1309 if (!*x) { fprintf(stderr,z); return ; } }
1311 /*-----------------------------------------------------------------*/
1312 /* getPeepLine - parses the peep lines */
1313 /*-----------------------------------------------------------------*/
1315 getPeepLine (lineNode ** head, char **bpp)
1317 char lines[MAX_PATTERN_LEN];
1321 lineNode *currL = NULL;
1328 fprintf (stderr, "unexpected end of match pattern\n");
1335 while (ISCHARSPACE (*bp) ||
1346 /* read till end of line */
1348 while ((*bp != '\n' && *bp != '}') && *bp)
1353 while (*lp && ISCHARSPACE(*lp))
1355 isComment = (*lp == ';');
1357 if (!isComment || (isComment && !options.noPeepComments))
1363 *head = currL = newLineNode (lines);
1365 currL = connectLine (currL, newLineNode (lines));
1366 currL->isComment = isComment;
1367 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1376 /*-----------------------------------------------------------------*/
1377 /* readRules - reads the rules from a string buffer */
1378 /*-----------------------------------------------------------------*/
1380 readRules (char *bp)
1383 char lines[MAX_PATTERN_LEN];
1387 lineNode *currL = NULL;
1393 /* look for the token "replace" that is the
1395 while (*bp && strncmp (bp, "replace", 7))
1402 /* then look for either "restart" or '{' */
1403 while (strncmp (bp, "restart", 7) &&
1410 fprintf (stderr, "expected 'restart' or '{'\n");
1418 { /* must be restart */
1420 bp += strlen ("restart");
1422 EXPECT_CHR (bp, '{', "expected '{'\n");
1426 /* skip thru all the blank space */
1427 SKIP_SPACE (bp, "unexpected end of rule\n");
1429 match = replace = currL = NULL;
1430 /* we are the start of a rule */
1431 getPeepLine (&match, &bp);
1433 /* now look for by */
1434 EXPECT_STR (bp, "by", "expected 'by'\n");
1436 /* then look for a '{' */
1437 EXPECT_CHR (bp, '{', "expected '{'\n");
1440 /* save char position (needed for generating error msg) */
1443 SKIP_SPACE (bp, "unexpected end of rule\n");
1444 getPeepLine (&replace, &bp);
1446 /* look for a 'if' */
1447 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1450 if (strncmp (bp, "if", 2) == 0)
1453 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1457 fprintf (stderr, "expected condition name\n");
1461 /* look for the condition */
1463 while (*bp && (*bp != '\n'))
1469 newPeepRule (match, replace, lines, restart);
1473 if (*bp && strncmp (bp, "replace", 7))
1475 /* not the start of a new peeprule, so "if" should be here */
1480 /* go to the start of the line following "{" of the "by" token */
1481 while (*rp && (*rp == '\n'))
1484 /* copy text of rule starting with line after "by {" */
1486 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1489 /* and now the rest of the line */
1490 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1494 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1497 newPeepRule (match, replace, NULL, restart);
1503 /*-----------------------------------------------------------------*/
1504 /* keyForVar - returns the numeric key for a var */
1505 /*-----------------------------------------------------------------*/
1511 while (ISCHARDIGIT (*d))
1520 /*-----------------------------------------------------------------*/
1521 /* bindVar - binds a value to a variable in the given hashtable */
1522 /*-----------------------------------------------------------------*/
1524 bindVar (int key, char **s, hTab ** vtab)
1526 char vval[MAX_PATTERN_LEN];
1530 /* first get the value of the variable */
1532 /* the value is ended by a ',' or space or newline or null or ) */
1535 !ISCHARSPACE (*vvx) &&
1541 /* if we find a '(' then we need to balance it */
1553 // include the trailing ')'
1562 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1564 hTabAddItem (vtab, key, vvx);
1567 /*-----------------------------------------------------------------*/
1568 /* matchLine - matches one line */
1569 /*-----------------------------------------------------------------*/
1571 matchLine (char *s, char *d, hTab ** vars)
1580 /* skip white space in both */
1581 while (ISCHARSPACE (*s))
1583 while (ISCHARSPACE (*d))
1586 /* if the destination is a var */
1587 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1589 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1590 /* if the variable is already bound
1591 then it MUST match with dest */
1599 /* variable not bound we need to
1601 bindVar (keyForVar (d + 1), &s, vars);
1603 /* in either case go past the variable */
1605 while (ISCHARDIGIT (*d))
1608 while (ISCHARSPACE (*s))
1610 while (ISCHARSPACE (*d))
1614 /* they should be an exact match other wise */
1623 /* get rid of the trailing spaces
1624 in both source & destination */
1626 while (ISCHARSPACE (*s))
1630 while (ISCHARSPACE (*d))
1633 /* after all this if only one of them
1634 has something left over then no match */
1641 /*-----------------------------------------------------------------*/
1642 /* matchRule - matches a all the rule lines */
1643 /*-----------------------------------------------------------------*/
1645 matchRule (lineNode * pl,
1650 lineNode *spl; /* source pl */
1651 lineNode *rpl; /* rule peep line */
1653 /* setToNull((void *) &pr->vars); */
1654 /* pr->vars = newHashTable(100); */
1656 /* for all the lines defined in the rule */
1662 /* if the source line starts with a ';' then
1663 comment line don't process or the source line
1664 contains == . debugger information skip it */
1666 (*spl->line == ';' || spl->isDebug))
1672 if (!matchLine (spl->line, rpl->line, &pr->vars))
1680 /* if rules ended */
1683 /* if this rule has additional conditions */
1686 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1705 reassociate_ic_down (lineNode *shead, lineNode *stail,
1706 lineNode *rhead, lineNode *rtail)
1708 lineNode *csl; /* current source line */
1709 lineNode *crl; /* current replacement line */
1715 /* skip over any comments */
1716 while (csl!=stail->next && csl->isComment)
1718 while (crl!=rtail->next && crl->isComment)
1721 /* quit if we reach the end */
1722 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1725 if (matchLine(csl->line,crl->line,NULL))
1737 reassociate_ic_up (lineNode *shead, lineNode *stail,
1738 lineNode *rhead, lineNode *rtail)
1740 lineNode *csl; /* current source line */
1741 lineNode *crl; /* current replacement line */
1747 /* skip over any comments */
1748 while (csl!=shead->prev && csl->isComment)
1750 while (crl!=rhead->prev && crl->isComment)
1753 /* quit if we reach the end */
1754 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1757 if (matchLine(csl->line,crl->line,NULL))
1768 /*------------------------------------------------------------------*/
1769 /* reassociate_ic - reassociate replacement lines with origin iCode */
1770 /*------------------------------------------------------------------*/
1772 reassociate_ic (lineNode *shead, lineNode *stail,
1773 lineNode *rhead, lineNode *rtail)
1775 lineNode *csl; /* current source line */
1776 lineNode *crl; /* current replacement line */
1780 /* Check to see if all the source lines (excluding comments) came
1781 ** for the same iCode
1784 for (csl=shead;csl!=stail->next;csl=csl->next)
1785 if (csl->ic && !csl->isComment)
1790 single_iCode = (ic!=NULL);
1791 for (csl=shead;csl!=stail->next;csl=csl->next)
1792 if ((csl->ic != ic) && !csl->isComment)
1794 /* More than one iCode was found. However, if it's just the
1795 ** last line with the different iCode and it was not changed
1796 ** in the replacement, everything else must be the first iCode.
1798 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1800 rtail->ic = stail->ic;
1801 for (crl=rhead;crl!=rtail;crl=crl->next)
1806 single_iCode = FALSE;
1810 /* If all of the source lines came from the same iCode, then so have
1811 ** all of the replacement lines too.
1815 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1820 /* The source lines span iCodes, so we may end up with replacement
1821 ** lines that we don't know which iCode(s) to associate with. Do the
1822 ** best we can by using the following strategies:
1823 ** 1) Start at the top and scan down. As long as the source line
1824 ** matches the replacement line, they have the same iCode.
1825 ** 2) Start at the bottom and scan up. As long as the source line
1826 ** matches the replacement line, they have the same iCode.
1827 ** 3) For any label in the source, look for a matching label in
1828 ** the replacment. If found, they have the same iCode. From
1829 ** these matching labels, scan down for additional matching
1830 ** lines; if found, they also have the same iCode.
1833 /* Strategy #1: Start at the top and scan down for matches
1835 reassociate_ic_down(shead,stail,rhead,rtail);
1837 /* Strategy #2: Start at the bottom and scan up for matches
1839 reassociate_ic_up(shead,stail,rhead,rtail);
1841 /* Strategy #3: Try to match labels
1846 /* skip over any comments */
1847 while (csl!=stail->next && csl->isComment)
1849 if (csl==stail->next)
1854 /* found a source line label; look for it in the replacment lines */
1858 while (crl!=rtail->next && crl->isComment)
1860 if (crl==rtail->next)
1862 if (matchLine(csl->line, crl->line, NULL))
1864 reassociate_ic_down(csl,stail,crl,rtail);
1874 /* Try to assign a meaningful iCode to any comment that is missing
1875 one. Since they are comments, it's ok to make mistakes; we are just
1876 trying to improve continuity to simplify other tests.
1879 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1881 if (!crl->ic && ic && crl->isComment)
1888 /*-----------------------------------------------------------------*/
1889 /* replaceRule - does replacement of a matching pattern */
1890 /*-----------------------------------------------------------------*/
1892 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1894 lineNode *cl = NULL;
1895 lineNode *pl = NULL, *lhead = NULL;
1896 /* a long function name and long variable name can evaluate to
1897 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1898 char lb[MAX_PATTERN_LEN*4];
1900 lineNode *comment = NULL;
1902 /* collect all the comment lines in the source */
1903 for (cl = *shead; cl != stail; cl = cl->next)
1905 if (cl->line && (*cl->line == ';' || cl->isDebug))
1907 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1908 (comment = newLineNode (cl->line)));
1909 pl->isDebug = cl->isDebug;
1910 pl->isComment = cl->isComment || (*cl->line == ';');
1915 /* for all the lines in the replacement pattern do */
1916 for (pl = pr->replace; pl; pl = pl->next)
1926 /* if the line contains a variable */
1927 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
1929 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1932 fprintf (stderr, "used unbound variable in replacement\n");
1940 while (ISCHARDIGIT (*l)) {
1950 cl = connectLine (cl, newLineNode (lb));
1952 lhead = cl = newLineNode (lb);
1953 cl->isComment = pl->isComment;
1954 cl->isLabel = pl->isLabel;
1957 /* add the comments if any to the head of list */
1960 lineNode *lc = comment;
1971 /* determine which iCodes the replacment lines relate to */
1972 reassociate_ic(*shead,stail,lhead,cl);
1974 /* now we need to connect / replace the original chain */
1975 /* if there is a prev then change it */
1978 (*shead)->prev->next = lhead;
1979 lhead->prev = (*shead)->prev;
1982 /* now for the tail */
1983 if (stail && stail->next)
1985 stail->next->prev = cl;
1987 cl->next = stail->next;
1992 /* the replacement is empty - delete the source lines */
1994 (*shead)->prev->next = stail->next;
1996 stail->next->prev = (*shead)->prev;
1997 *shead = stail->next;
2001 /* Returns TRUE if this line is a label definition.
2003 * If so, start will point to the start of the label name,
2004 * and len will be it's length.
2007 isLabelDefinition (const char *line, const char **start, int *len,
2010 const char *cp = line;
2012 /* This line is a label if if consists of:
2013 * [optional whitespace] followed by identifier chars
2014 * (alnum | $ | _ ) followed by a colon.
2017 while (*cp && ISCHARSPACE (*cp))
2029 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2030 (isPeepRule && (*cp == '%')))
2035 if ((cp == *start) || (*cp != ':'))
2040 *len = (cp - (*start));
2044 /* Quick & dirty string hash function. */
2046 hashSymbolName (const char *name)
2052 hash = (hash << 6) ^ *name;
2061 return hash % HTAB_SIZE;
2064 /* Build a hash of all labels in the passed set of lines
2065 * and how many times they are referenced.
2068 buildLabelRefCountHash (lineNode * head)
2075 assert (labelHash == NULL);
2076 labelHash = newHashTable (HTAB_SIZE);
2078 /* First pass: locate all the labels. */
2079 for (line = head; line; line = line->next)
2081 if (line->isLabel ||
2084 /* run isLabelDefinition to:
2085 - look for labels in inline assembler
2086 - calculate labelLen
2088 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2089 labelLen <= SDCC_NAME_MAX)
2091 labelHashEntry *entry;
2093 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2095 memcpy (entry->name, label, labelLen);
2096 entry->name[labelLen] = 0;
2097 entry->refCount = -1;
2099 /* Assume function entry points are referenced somewhere, */
2100 /* even if we can't find a reference (might be from outside */
2102 if (line->ic && (line->ic->op == FUNCTION))
2105 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2111 /* Second pass: for each line, note all the referenced labels. */
2112 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2116 for (i = 0; i < HTAB_SIZE; i++)
2118 labelHashEntry *thisEntry;
2120 thisEntry = hTabFirstItemWK (labelHash, i);
2124 if (strstr (line->line, thisEntry->name))
2126 thisEntry->refCount++;
2128 thisEntry = hTabNextItemWK (labelHash);
2135 /* Spew the contents of the table. Debugging fun only. */
2136 for (i = 0; i < HTAB_SIZE; i++)
2138 labelHashEntry *thisEntry;
2140 thisEntry = hTabFirstItemWK (labelHash, i);
2144 fprintf (stderr, "label: %s ref %d\n",
2145 thisEntry->name, thisEntry->refCount);
2146 thisEntry = hTabNextItemWK (labelHash);
2152 /* How does this work?
2158 replace and restart.
2163 Where is stuff allocated?
2167 /*-----------------------------------------------------------------*/
2168 /* peepHole - matches & substitutes rules */
2169 /*-----------------------------------------------------------------*/
2171 peepHole (lineNode ** pls)
2175 lineNode *mtail = NULL;
2178 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2179 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2180 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2184 assert(labelHash == NULL);
2191 for (pr = rootRules; pr; pr = pr->next)
2193 for (spl = *pls; spl; spl = spl->next)
2195 /* if inline assembler then no peep hole */
2199 /* don't waste time starting a match on debug symbol
2201 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2206 /* Tidy up any data stored in the hTab */
2209 if (matchRule (spl, &mtail, pr, *pls))
2214 replaceRule (pls, mtail, pr);
2216 replaceRule (&spl, mtail, pr);
2218 /* if restart rule type then
2219 start at the top again */
2228 hTabDeleteAll (pr->vars);
2229 Safe_free (pr->vars);
2233 freeTrace (&_G.values);
2236 } while (restart == TRUE);
2240 hTabDeleteAll (labelHash);
2241 freeTrace (&_G.labels);
2247 /*-----------------------------------------------------------------*/
2248 /* readFileIntoBuffer - reads a file into a string buffer */
2249 /*-----------------------------------------------------------------*/
2251 readFileIntoBuffer (char *fname)
2257 char lb[MAX_PATTERN_LEN];
2259 if (!(f = fopen (fname, "r")))
2261 fprintf (stderr, "cannot open peep rule file\n");
2265 while ((ch = fgetc (f)) != EOF)
2269 /* if we maxed out our local buffer */
2270 if (nch >= (MAX_PATTERN_LEN - 2))
2273 /* copy it into allocated buffer */
2276 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2277 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2281 rs = Safe_strdup (lb);
2287 /* if some charaters left over */
2291 /* copy it into allocated buffer */
2294 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2295 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2299 rs = Safe_strdup (lb);
2305 /*-----------------------------------------------------------------*/
2306 /* initPeepHole - initialises the peep hole optimizer stuff */
2307 /*-----------------------------------------------------------------*/
2313 /* read in the default rules */
2314 if (!options.nopeep)
2316 readRules (port->peep.default_rules);
2319 /* if we have any additional file read it too */
2320 if (options.peep_file)
2322 readRules (s = readFileIntoBuffer (options.peep_file));
2323 setToNull ((void *) &s);
2324 /* override nopeep setting, default rules have not been read */
2329 #if !OPT_DISABLE_PIC
2330 /* Convert the peep rules into pcode.
2331 NOTE: this is only support in the PIC port (at the moment)
2334 peepRules2pCode(rootRules);
2337 #if !OPT_DISABLE_PIC16
2338 /* Convert the peep rules into pcode.
2339 NOTE: this is only support in the PIC port (at the moment)
2340 and the PIC16 port (VR 030601)
2342 if (TARGET_IS_PIC16)
2343 pic16_peepRules2pCode(rootRules);