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);
48 static void bindVar (int key, char **s, hTab ** vtab);
50 static bool matchLine (char *, char *, hTab **);
52 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
53 lineNode *head, char *cmdLine)
56 void peepRules2pCode(peepRule *);
59 #if !OPT_DISABLE_PIC16
60 void pic16_peepRules2pCode(peepRule *);
63 /*-----------------------------------------------------------------*/
64 /* pcDistance - afinds a label back ward or forward */
65 /*-----------------------------------------------------------------*/
68 pcDistance (lineNode * cpos, char *lbl, bool back)
71 char buff[MAX_PATTERN_LEN];
74 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
82 if (port->peep.getSize) {
83 dist += port->peep.getSize(pl);
89 if (strncmp (pl->line, buff, strlen (buff)) == 0)
101 /*-----------------------------------------------------------------*/
102 /* flat24bitModeAndPortDS390 - */
103 /*-----------------------------------------------------------------*/
104 FBYNAME (flat24bitModeAndPortDS390)
106 return (((strcmp(port->target,"ds390") == 0) ||
107 (strcmp(port->target,"ds400") == 0)) &&
108 (options.model == MODEL_FLAT24));
111 /*-----------------------------------------------------------------*/
112 /* portIsDS390 - return true if port is DS390 */
113 /*-----------------------------------------------------------------*/
114 FBYNAME (portIsDS390)
116 return ((strcmp(port->target,"ds390") == 0) ||
117 (strcmp(port->target,"ds400") == 0));
120 /*-----------------------------------------------------------------*/
121 /* flat24bitMode - will check to see if we are in flat24 mode */
122 /*-----------------------------------------------------------------*/
123 FBYNAME (flat24bitMode)
125 return (options.model == MODEL_FLAT24);
128 /*-----------------------------------------------------------------*/
129 /* xramMovcOption - check if using movc to read xram */
130 /*-----------------------------------------------------------------*/
131 FBYNAME (xramMovcOption)
133 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
141 /*-----------------------------------------------------------------*/
142 /* labelInRange - will check to see if label %5 is within range */
143 /*-----------------------------------------------------------------*/
144 FBYNAME (labelInRange)
146 /* assumes that %5 pattern variable has the label name */
147 char *lbl = hTabItemWithKey (vars, 5);
153 /* Don't optimize jumps in a jump table; a more generic test */
154 if (currPl->ic && currPl->ic->op == JUMPTABLE)
157 /* if the previous two instructions are "ljmp"s then don't
158 do it since it can be part of a jump table */
159 if (currPl->prev && currPl->prev->prev &&
160 strstr (currPl->prev->line, "ljmp") &&
161 strstr (currPl->prev->prev->line, "ljmp"))
164 /* calculate the label distance : the jump for reladdr can be
165 +/- 127 bytes, here Iam assuming that an average 8051
166 instruction is 2 bytes long, so if the label is more than
167 63 intructions away, the label is considered out of range
168 for a relative jump. we could get more precise this will
169 suffice for now since it catches > 90% cases */
170 dist = (pcDistance (currPl, lbl, TRUE) +
171 pcDistance (currPl, lbl, FALSE));
173 /* changed to 127, now that pcDistance return actual number of bytes */
174 if (!dist || dist > 127)
181 /*-----------------------------------------------------------------*/
182 /* labelJTInRange - will check to see if label %5 and up are */
184 /* Specifically meant to optimize long (3-byte) jumps to short */
185 /* (2-byte) jumps in jumptables */
186 /*-----------------------------------------------------------------*/
187 FBYNAME (labelJTInRange)
192 if (!getenv("SDCC_SJMP_JUMPTABLE"))
195 /* Only optimize within a jump table */
196 if (currPl->ic && currPl->ic->op != JUMPTABLE)
199 count = elementsInSet( IC_JTLABELS (currPl->ic) );
201 /* check all labels (this is needed if the case statements are unsorted) */
202 for (i=0; i<count; i++)
204 /* assumes that the %5 pattern variable has the first ljmp label */
205 lbl = hTabItemWithKey (vars, 5+i);
209 dist = pcDistance (currPl, lbl, FALSE);
211 /* three terms used to calculate allowable distance */
212 // 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);
214 dist > 127+ /* range of sjmp */
215 (7+3*i)+ /* offset between this jump and currPl,
216 should use pcDistance instead? */
217 (count-i-1) /* if peephole applies distance is shortened */
225 /*-----------------------------------------------------------------*/
226 /* labelIsReturnOnly - Check if label %5 is followed by RET */
227 /*-----------------------------------------------------------------*/
228 FBYNAME (labelIsReturnOnly)
230 /* assumes that %5 pattern variable has the label name */
231 const char *label, *p;
236 /* Don't optimize jumps in a jump table; a more generic test */
237 if (currPl->ic && currPl->ic->op == JUMPTABLE)
240 label = hTabItemWithKey (vars, 5);
245 for(pl = currPl; pl; pl = pl->next)
247 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
249 if (strncmp(pl->line, label, len) == 0)
250 break; /* Found Label */
251 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
252 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
253 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
254 *(pl->line+5) != '$')
256 return FALSE; /* non-local label encountered */
261 return FALSE; /* did not find the label */
263 while (pl && (pl->isDebug || pl->isComment))
265 if (!pl || !pl->line || pl->isDebug)
266 return FALSE; /* next line not valid */
268 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
274 if (strcmp(p, retInst) == 0)
280 /*-----------------------------------------------------------------*/
281 /* labelIsUncondJump - Check if label %5 is followed by an */
282 /* unconditional jump and put the destination of that jump in %6 */
283 /*-----------------------------------------------------------------*/
284 FBYNAME (labelIsUncondJump)
286 /* assumes that %5 pattern variable has the label name */
291 char * jpInst = NULL;
293 /* Don't optimize jumps in a jump table; a more generic test */
294 if (currPl->ic && currPl->ic->op == JUMPTABLE)
297 label = hTabItemWithKey (vars, 5);
302 for (pl = currPl; pl; pl = pl->next)
304 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
306 if (strncmp(pl->line, label, len) == 0)
307 break; /* Found Label */
308 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
309 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
310 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
311 *(pl->line+5) != '$')
313 return FALSE; /* non-local label encountered */
318 return FALSE; /* did not find the label */
320 while (pl && (pl->isDebug || pl->isComment))
322 if (!pl || !pl->line)
323 return FALSE; /* next line not valid */
325 while (*p && ISCHARSPACE(*p))
328 if (TARGET_MCS51_LIKE)
334 len = strlen(jpInst);
335 if (strncmp(p, jpInst, len) != 0)
336 return FALSE; /* next line is no jump */
338 while (*p && ISCHARSPACE(*p))
342 while (*q && *q!=';')
344 while (q>p && ISCHARSPACE(*q))
348 return FALSE; /* no destination? */
351 while (q>p && *q!=',')
354 return FALSE; /* conditional jump */
356 /* now put the destination in %6 */
357 bindVar (6, &p, &vars);
362 /*-----------------------------------------------------------------*/
363 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
364 /* usage of it in the code depends on a value from this section */
365 /*-----------------------------------------------------------------*/
366 FBYNAME (okToRemoveSLOC)
369 const char *sloc, *p;
370 int dummy1, dummy2, dummy3;
372 /* assumes that %1 as the SLOC name */
373 sloc = hTabItemWithKey (vars, 1);
374 if (sloc == NULL) return FALSE;
375 p = strstr(sloc, "sloc");
376 if (p == NULL) return FALSE;
378 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
379 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
380 /* the sloc name begins with that. Probably not really necessary */
382 /* Look for any occurance of this SLOC before the peephole match */
383 for (pl = currPl->prev; pl; pl = pl->prev) {
384 if (pl->line && !pl->isDebug && !pl->isComment
385 && *pl->line != ';' && strstr(pl->line, sloc))
388 /* Look for any occurance of this SLOC after the peephole match */
389 for (pl = endPl->next; pl; pl = pl->next) {
390 if (pl->line && !pl->isDebug && !pl->isComment
391 && *pl->line != ';' && strstr(pl->line, sloc))
394 return TRUE; /* safe for a peephole to remove it :) */
397 /*-----------------------------------------------------------------*/
398 /* deadMove - Check, if a pop/push pair can be removed */
399 /*-----------------------------------------------------------------*/
402 const char *reg = hTabItemWithKey (vars, 1);
404 if (port->peep.deadMove)
405 return port->peep.deadMove (reg, currPl, head);
407 fprintf (stderr, "Function deadMove not initialized in port structure\n");
411 /*-----------------------------------------------------------------*/
412 /* operandsNotSame - check if %1 & %2 are the same */
413 /*-----------------------------------------------------------------*/
414 FBYNAME (operandsNotSame)
416 char *op1 = hTabItemWithKey (vars, 1);
417 char *op2 = hTabItemWithKey (vars, 2);
419 if (strcmp (op1, op2) == 0)
425 /*-----------------------------------------------------------------*/
426 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
427 /*-----------------------------------------------------------------*/
428 FBYNAME (operandsNotSame3)
430 char *op1 = hTabItemWithKey (vars, 1);
431 char *op2 = hTabItemWithKey (vars, 2);
432 char *op3 = hTabItemWithKey (vars, 3);
434 if ( (strcmp (op1, op2) == 0) ||
435 (strcmp (op1, op3) == 0) ||
436 (strcmp (op2, op3) == 0) )
442 /*-----------------------------------------------------------------*/
443 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
444 /*-----------------------------------------------------------------*/
445 FBYNAME (operandsNotSame4)
447 char *op1 = hTabItemWithKey (vars, 1);
448 char *op2 = hTabItemWithKey (vars, 2);
449 char *op3 = hTabItemWithKey (vars, 3);
450 char *op4 = hTabItemWithKey (vars, 4);
452 if ( (strcmp (op1, op2) == 0) ||
453 (strcmp (op1, op3) == 0) ||
454 (strcmp (op1, op4) == 0) ||
455 (strcmp (op2, op3) == 0) ||
456 (strcmp (op2, op4) == 0) ||
457 (strcmp (op3, op4) == 0) )
463 /*-----------------------------------------------------------------*/
464 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
465 /*-----------------------------------------------------------------*/
466 FBYNAME (operandsNotSame5)
468 char *op1 = hTabItemWithKey (vars, 1);
469 char *op2 = hTabItemWithKey (vars, 2);
470 char *op3 = hTabItemWithKey (vars, 3);
471 char *op4 = hTabItemWithKey (vars, 4);
472 char *op5 = hTabItemWithKey (vars, 5);
474 if ( (strcmp (op1, op2) == 0) ||
475 (strcmp (op1, op3) == 0) ||
476 (strcmp (op1, op4) == 0) ||
477 (strcmp (op1, op5) == 0) ||
478 (strcmp (op2, op3) == 0) ||
479 (strcmp (op2, op4) == 0) ||
480 (strcmp (op2, op5) == 0) ||
481 (strcmp (op3, op4) == 0) ||
482 (strcmp (op3, op5) == 0) ||
483 (strcmp (op4, op5) == 0) )
489 /*-----------------------------------------------------------------*/
490 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
491 /*-----------------------------------------------------------------*/
492 FBYNAME (operandsNotSame6)
494 char *op1 = hTabItemWithKey (vars, 1);
495 char *op2 = hTabItemWithKey (vars, 2);
496 char *op3 = hTabItemWithKey (vars, 3);
497 char *op4 = hTabItemWithKey (vars, 4);
498 char *op5 = hTabItemWithKey (vars, 5);
499 char *op6 = hTabItemWithKey (vars, 6);
501 if ( (strcmp (op1, op2) == 0) ||
502 (strcmp (op1, op3) == 0) ||
503 (strcmp (op1, op4) == 0) ||
504 (strcmp (op1, op5) == 0) ||
505 (strcmp (op1, op6) == 0) ||
506 (strcmp (op2, op3) == 0) ||
507 (strcmp (op2, op4) == 0) ||
508 (strcmp (op2, op5) == 0) ||
509 (strcmp (op2, op6) == 0) ||
510 (strcmp (op3, op4) == 0) ||
511 (strcmp (op3, op5) == 0) ||
512 (strcmp (op3, op6) == 0) ||
513 (strcmp (op4, op5) == 0) ||
514 (strcmp (op4, op6) == 0) ||
515 (strcmp (op5, op6) == 0) )
522 /*-----------------------------------------------------------------*/
523 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
524 /*-----------------------------------------------------------------*/
525 FBYNAME (operandsNotSame7)
527 char *op1 = hTabItemWithKey (vars, 1);
528 char *op2 = hTabItemWithKey (vars, 2);
529 char *op3 = hTabItemWithKey (vars, 3);
530 char *op4 = hTabItemWithKey (vars, 4);
531 char *op5 = hTabItemWithKey (vars, 5);
532 char *op6 = hTabItemWithKey (vars, 6);
533 char *op7 = hTabItemWithKey (vars, 7);
535 if ( (strcmp (op1, op2) == 0) ||
536 (strcmp (op1, op3) == 0) ||
537 (strcmp (op1, op4) == 0) ||
538 (strcmp (op1, op5) == 0) ||
539 (strcmp (op1, op6) == 0) ||
540 (strcmp (op1, op7) == 0) ||
541 (strcmp (op2, op3) == 0) ||
542 (strcmp (op2, op4) == 0) ||
543 (strcmp (op2, op5) == 0) ||
544 (strcmp (op2, op6) == 0) ||
545 (strcmp (op2, op7) == 0) ||
546 (strcmp (op3, op4) == 0) ||
547 (strcmp (op3, op5) == 0) ||
548 (strcmp (op3, op6) == 0) ||
549 (strcmp (op3, op7) == 0) ||
550 (strcmp (op4, op5) == 0) ||
551 (strcmp (op4, op6) == 0) ||
552 (strcmp (op4, op7) == 0) ||
553 (strcmp (op5, op6) == 0) ||
554 (strcmp (op5, op7) == 0) ||
555 (strcmp (op6, op7) == 0) )
561 /*-----------------------------------------------------------------*/
562 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
563 /*-----------------------------------------------------------------*/
564 FBYNAME (operandsNotSame8)
566 char *op1 = hTabItemWithKey (vars, 1);
567 char *op2 = hTabItemWithKey (vars, 2);
568 char *op3 = hTabItemWithKey (vars, 3);
569 char *op4 = hTabItemWithKey (vars, 4);
570 char *op5 = hTabItemWithKey (vars, 5);
571 char *op6 = hTabItemWithKey (vars, 6);
572 char *op7 = hTabItemWithKey (vars, 7);
573 char *op8 = hTabItemWithKey (vars, 8);
575 if ( (strcmp (op1, op2) == 0) ||
576 (strcmp (op1, op3) == 0) ||
577 (strcmp (op1, op4) == 0) ||
578 (strcmp (op1, op5) == 0) ||
579 (strcmp (op1, op6) == 0) ||
580 (strcmp (op1, op7) == 0) ||
581 (strcmp (op1, op8) == 0) ||
582 (strcmp (op2, op3) == 0) ||
583 (strcmp (op2, op4) == 0) ||
584 (strcmp (op2, op5) == 0) ||
585 (strcmp (op2, op6) == 0) ||
586 (strcmp (op2, op7) == 0) ||
587 (strcmp (op2, op8) == 0) ||
588 (strcmp (op3, op4) == 0) ||
589 (strcmp (op3, op5) == 0) ||
590 (strcmp (op3, op6) == 0) ||
591 (strcmp (op3, op7) == 0) ||
592 (strcmp (op3, op8) == 0) ||
593 (strcmp (op4, op5) == 0) ||
594 (strcmp (op4, op6) == 0) ||
595 (strcmp (op4, op7) == 0) ||
596 (strcmp (op4, op8) == 0) ||
597 (strcmp (op5, op6) == 0) ||
598 (strcmp (op5, op7) == 0) ||
599 (strcmp (op5, op8) == 0) ||
600 (strcmp (op6, op7) == 0) ||
601 (strcmp (op6, op8) == 0) ||
602 (strcmp (op7, op8) == 0) )
608 /*-----------------------------------------------------------------*/
609 /* labelHashEntry- searches for a label in the list labelHash */
610 /* Builds labelHash, if it does not yet exist. */
611 /* Returns the labelHashEntry or NULL */
612 /*-----------------------------------------------------------------*/
614 getLabelRef (const char *label, lineNode *head)
616 labelHashEntry *entry;
618 /* If we don't have the label hash table yet, build it. */
621 buildLabelRefCountHash (head);
624 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
628 if (!strcmp (label, entry->name))
632 entry = hTabNextItemWK (labelHash);
639 * takes two parameters: a variable (bound to a label name)
640 * and an expected reference count.
642 * Returns TRUE if that label is defined and referenced exactly
643 * the given number of times.
645 FBYNAME (labelRefCount)
647 int varNumber, expectedRefCount;
650 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
652 char *label = hTabItemWithKey (vars, varNumber);
656 labelHashEntry *entry = getLabelRef (label, head);
662 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
663 label, entry->refCount, expectedRefCount);
666 rc = (expectedRefCount == entry->refCount);
670 fprintf (stderr, "*** internal error: no label has entry for"
671 " %s in labelRefCount peephole.\n",
677 fprintf (stderr, "*** internal error: var %d not bound"
678 " in peephole labelRefCount rule.\n",
686 "*** internal error: labelRefCount peephole restriction"
687 " malformed: %s\n", cmdLine);
693 /* labelRefCountChange:
694 * takes two parameters: a variable (bound to a label name)
695 * and a signed int for changing the reference count.
697 * Please note, this function is not a conditional. It unconditionally
698 * changes the label. It should be passed as the 'last' function
699 * so it only is applied if all other conditions have been met.
701 * should always return TRUE
703 FBYNAME (labelRefCountChange)
705 int varNumber, RefCountDelta;
708 /* If we don't have the label hash table yet, build it. */
711 buildLabelRefCountHash (head);
714 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
716 char *label = hTabItemWithKey (vars, varNumber);
720 labelHashEntry *entry;
722 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
726 if (!strcmp (label, entry->name))
730 entry = hTabNextItemWK (labelHash);
734 if (0 <= entry->refCount + RefCountDelta)
736 entry->refCount += RefCountDelta;
741 fprintf (stderr, "*** internal error: label %s may not get"
742 " negative refCount in %s peephole.\n",
743 label, __FUNCTION__);
748 fprintf (stderr, "*** internal error: no label has entry for"
749 " %s in %s peephole.\n",
750 label, __FUNCTION__);
755 fprintf (stderr, "*** internal error: var %d not bound"
756 " in peephole %s rule.\n",
757 varNumber, __FUNCTION__);
763 "*** internal error: labelRefCount peephole restriction"
764 " malformed: %s\n", cmdLine);
770 /* Within the context of the lines currPl through endPl, determine
771 ** if the variable var contains a symbol that is volatile. Returns
772 ** TRUE only if it is certain that this was not volatile (the symbol
773 ** was found and not volatile, or var was a constant or CPU register).
774 ** Returns FALSE if the symbol was found and volatile, the symbol was
775 ** not found, or var was a indirect/pointer addressing mode.
778 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
780 char symname[SDCC_NAME_MAX + 1];
787 /* Can't tell if indirect accesses are volatile or not, so
788 ** assume they are, just to be safe.
790 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
795 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
797 if (strstr(var,"(bc)"))
799 if (strstr(var,"(de)"))
801 if (strstr(var,"(hl)"))
803 if (strstr(var,"(ix"))
805 if (strstr(var,"(iy"))
809 /* Extract a symbol name from the variable */
810 while (*vp && (*vp!='_'))
812 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
818 /* Nothing resembling a symbol name was found, so it can't
825 for (cl = currPl; cl!=endPl->next; cl = cl->next)
827 if (cl->ic && (cl->ic!=last_ic))
833 op = IC_COND (cl->ic);
834 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
835 return !op->isvolatile;
837 op = IC_JTCOND (cl->ic);
838 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
839 return !op->isvolatile;
841 op = IC_LEFT (cl->ic);
842 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
843 return !op->isvolatile;
844 op = IC_RIGHT (cl->ic);
845 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
846 return !op->isvolatile;
847 op = IC_RESULT (cl->ic);
848 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
849 return !op->isvolatile;
854 /* Couldn't find the symbol for some reason. Assume volatile. */
860 * This rule restriction has two different behaviours depending on
861 * the number of parameters given.
863 * if notVolatile (no parameters given)
864 * The rule is applied only if none of the iCodes originating
865 * the matched pattern reference a volatile operand.
867 * if notVolatile %1 ... (one or more parameters given)
868 * The rule is applied if the parameters are not expressions
869 * containing volatile symbols and are not pointer accesses.
872 FBYNAME (notVolatile)
883 /* If no parameters given, just scan the iCodes for volatile operands */
884 for (cl = currPl; cl!=endPl->next; cl = cl->next)
891 op = IC_COND (cl->ic);
892 if (IS_SYMOP (op) && op->isvolatile)
895 op = IC_JTCOND (cl->ic);
896 if (IS_SYMOP (op) && op->isvolatile)
899 op = IC_LEFT (cl->ic);
900 if (IS_SYMOP (op) && op->isvolatile)
902 op = IC_RIGHT (cl->ic);
903 if (IS_SYMOP (op) && op->isvolatile)
905 op = IC_RESULT (cl->ic);
906 if (IS_SYMOP (op) && op->isvolatile)
914 /* There were parameters; check the volatility of each */
915 while (*cmdLine && ISCHARSPACE(*cmdLine))
922 if (!ISCHARDIGIT(*cmdLine))
924 varNumber = strtol(cmdLine, &digitend, 10);
926 while (*cmdLine && ISCHARSPACE(*cmdLine))
929 var = hTabItemWithKey (vars, varNumber);
933 notvol = notVolatileVariable (var, currPl, endPl);
939 fprintf (stderr, "*** internal error: var %d not bound"
940 " in peephole notVolatile rule.\n",
951 "*** internal error: notVolatile peephole restriction"
952 " malformed: %s\n", cmdLine);
957 /*------------------------------------------------------------------*/
958 /* setFromConditionArgs - parse a peephole condition's arguments */
959 /* to produce a set of strings, one per argument. Variables %x will */
960 /* be replaced with their values. String literals (in single quotes)*/
961 /* are accepted and return in unquoted form. */
962 /*------------------------------------------------------------------*/
964 setFromConditionArgs (char *cmdLine, hTab * vars)
969 set *operands = NULL;
974 while (*cmdLine && ISCHARSPACE(*cmdLine))
982 if (!ISCHARDIGIT(*cmdLine))
984 varNumber = strtol(cmdLine, &digitend, 10);
987 var = hTabItemWithKey (vars, varNumber);
991 addSetHead (&operands, var);
996 else if (*cmdLine == '\'' )
998 char quote = *cmdLine;
1001 while (*cmdLine && *cmdLine != quote)
1003 if (*cmdLine == quote)
1007 addSetHead (&operands, var);
1012 while (*cmdLine && ISCHARSPACE(*cmdLine))
1019 deleteSet (&operands);
1024 operandBaseName (const char *op)
1026 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1028 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1030 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1038 /*-------------------------------------------------------------------*/
1039 /* operandsNotRelated - returns true if the condition's operands are */
1040 /* not related (taking into account register name aliases). N-way */
1041 /* comparison performed between all operands. */
1042 /*-------------------------------------------------------------------*/
1043 FBYNAME (operandsNotRelated)
1046 const char *op1, *op2;
1048 operands = setFromConditionArgs (cmdLine, vars);
1053 "*** internal error: operandsNotRelated peephole restriction"
1054 " malformed: %s\n", cmdLine);
1058 while ((op1 = setFirstItem (operands)))
1060 deleteSetItem (&operands, (void*)op1);
1061 op1 = operandBaseName (op1);
1063 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1065 op2 = operandBaseName (op2);
1066 if (strcmp (op1, op2) == 0)
1068 deleteSet (&operands);
1074 deleteSet (&operands);
1079 /*-------------------------------------------------------------------*/
1080 /* operandsLiteral - returns true of the condition's operands are */
1082 /*-------------------------------------------------------------------*/
1083 FBYNAME (operandsLiteral)
1088 operands = setFromConditionArgs (cmdLine, vars);
1093 "*** internal error: operandsLiteral peephole restriction"
1094 " malformed: %s\n", cmdLine);
1098 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1102 deleteSet (&operands);
1107 deleteSet (&operands);
1112 /*-----------------------------------------------------------------*/
1113 /* callFuncByName - calls a function as defined in the table */
1114 /*-----------------------------------------------------------------*/
1116 callFuncByName (char *fname,
1125 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1130 "labelInRange", labelInRange
1134 "labelJTInRange", labelJTInRange
1138 "operandsNotSame", operandsNotSame
1142 "operandsNotSame3", operandsNotSame3
1146 "operandsNotSame4", operandsNotSame4
1150 "operandsNotSame5", operandsNotSame5
1154 "operandsNotSame6", operandsNotSame6
1158 "operandsNotSame7", operandsNotSame7
1162 "operandsNotSame8", operandsNotSame8
1166 "24bitMode", flat24bitMode
1170 "xramMovcOption", xramMovcOption
1174 "labelRefCount", labelRefCount
1178 "portIsDS390", portIsDS390
1181 "labelIsReturnOnly", labelIsReturnOnly
1184 "labelIsUncondJump", labelIsUncondJump
1187 "okToRemoveSLOC", okToRemoveSLOC
1190 "deadMove", deadMove
1193 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1196 "notVolatile", notVolatile
1199 "operandsNotRelated", operandsNotRelated
1202 "operandsLiteral", operandsLiteral
1205 "labelRefCountChange", labelRefCountChange
1209 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1213 /* Isolate the function name part (we are passed the full condition
1214 * string including arguments)
1216 cmdTerm = cmdCopy = Safe_strdup(fname);
1220 funcArgs = funcName = cmdTerm;
1221 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1223 *funcArgs = '\0'; /* terminate the function name */
1227 /* Find the start of the arguments */
1228 if (c == ' ' || c == '\t')
1229 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1232 /* If the arguments started with an opening parenthesis, */
1233 /* use the closing parenthesis for the end of the */
1234 /* arguments and look for the start of another condition */
1235 /* that can optionally follow. If there was no opening */
1236 /* parethesis, then everything that follows are arguments */
1237 /* and there can be no additional conditions. */
1241 while ((c = *cmdTerm) && c != ')')
1243 *cmdTerm = '\0'; /* terminate the arguments */
1247 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1253 cmdTerm = NULL; /* closing parenthesis missing */
1262 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1264 if (strcmp (ftab[i].fname, funcName) == 0)
1266 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1274 "could not find named function \"%s\" in "
1275 "peephole function table\n",
1277 // If the function couldn't be found, let's assume it's
1278 // a bad rule and refuse it.
1283 while (rc && cmdTerm);
1290 /*-----------------------------------------------------------------*/
1291 /* printLine - prints a line chain into a given file */
1292 /*-----------------------------------------------------------------*/
1294 printLine (lineNode * head, struct dbuf_s * oBuf)
1296 iCode *last_ic = NULL;
1297 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1301 if (head->ic!=last_ic)
1304 if (debug_iCode_tracking)
1307 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1308 head->ic->block, head->ic->seq);
1310 dbuf_append_str (oBuf, "; iCode lost\n");
1314 /* don't indent comments & labels */
1316 (head->isComment || head->isLabel)) {
1317 dbuf_printf (oBuf, "%s\n", head->line);
1319 if (head->isInline && *head->line=='#') {
1320 // comment out preprocessor directives in inline asm
1321 dbuf_append_char (oBuf, ';');
1323 dbuf_printf (oBuf, "\t%s\n", head->line);
1329 /*-----------------------------------------------------------------*/
1330 /* newPeepRule - creates a new peeprule and attach it to the root */
1331 /*-----------------------------------------------------------------*/
1333 newPeepRule (lineNode * match,
1340 pr = Safe_alloc ( sizeof (peepRule));
1342 pr->replace = replace;
1343 pr->restart = restart;
1347 pr->cond = Safe_strdup (cond);
1352 pr->vars = newHashTable (100);
1354 /* if root is empty */
1356 rootRules = currRule = pr;
1358 currRule = currRule->next = pr;
1363 /*-----------------------------------------------------------------*/
1364 /* newLineNode - creates a new peep line */
1365 /*-----------------------------------------------------------------*/
1367 newLineNode (const char *line)
1371 pl = Safe_alloc ( sizeof (lineNode));
1372 pl->line = Safe_strdup (line);
1377 /*-----------------------------------------------------------------*/
1378 /* connectLine - connects two lines */
1379 /*-----------------------------------------------------------------*/
1381 connectLine (lineNode * pl1, lineNode * pl2)
1385 fprintf (stderr, "trying to connect null line\n");
1395 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1396 if (!*x) { fprintf(stderr,y); return ; } }
1398 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1399 if (!*x) { fprintf(stderr,z); return ; } }
1400 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1401 if (!*x) { fprintf(stderr,z); return ; } }
1403 /*-----------------------------------------------------------------*/
1404 /* getPeepLine - parses the peep lines */
1405 /*-----------------------------------------------------------------*/
1407 getPeepLine (lineNode ** head, char **bpp)
1409 char lines[MAX_PATTERN_LEN];
1413 lineNode *currL = NULL;
1420 fprintf (stderr, "unexpected end of match pattern\n");
1427 while (ISCHARSPACE (*bp) ||
1438 /* read till end of line */
1440 while ((*bp != '\n' && *bp != '}') && *bp)
1445 while (*lp && ISCHARSPACE(*lp))
1447 isComment = (*lp == ';');
1449 if (!isComment || (isComment && !options.noPeepComments))
1455 *head = currL = newLineNode (lines);
1457 currL = connectLine (currL, newLineNode (lines));
1458 currL->isComment = isComment;
1459 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1468 /*-----------------------------------------------------------------*/
1469 /* readRules - reads the rules from a string buffer */
1470 /*-----------------------------------------------------------------*/
1472 readRules (char *bp)
1475 char lines[MAX_PATTERN_LEN];
1479 lineNode *currL = NULL;
1485 /* look for the token "replace" that is the
1487 while (*bp && strncmp (bp, "replace", 7))
1494 /* then look for either "restart" or '{' */
1495 while (strncmp (bp, "restart", 7) &&
1502 fprintf (stderr, "expected 'restart' or '{'\n");
1510 { /* must be restart */
1512 bp += strlen ("restart");
1514 EXPECT_CHR (bp, '{', "expected '{'\n");
1518 /* skip thru all the blank space */
1519 SKIP_SPACE (bp, "unexpected end of rule\n");
1521 match = replace = currL = NULL;
1522 /* we are the start of a rule */
1523 getPeepLine (&match, &bp);
1525 /* now look for by */
1526 EXPECT_STR (bp, "by", "expected 'by'\n");
1528 /* then look for a '{' */
1529 EXPECT_CHR (bp, '{', "expected '{'\n");
1532 /* save char position (needed for generating error msg) */
1535 SKIP_SPACE (bp, "unexpected end of rule\n");
1536 getPeepLine (&replace, &bp);
1538 /* look for a 'if' */
1539 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1542 if (strncmp (bp, "if", 2) == 0)
1545 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1549 fprintf (stderr, "expected condition name\n");
1553 /* look for the condition */
1555 while (*bp && (*bp != '\n'))
1561 newPeepRule (match, replace, lines, restart);
1565 if (*bp && strncmp (bp, "replace", 7))
1567 /* not the start of a new peeprule, so "if" should be here */
1572 /* go to the start of the line following "{" of the "by" token */
1573 while (*rp && (*rp == '\n'))
1576 /* copy text of rule starting with line after "by {" */
1578 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1581 /* and now the rest of the line */
1582 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1586 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1589 newPeepRule (match, replace, NULL, restart);
1595 /*-----------------------------------------------------------------*/
1596 /* keyForVar - returns the numeric key for a var */
1597 /*-----------------------------------------------------------------*/
1603 while (ISCHARDIGIT (*d))
1612 /*-----------------------------------------------------------------*/
1613 /* bindVar - binds a value to a variable in the given hashtable */
1614 /*-----------------------------------------------------------------*/
1616 bindVar (int key, char **s, hTab ** vtab)
1618 char vval[MAX_PATTERN_LEN];
1622 /* first get the value of the variable */
1624 /* the value is ended by a ',' or space or newline or null or ) */
1627 !ISCHARSPACE (*vvx) &&
1633 /* if we find a '(' then we need to balance it */
1645 // include the trailing ')'
1654 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1656 hTabAddItem (vtab, key, vvx);
1659 /*-----------------------------------------------------------------*/
1660 /* matchLine - matches one line */
1661 /*-----------------------------------------------------------------*/
1663 matchLine (char *s, char *d, hTab ** vars)
1672 /* skip white space in both */
1673 while (ISCHARSPACE (*s))
1675 while (ISCHARSPACE (*d))
1678 /* if the destination is a var */
1679 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1681 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1682 /* if the variable is already bound
1683 then it MUST match with dest */
1691 /* variable not bound we need to bind it */
1692 bindVar (keyForVar (d + 1), &s, vars);
1694 /* in either case go past the variable */
1696 while (ISCHARDIGIT (*d))
1699 while (ISCHARSPACE (*s))
1701 while (ISCHARSPACE (*d))
1705 /* they should be an exact match other wise */
1714 /* get rid of the trailing spaces
1715 in both source & destination */
1717 while (ISCHARSPACE (*s))
1721 while (ISCHARSPACE (*d))
1724 /* after all this if only one of them
1725 has something left over then no match */
1732 /*-----------------------------------------------------------------*/
1733 /* matchRule - matches a all the rule lines */
1734 /*-----------------------------------------------------------------*/
1736 matchRule (lineNode * pl,
1741 lineNode *spl; /* source pl */
1742 lineNode *rpl; /* rule peep line */
1744 /* setToNull((void *) &pr->vars); */
1745 /* pr->vars = newHashTable(100); */
1747 /* for all the lines defined in the rule */
1753 /* if the source line starts with a ';' then
1754 comment line don't process or the source line
1755 contains == . debugger information skip it */
1757 (*spl->line == ';' || spl->isDebug))
1763 if (!matchLine (spl->line, rpl->line, &pr->vars))
1771 /* if rules ended */
1774 /* if this rule has additional conditions */
1777 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1796 reassociate_ic_down (lineNode *shead, lineNode *stail,
1797 lineNode *rhead, lineNode *rtail)
1799 lineNode *csl; /* current source line */
1800 lineNode *crl; /* current replacement line */
1806 /* skip over any comments */
1807 while (csl!=stail->next && csl->isComment)
1809 while (crl!=rtail->next && crl->isComment)
1812 /* quit if we reach the end */
1813 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1816 if (matchLine(csl->line,crl->line,NULL))
1828 reassociate_ic_up (lineNode *shead, lineNode *stail,
1829 lineNode *rhead, lineNode *rtail)
1831 lineNode *csl; /* current source line */
1832 lineNode *crl; /* current replacement line */
1838 /* skip over any comments */
1839 while (csl!=shead->prev && csl->isComment)
1841 while (crl!=rhead->prev && crl->isComment)
1844 /* quit if we reach the end */
1845 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1848 if (matchLine(csl->line,crl->line,NULL))
1859 /*------------------------------------------------------------------*/
1860 /* reassociate_ic - reassociate replacement lines with origin iCode */
1861 /*------------------------------------------------------------------*/
1863 reassociate_ic (lineNode *shead, lineNode *stail,
1864 lineNode *rhead, lineNode *rtail)
1866 lineNode *csl; /* current source line */
1867 lineNode *crl; /* current replacement line */
1871 /* Check to see if all the source lines (excluding comments) came
1872 ** for the same iCode
1875 for (csl=shead;csl!=stail->next;csl=csl->next)
1876 if (csl->ic && !csl->isComment)
1881 single_iCode = (ic!=NULL);
1882 for (csl=shead;csl!=stail->next;csl=csl->next)
1883 if ((csl->ic != ic) && !csl->isComment)
1885 /* More than one iCode was found. However, if it's just the
1886 ** last line with the different iCode and it was not changed
1887 ** in the replacement, everything else must be the first iCode.
1889 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1891 rtail->ic = stail->ic;
1892 for (crl=rhead;crl!=rtail;crl=crl->next)
1897 single_iCode = FALSE;
1901 /* If all of the source lines came from the same iCode, then so have
1902 ** all of the replacement lines too.
1906 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1911 /* The source lines span iCodes, so we may end up with replacement
1912 ** lines that we don't know which iCode(s) to associate with. Do the
1913 ** best we can by using the following strategies:
1914 ** 1) Start at the top and scan down. As long as the source line
1915 ** matches the replacement line, they have the same iCode.
1916 ** 2) Start at the bottom and scan up. As long as the source line
1917 ** matches the replacement line, they have the same iCode.
1918 ** 3) For any label in the source, look for a matching label in
1919 ** the replacment. If found, they have the same iCode. From
1920 ** these matching labels, scan down for additional matching
1921 ** lines; if found, they also have the same iCode.
1924 /* Strategy #1: Start at the top and scan down for matches
1926 reassociate_ic_down(shead,stail,rhead,rtail);
1928 /* Strategy #2: Start at the bottom and scan up for matches
1930 reassociate_ic_up(shead,stail,rhead,rtail);
1932 /* Strategy #3: Try to match labels
1937 /* skip over any comments */
1938 while (csl!=stail->next && csl->isComment)
1940 if (csl==stail->next)
1945 /* found a source line label; look for it in the replacment lines */
1949 while (crl!=rtail->next && crl->isComment)
1951 if (crl==rtail->next)
1953 if (matchLine(csl->line, crl->line, NULL))
1955 reassociate_ic_down(csl,stail,crl,rtail);
1965 /* Try to assign a meaningful iCode to any comment that is missing
1966 one. Since they are comments, it's ok to make mistakes; we are just
1967 trying to improve continuity to simplify other tests.
1970 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1972 if (!crl->ic && ic && crl->isComment)
1979 /*-----------------------------------------------------------------*/
1980 /* replaceRule - does replacement of a matching pattern */
1981 /*-----------------------------------------------------------------*/
1983 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1985 lineNode *cl = NULL;
1986 lineNode *pl = NULL, *lhead = NULL;
1987 /* a long function name and long variable name can evaluate to
1988 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1989 char lb[MAX_PATTERN_LEN*4];
1991 lineNode *comment = NULL;
1993 /* collect all the comment lines in the source */
1994 for (cl = *shead; cl != stail; cl = cl->next)
1996 if (cl->line && (*cl->line == ';' || cl->isDebug))
1998 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1999 (comment = newLineNode (cl->line)));
2000 pl->isDebug = cl->isDebug;
2001 pl->isComment = cl->isComment || (*cl->line == ';');
2006 /* for all the lines in the replacement pattern do */
2007 for (pl = pr->replace; pl; pl = pl->next)
2017 /* if the line contains a variable */
2018 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2020 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2023 fprintf (stderr, "used unbound variable in replacement\n");
2031 while (ISCHARDIGIT (*l)) {
2041 cl = connectLine (cl, newLineNode (lb));
2043 lhead = cl = newLineNode (lb);
2044 cl->isComment = pl->isComment;
2045 cl->isLabel = pl->isLabel;
2048 /* add the comments if any to the head of list */
2051 lineNode *lc = comment;
2062 /* determine which iCodes the replacment lines relate to */
2063 reassociate_ic(*shead,stail,lhead,cl);
2065 /* now we need to connect / replace the original chain */
2066 /* if there is a prev then change it */
2069 (*shead)->prev->next = lhead;
2070 lhead->prev = (*shead)->prev;
2073 /* now for the tail */
2074 if (stail && stail->next)
2076 stail->next->prev = cl;
2078 cl->next = stail->next;
2083 /* the replacement is empty - delete the source lines */
2085 (*shead)->prev->next = stail->next;
2087 stail->next->prev = (*shead)->prev;
2088 *shead = stail->next;
2092 /* Returns TRUE if this line is a label definition.
2094 * If so, start will point to the start of the label name,
2095 * and len will be it's length.
2098 isLabelDefinition (const char *line, const char **start, int *len,
2101 const char *cp = line;
2103 /* This line is a label if if consists of:
2104 * [optional whitespace] followed by identifier chars
2105 * (alnum | $ | _ ) followed by a colon.
2108 while (*cp && ISCHARSPACE (*cp))
2120 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2121 (isPeepRule && (*cp == '%')))
2126 if ((cp == *start) || (*cp != ':'))
2131 *len = (cp - (*start));
2135 /* Quick & dirty string hash function. */
2137 hashSymbolName (const char *name)
2143 hash = (hash << 6) ^ *name;
2152 return hash % HTAB_SIZE;
2155 /* Build a hash of all labels in the passed set of lines
2156 * and how many times they are referenced.
2159 buildLabelRefCountHash (lineNode * head)
2166 assert (labelHash == NULL);
2167 labelHash = newHashTable (HTAB_SIZE);
2169 /* First pass: locate all the labels. */
2170 for (line = head; line; line = line->next)
2172 if (line->isLabel ||
2175 /* run isLabelDefinition to:
2176 - look for labels in inline assembler
2177 - calculate labelLen
2179 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2180 labelLen <= SDCC_NAME_MAX)
2182 labelHashEntry *entry;
2184 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2186 memcpy (entry->name, label, labelLen);
2187 entry->name[labelLen] = 0;
2188 entry->refCount = -1;
2190 /* Assume function entry points are referenced somewhere, */
2191 /* even if we can't find a reference (might be from outside */
2193 if (line->ic && (line->ic->op == FUNCTION))
2196 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2202 /* Second pass: for each line, note all the referenced labels. */
2203 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2207 for (i = 0; i < HTAB_SIZE; i++)
2209 labelHashEntry *thisEntry;
2211 thisEntry = hTabFirstItemWK (labelHash, i);
2215 if (strstr (line->line, thisEntry->name))
2217 thisEntry->refCount++;
2219 thisEntry = hTabNextItemWK (labelHash);
2226 /* Spew the contents of the table. Debugging fun only. */
2227 for (i = 0; i < HTAB_SIZE; i++)
2229 labelHashEntry *thisEntry;
2231 thisEntry = hTabFirstItemWK (labelHash, i);
2235 fprintf (stderr, "label: %s ref %d\n",
2236 thisEntry->name, thisEntry->refCount);
2237 thisEntry = hTabNextItemWK (labelHash);
2243 /* How does this work?
2249 replace and restart.
2254 Where is stuff allocated?
2258 /*-----------------------------------------------------------------*/
2259 /* peepHole - matches & substitutes rules */
2260 /*-----------------------------------------------------------------*/
2262 peepHole (lineNode ** pls)
2266 lineNode *mtail = NULL;
2267 bool restart, replaced;
2269 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2270 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2271 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2275 assert(labelHash == NULL);
2282 for (pr = rootRules; pr; pr = pr->next)
2284 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2288 /* if inline assembler then no peep hole */
2292 /* don't waste time starting a match on debug symbol
2294 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2299 /* Tidy up any data stored in the hTab */
2302 if (matchRule (spl, &mtail, pr, *pls))
2304 /* restart at the replaced line */
2310 replaceRule (pls, mtail, pr);
2314 replaceRule (&spl, mtail, pr);
2316 /* if restart rule type then
2317 start at the top again */
2326 hTabDeleteAll (pr->vars);
2327 Safe_free (pr->vars);
2331 freeTrace (&_G.values);
2334 } while (restart == TRUE);
2338 hTabDeleteAll (labelHash);
2339 freeTrace (&_G.labels);
2345 /*-----------------------------------------------------------------*/
2346 /* readFileIntoBuffer - reads a file into a string buffer */
2347 /*-----------------------------------------------------------------*/
2349 readFileIntoBuffer (char *fname)
2355 char lb[MAX_PATTERN_LEN];
2357 if (!(f = fopen (fname, "r")))
2359 fprintf (stderr, "cannot open peep rule file\n");
2363 while ((ch = fgetc (f)) != EOF)
2367 /* if we maxed out our local buffer */
2368 if (nch >= (MAX_PATTERN_LEN - 2))
2371 /* copy it into allocated buffer */
2374 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2375 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2379 rs = Safe_strdup (lb);
2385 /* if some charaters left over */
2389 /* copy it into allocated buffer */
2392 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2393 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2397 rs = Safe_strdup (lb);
2403 /*-----------------------------------------------------------------*/
2404 /* initPeepHole - initialises the peep hole optimizer stuff */
2405 /*-----------------------------------------------------------------*/
2411 /* read in the default rules */
2412 if (!options.nopeep)
2414 readRules (port->peep.default_rules);
2417 /* if we have any additional file read it too */
2418 if (options.peep_file)
2420 readRules (s = readFileIntoBuffer (options.peep_file));
2421 setToNull ((void *) &s);
2422 /* override nopeep setting, default rules have not been read */
2427 #if !OPT_DISABLE_PIC
2428 /* Convert the peep rules into pcode.
2429 NOTE: this is only support in the PIC port (at the moment)
2432 peepRules2pCode(rootRules);
2435 #if !OPT_DISABLE_PIC16
2436 /* Convert the peep rules into pcode.
2437 NOTE: this is only support in the PIC port (at the moment)
2438 and the PIC16 port (VR 030601)
2440 if (TARGET_IS_PIC16)
2441 pic16_peepRules2pCode(rootRules);