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 if (strcmp(p, q) == 0)
357 return FALSE; /* labels are equal */
358 /* now put the destination in %6 */
359 bindVar (6, &p, &vars);
364 /*-----------------------------------------------------------------*/
365 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
366 /* usage of it in the code depends on a value from this section */
367 /*-----------------------------------------------------------------*/
368 FBYNAME (okToRemoveSLOC)
371 const char *sloc, *p;
372 int dummy1, dummy2, dummy3;
374 /* assumes that %1 as the SLOC name */
375 sloc = hTabItemWithKey (vars, 1);
376 if (sloc == NULL) return FALSE;
377 p = strstr(sloc, "sloc");
378 if (p == NULL) return FALSE;
380 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
381 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
382 /* the sloc name begins with that. Probably not really necessary */
384 /* Look for any occurance of this SLOC before the peephole match */
385 for (pl = currPl->prev; pl; pl = pl->prev) {
386 if (pl->line && !pl->isDebug && !pl->isComment
387 && *pl->line != ';' && strstr(pl->line, sloc))
390 /* Look for any occurance of this SLOC after the peephole match */
391 for (pl = endPl->next; pl; pl = pl->next) {
392 if (pl->line && !pl->isDebug && !pl->isComment
393 && *pl->line != ';' && strstr(pl->line, sloc))
396 return TRUE; /* safe for a peephole to remove it :) */
399 /*-----------------------------------------------------------------*/
400 /* deadMove - Check, if a pop/push pair can be removed */
401 /*-----------------------------------------------------------------*/
404 const char *reg = hTabItemWithKey (vars, 1);
406 if (port->peep.deadMove)
407 return port->peep.deadMove (reg, currPl, head);
409 fprintf (stderr, "Function deadMove not initialized in port structure\n");
413 /*-----------------------------------------------------------------*/
414 /* operandsNotSame - check if %1 & %2 are the same */
415 /*-----------------------------------------------------------------*/
416 FBYNAME (operandsNotSame)
418 char *op1 = hTabItemWithKey (vars, 1);
419 char *op2 = hTabItemWithKey (vars, 2);
421 if (strcmp (op1, op2) == 0)
427 /*-----------------------------------------------------------------*/
428 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
429 /*-----------------------------------------------------------------*/
430 FBYNAME (operandsNotSame3)
432 char *op1 = hTabItemWithKey (vars, 1);
433 char *op2 = hTabItemWithKey (vars, 2);
434 char *op3 = hTabItemWithKey (vars, 3);
436 if ( (strcmp (op1, op2) == 0) ||
437 (strcmp (op1, op3) == 0) ||
438 (strcmp (op2, op3) == 0) )
444 /*-----------------------------------------------------------------*/
445 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
446 /*-----------------------------------------------------------------*/
447 FBYNAME (operandsNotSame4)
449 char *op1 = hTabItemWithKey (vars, 1);
450 char *op2 = hTabItemWithKey (vars, 2);
451 char *op3 = hTabItemWithKey (vars, 3);
452 char *op4 = hTabItemWithKey (vars, 4);
454 if ( (strcmp (op1, op2) == 0) ||
455 (strcmp (op1, op3) == 0) ||
456 (strcmp (op1, op4) == 0) ||
457 (strcmp (op2, op3) == 0) ||
458 (strcmp (op2, op4) == 0) ||
459 (strcmp (op3, op4) == 0) )
465 /*-----------------------------------------------------------------*/
466 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
467 /*-----------------------------------------------------------------*/
468 FBYNAME (operandsNotSame5)
470 char *op1 = hTabItemWithKey (vars, 1);
471 char *op2 = hTabItemWithKey (vars, 2);
472 char *op3 = hTabItemWithKey (vars, 3);
473 char *op4 = hTabItemWithKey (vars, 4);
474 char *op5 = hTabItemWithKey (vars, 5);
476 if ( (strcmp (op1, op2) == 0) ||
477 (strcmp (op1, op3) == 0) ||
478 (strcmp (op1, op4) == 0) ||
479 (strcmp (op1, op5) == 0) ||
480 (strcmp (op2, op3) == 0) ||
481 (strcmp (op2, op4) == 0) ||
482 (strcmp (op2, op5) == 0) ||
483 (strcmp (op3, op4) == 0) ||
484 (strcmp (op3, op5) == 0) ||
485 (strcmp (op4, op5) == 0) )
491 /*-----------------------------------------------------------------*/
492 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
493 /*-----------------------------------------------------------------*/
494 FBYNAME (operandsNotSame6)
496 char *op1 = hTabItemWithKey (vars, 1);
497 char *op2 = hTabItemWithKey (vars, 2);
498 char *op3 = hTabItemWithKey (vars, 3);
499 char *op4 = hTabItemWithKey (vars, 4);
500 char *op5 = hTabItemWithKey (vars, 5);
501 char *op6 = hTabItemWithKey (vars, 6);
503 if ( (strcmp (op1, op2) == 0) ||
504 (strcmp (op1, op3) == 0) ||
505 (strcmp (op1, op4) == 0) ||
506 (strcmp (op1, op5) == 0) ||
507 (strcmp (op1, op6) == 0) ||
508 (strcmp (op2, op3) == 0) ||
509 (strcmp (op2, op4) == 0) ||
510 (strcmp (op2, op5) == 0) ||
511 (strcmp (op2, op6) == 0) ||
512 (strcmp (op3, op4) == 0) ||
513 (strcmp (op3, op5) == 0) ||
514 (strcmp (op3, op6) == 0) ||
515 (strcmp (op4, op5) == 0) ||
516 (strcmp (op4, op6) == 0) ||
517 (strcmp (op5, op6) == 0) )
524 /*-----------------------------------------------------------------*/
525 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
526 /*-----------------------------------------------------------------*/
527 FBYNAME (operandsNotSame7)
529 char *op1 = hTabItemWithKey (vars, 1);
530 char *op2 = hTabItemWithKey (vars, 2);
531 char *op3 = hTabItemWithKey (vars, 3);
532 char *op4 = hTabItemWithKey (vars, 4);
533 char *op5 = hTabItemWithKey (vars, 5);
534 char *op6 = hTabItemWithKey (vars, 6);
535 char *op7 = hTabItemWithKey (vars, 7);
537 if ( (strcmp (op1, op2) == 0) ||
538 (strcmp (op1, op3) == 0) ||
539 (strcmp (op1, op4) == 0) ||
540 (strcmp (op1, op5) == 0) ||
541 (strcmp (op1, op6) == 0) ||
542 (strcmp (op1, op7) == 0) ||
543 (strcmp (op2, op3) == 0) ||
544 (strcmp (op2, op4) == 0) ||
545 (strcmp (op2, op5) == 0) ||
546 (strcmp (op2, op6) == 0) ||
547 (strcmp (op2, op7) == 0) ||
548 (strcmp (op3, op4) == 0) ||
549 (strcmp (op3, op5) == 0) ||
550 (strcmp (op3, op6) == 0) ||
551 (strcmp (op3, op7) == 0) ||
552 (strcmp (op4, op5) == 0) ||
553 (strcmp (op4, op6) == 0) ||
554 (strcmp (op4, op7) == 0) ||
555 (strcmp (op5, op6) == 0) ||
556 (strcmp (op5, op7) == 0) ||
557 (strcmp (op6, op7) == 0) )
563 /*-----------------------------------------------------------------*/
564 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
565 /*-----------------------------------------------------------------*/
566 FBYNAME (operandsNotSame8)
568 char *op1 = hTabItemWithKey (vars, 1);
569 char *op2 = hTabItemWithKey (vars, 2);
570 char *op3 = hTabItemWithKey (vars, 3);
571 char *op4 = hTabItemWithKey (vars, 4);
572 char *op5 = hTabItemWithKey (vars, 5);
573 char *op6 = hTabItemWithKey (vars, 6);
574 char *op7 = hTabItemWithKey (vars, 7);
575 char *op8 = hTabItemWithKey (vars, 8);
577 if ( (strcmp (op1, op2) == 0) ||
578 (strcmp (op1, op3) == 0) ||
579 (strcmp (op1, op4) == 0) ||
580 (strcmp (op1, op5) == 0) ||
581 (strcmp (op1, op6) == 0) ||
582 (strcmp (op1, op7) == 0) ||
583 (strcmp (op1, op8) == 0) ||
584 (strcmp (op2, op3) == 0) ||
585 (strcmp (op2, op4) == 0) ||
586 (strcmp (op2, op5) == 0) ||
587 (strcmp (op2, op6) == 0) ||
588 (strcmp (op2, op7) == 0) ||
589 (strcmp (op2, op8) == 0) ||
590 (strcmp (op3, op4) == 0) ||
591 (strcmp (op3, op5) == 0) ||
592 (strcmp (op3, op6) == 0) ||
593 (strcmp (op3, op7) == 0) ||
594 (strcmp (op3, op8) == 0) ||
595 (strcmp (op4, op5) == 0) ||
596 (strcmp (op4, op6) == 0) ||
597 (strcmp (op4, op7) == 0) ||
598 (strcmp (op4, op8) == 0) ||
599 (strcmp (op5, op6) == 0) ||
600 (strcmp (op5, op7) == 0) ||
601 (strcmp (op5, op8) == 0) ||
602 (strcmp (op6, op7) == 0) ||
603 (strcmp (op6, op8) == 0) ||
604 (strcmp (op7, op8) == 0) )
610 /*-----------------------------------------------------------------*/
611 /* labelHashEntry- searches for a label in the list labelHash */
612 /* Builds labelHash, if it does not yet exist. */
613 /* Returns the labelHashEntry or NULL */
614 /*-----------------------------------------------------------------*/
616 getLabelRef (const char *label, lineNode *head)
618 labelHashEntry *entry;
620 /* If we don't have the label hash table yet, build it. */
623 buildLabelRefCountHash (head);
626 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
630 if (!strcmp (label, entry->name))
634 entry = hTabNextItemWK (labelHash);
641 * takes two parameters: a variable (bound to a label name)
642 * and an expected reference count.
644 * Returns TRUE if that label is defined and referenced exactly
645 * the given number of times.
647 FBYNAME (labelRefCount)
649 int varNumber, expectedRefCount;
652 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
654 char *label = hTabItemWithKey (vars, varNumber);
658 labelHashEntry *entry = getLabelRef (label, head);
664 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
665 label, entry->refCount, expectedRefCount);
668 rc = (expectedRefCount == entry->refCount);
672 fprintf (stderr, "*** internal error: no label has entry for"
673 " %s in labelRefCount peephole.\n",
679 fprintf (stderr, "*** internal error: var %d not bound"
680 " in peephole labelRefCount rule.\n",
688 "*** internal error: labelRefCount peephole restriction"
689 " malformed: %s\n", cmdLine);
695 /* labelRefCountChange:
696 * takes two parameters: a variable (bound to a label name)
697 * and a signed int for changing the reference count.
699 * Please note, this function is not a conditional. It unconditionally
700 * changes the label. It should be passed as the 'last' function
701 * so it only is applied if all other conditions have been met.
703 * should always return TRUE
705 FBYNAME (labelRefCountChange)
707 int varNumber, RefCountDelta;
710 /* If we don't have the label hash table yet, build it. */
713 buildLabelRefCountHash (head);
716 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
718 char *label = hTabItemWithKey (vars, varNumber);
722 labelHashEntry *entry;
724 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
728 if (!strcmp (label, entry->name))
732 entry = hTabNextItemWK (labelHash);
736 if (0 <= entry->refCount + RefCountDelta)
738 entry->refCount += RefCountDelta;
743 fprintf (stderr, "*** internal error: label %s may not get"
744 " negative refCount in %s peephole.\n",
745 label, __FUNCTION__);
750 fprintf (stderr, "*** internal error: no label has entry for"
751 " %s in %s peephole.\n",
752 label, __FUNCTION__);
757 fprintf (stderr, "*** internal error: var %d not bound"
758 " in peephole %s rule.\n",
759 varNumber, __FUNCTION__);
765 "*** internal error: labelRefCount peephole restriction"
766 " malformed: %s\n", cmdLine);
772 /* Within the context of the lines currPl through endPl, determine
773 ** if the variable var contains a symbol that is volatile. Returns
774 ** TRUE only if it is certain that this was not volatile (the symbol
775 ** was found and not volatile, or var was a constant or CPU register).
776 ** Returns FALSE if the symbol was found and volatile, the symbol was
777 ** not found, or var was a indirect/pointer addressing mode.
780 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
782 char symname[SDCC_NAME_MAX + 1];
789 /* Can't tell if indirect accesses are volatile or not, so
790 ** assume they are, just to be safe.
792 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
797 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
799 if (strstr(var,"(bc)"))
801 if (strstr(var,"(de)"))
803 if (strstr(var,"(hl)"))
805 if (strstr(var,"(ix"))
807 if (strstr(var,"(iy"))
811 /* Extract a symbol name from the variable */
812 while (*vp && (*vp!='_'))
814 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
820 /* Nothing resembling a symbol name was found, so it can't
827 for (cl = currPl; cl!=endPl->next; cl = cl->next)
829 if (cl->ic && (cl->ic!=last_ic))
835 op = IC_COND (cl->ic);
836 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
837 return !op->isvolatile;
839 op = IC_JTCOND (cl->ic);
840 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
841 return !op->isvolatile;
843 op = IC_LEFT (cl->ic);
844 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
845 return !op->isvolatile;
846 op = IC_RIGHT (cl->ic);
847 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
848 return !op->isvolatile;
849 op = IC_RESULT (cl->ic);
850 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
851 return !op->isvolatile;
856 /* Couldn't find the symbol for some reason. Assume volatile. */
862 * This rule restriction has two different behaviours depending on
863 * the number of parameters given.
865 * if notVolatile (no parameters given)
866 * The rule is applied only if none of the iCodes originating
867 * the matched pattern reference a volatile operand.
869 * if notVolatile %1 ... (one or more parameters given)
870 * The rule is applied if the parameters are not expressions
871 * containing volatile symbols and are not pointer accesses.
874 FBYNAME (notVolatile)
885 /* If no parameters given, just scan the iCodes for volatile operands */
886 for (cl = currPl; cl!=endPl->next; cl = cl->next)
893 op = IC_COND (cl->ic);
894 if (IS_SYMOP (op) && op->isvolatile)
897 op = IC_JTCOND (cl->ic);
898 if (IS_SYMOP (op) && op->isvolatile)
901 op = IC_LEFT (cl->ic);
902 if (IS_SYMOP (op) && op->isvolatile)
904 op = IC_RIGHT (cl->ic);
905 if (IS_SYMOP (op) && op->isvolatile)
907 op = IC_RESULT (cl->ic);
908 if (IS_SYMOP (op) && op->isvolatile)
916 /* There were parameters; check the volatility of each */
917 while (*cmdLine && ISCHARSPACE(*cmdLine))
924 if (!ISCHARDIGIT(*cmdLine))
926 varNumber = strtol(cmdLine, &digitend, 10);
928 while (*cmdLine && ISCHARSPACE(*cmdLine))
931 var = hTabItemWithKey (vars, varNumber);
935 notvol = notVolatileVariable (var, currPl, endPl);
941 fprintf (stderr, "*** internal error: var %d not bound"
942 " in peephole notVolatile rule.\n",
953 "*** internal error: notVolatile peephole restriction"
954 " malformed: %s\n", cmdLine);
959 /*------------------------------------------------------------------*/
960 /* setFromConditionArgs - parse a peephole condition's arguments */
961 /* to produce a set of strings, one per argument. Variables %x will */
962 /* be replaced with their values. String literals (in single quotes)*/
963 /* are accepted and return in unquoted form. */
964 /*------------------------------------------------------------------*/
966 setFromConditionArgs (char *cmdLine, hTab * vars)
971 set *operands = NULL;
976 while (*cmdLine && ISCHARSPACE(*cmdLine))
984 if (!ISCHARDIGIT(*cmdLine))
986 varNumber = strtol(cmdLine, &digitend, 10);
989 var = hTabItemWithKey (vars, varNumber);
993 addSetHead (&operands, var);
998 else if (*cmdLine == '\'' )
1000 char quote = *cmdLine;
1003 while (*cmdLine && *cmdLine != quote)
1005 if (*cmdLine == quote)
1009 addSetHead (&operands, var);
1014 while (*cmdLine && ISCHARSPACE(*cmdLine))
1021 deleteSet (&operands);
1026 operandBaseName (const char *op)
1028 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1030 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1032 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1040 /*-------------------------------------------------------------------*/
1041 /* operandsNotRelated - returns true if the condition's operands are */
1042 /* not related (taking into account register name aliases). N-way */
1043 /* comparison performed between all operands. */
1044 /*-------------------------------------------------------------------*/
1045 FBYNAME (operandsNotRelated)
1048 const char *op1, *op2;
1050 operands = setFromConditionArgs (cmdLine, vars);
1055 "*** internal error: operandsNotRelated peephole restriction"
1056 " malformed: %s\n", cmdLine);
1060 while ((op1 = setFirstItem (operands)))
1062 deleteSetItem (&operands, (void*)op1);
1063 op1 = operandBaseName (op1);
1065 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1067 op2 = operandBaseName (op2);
1068 if (strcmp (op1, op2) == 0)
1070 deleteSet (&operands);
1076 deleteSet (&operands);
1081 /*-------------------------------------------------------------------*/
1082 /* operandsLiteral - returns true of the condition's operands are */
1084 /*-------------------------------------------------------------------*/
1085 FBYNAME (operandsLiteral)
1090 operands = setFromConditionArgs (cmdLine, vars);
1095 "*** internal error: operandsLiteral peephole restriction"
1096 " malformed: %s\n", cmdLine);
1100 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1104 deleteSet (&operands);
1109 deleteSet (&operands);
1114 /*-----------------------------------------------------------------*/
1115 /* callFuncByName - calls a function as defined in the table */
1116 /*-----------------------------------------------------------------*/
1118 callFuncByName (char *fname,
1127 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1132 "labelInRange", labelInRange
1136 "labelJTInRange", labelJTInRange
1140 "operandsNotSame", operandsNotSame
1144 "operandsNotSame3", operandsNotSame3
1148 "operandsNotSame4", operandsNotSame4
1152 "operandsNotSame5", operandsNotSame5
1156 "operandsNotSame6", operandsNotSame6
1160 "operandsNotSame7", operandsNotSame7
1164 "operandsNotSame8", operandsNotSame8
1168 "24bitMode", flat24bitMode
1172 "xramMovcOption", xramMovcOption
1176 "labelRefCount", labelRefCount
1180 "portIsDS390", portIsDS390
1183 "labelIsReturnOnly", labelIsReturnOnly
1186 "labelIsUncondJump", labelIsUncondJump
1189 "okToRemoveSLOC", okToRemoveSLOC
1192 "deadMove", deadMove
1195 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1198 "notVolatile", notVolatile
1201 "operandsNotRelated", operandsNotRelated
1204 "operandsLiteral", operandsLiteral
1207 "labelRefCountChange", labelRefCountChange
1211 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1215 /* Isolate the function name part (we are passed the full condition
1216 * string including arguments)
1218 cmdTerm = cmdCopy = Safe_strdup(fname);
1222 funcArgs = funcName = cmdTerm;
1223 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1225 *funcArgs = '\0'; /* terminate the function name */
1229 /* Find the start of the arguments */
1230 if (c == ' ' || c == '\t')
1231 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1234 /* If the arguments started with an opening parenthesis, */
1235 /* use the closing parenthesis for the end of the */
1236 /* arguments and look for the start of another condition */
1237 /* that can optionally follow. If there was no opening */
1238 /* parethesis, then everything that follows are arguments */
1239 /* and there can be no additional conditions. */
1243 while ((c = *cmdTerm) && c != ')')
1245 *cmdTerm = '\0'; /* terminate the arguments */
1249 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1255 cmdTerm = NULL; /* closing parenthesis missing */
1264 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1266 if (strcmp (ftab[i].fname, funcName) == 0)
1268 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1276 "could not find named function \"%s\" in "
1277 "peephole function table\n",
1279 // If the function couldn't be found, let's assume it's
1280 // a bad rule and refuse it.
1285 while (rc && cmdTerm);
1292 /*-----------------------------------------------------------------*/
1293 /* printLine - prints a line chain into a given file */
1294 /*-----------------------------------------------------------------*/
1296 printLine (lineNode * head, struct dbuf_s * oBuf)
1298 iCode *last_ic = NULL;
1299 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1303 if (head->ic!=last_ic)
1306 if (debug_iCode_tracking)
1309 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1310 head->ic->block, head->ic->seq);
1312 dbuf_append_str (oBuf, "; iCode lost\n");
1316 /* don't indent comments & labels */
1318 (head->isComment || head->isLabel)) {
1319 dbuf_printf (oBuf, "%s\n", head->line);
1321 if (head->isInline && *head->line=='#') {
1322 // comment out preprocessor directives in inline asm
1323 dbuf_append_char (oBuf, ';');
1325 dbuf_printf (oBuf, "\t%s\n", head->line);
1331 /*-----------------------------------------------------------------*/
1332 /* newPeepRule - creates a new peeprule and attach it to the root */
1333 /*-----------------------------------------------------------------*/
1335 newPeepRule (lineNode * match,
1342 pr = Safe_alloc ( sizeof (peepRule));
1344 pr->replace = replace;
1345 pr->restart = restart;
1349 pr->cond = Safe_strdup (cond);
1354 pr->vars = newHashTable (100);
1356 /* if root is empty */
1358 rootRules = currRule = pr;
1360 currRule = currRule->next = pr;
1365 /*-----------------------------------------------------------------*/
1366 /* newLineNode - creates a new peep line */
1367 /*-----------------------------------------------------------------*/
1369 newLineNode (const char *line)
1373 pl = Safe_alloc ( sizeof (lineNode));
1374 pl->line = Safe_strdup (line);
1379 /*-----------------------------------------------------------------*/
1380 /* connectLine - connects two lines */
1381 /*-----------------------------------------------------------------*/
1383 connectLine (lineNode * pl1, lineNode * pl2)
1387 fprintf (stderr, "trying to connect null line\n");
1397 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1398 if (!*x) { fprintf(stderr,y); return ; } }
1400 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1401 if (!*x) { fprintf(stderr,z); return ; } }
1402 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1403 if (!*x) { fprintf(stderr,z); return ; } }
1405 /*-----------------------------------------------------------------*/
1406 /* getPeepLine - parses the peep lines */
1407 /*-----------------------------------------------------------------*/
1409 getPeepLine (lineNode ** head, char **bpp)
1411 char lines[MAX_PATTERN_LEN];
1415 lineNode *currL = NULL;
1422 fprintf (stderr, "unexpected end of match pattern\n");
1429 while (ISCHARSPACE (*bp) ||
1440 /* read till end of line */
1442 while ((*bp != '\n' && *bp != '}') && *bp)
1447 while (*lp && ISCHARSPACE(*lp))
1449 isComment = (*lp == ';');
1451 if (!isComment || (isComment && !options.noPeepComments))
1457 *head = currL = newLineNode (lines);
1459 currL = connectLine (currL, newLineNode (lines));
1460 currL->isComment = isComment;
1461 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1470 /*-----------------------------------------------------------------*/
1471 /* readRules - reads the rules from a string buffer */
1472 /*-----------------------------------------------------------------*/
1474 readRules (char *bp)
1477 char lines[MAX_PATTERN_LEN];
1481 lineNode *currL = NULL;
1487 /* look for the token "replace" that is the
1489 while (*bp && strncmp (bp, "replace", 7))
1496 /* then look for either "restart" or '{' */
1497 while (strncmp (bp, "restart", 7) &&
1504 fprintf (stderr, "expected 'restart' or '{'\n");
1512 { /* must be restart */
1514 bp += strlen ("restart");
1516 EXPECT_CHR (bp, '{', "expected '{'\n");
1520 /* skip thru all the blank space */
1521 SKIP_SPACE (bp, "unexpected end of rule\n");
1523 match = replace = currL = NULL;
1524 /* we are the start of a rule */
1525 getPeepLine (&match, &bp);
1527 /* now look for by */
1528 EXPECT_STR (bp, "by", "expected 'by'\n");
1530 /* then look for a '{' */
1531 EXPECT_CHR (bp, '{', "expected '{'\n");
1534 /* save char position (needed for generating error msg) */
1537 SKIP_SPACE (bp, "unexpected end of rule\n");
1538 getPeepLine (&replace, &bp);
1540 /* look for a 'if' */
1541 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1544 if (strncmp (bp, "if", 2) == 0)
1547 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1551 fprintf (stderr, "expected condition name\n");
1555 /* look for the condition */
1557 while (*bp && (*bp != '\n'))
1563 newPeepRule (match, replace, lines, restart);
1567 if (*bp && strncmp (bp, "replace", 7))
1569 /* not the start of a new peeprule, so "if" should be here */
1574 /* go to the start of the line following "{" of the "by" token */
1575 while (*rp && (*rp == '\n'))
1578 /* copy text of rule starting with line after "by {" */
1580 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1583 /* and now the rest of the line */
1584 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1588 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1591 newPeepRule (match, replace, NULL, restart);
1597 /*-----------------------------------------------------------------*/
1598 /* keyForVar - returns the numeric key for a var */
1599 /*-----------------------------------------------------------------*/
1605 while (ISCHARDIGIT (*d))
1614 /*-----------------------------------------------------------------*/
1615 /* bindVar - binds a value to a variable in the given hashtable */
1616 /*-----------------------------------------------------------------*/
1618 bindVar (int key, char **s, hTab ** vtab)
1620 char vval[MAX_PATTERN_LEN];
1624 /* first get the value of the variable */
1626 /* the value is ended by a ',' or space or newline or null or ) */
1629 !ISCHARSPACE (*vvx) &&
1635 /* if we find a '(' then we need to balance it */
1647 // include the trailing ')'
1656 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1658 hTabAddItem (vtab, key, vvx);
1661 /*-----------------------------------------------------------------*/
1662 /* matchLine - matches one line */
1663 /*-----------------------------------------------------------------*/
1665 matchLine (char *s, char *d, hTab ** vars)
1674 /* skip white space in both */
1675 while (ISCHARSPACE (*s))
1677 while (ISCHARSPACE (*d))
1680 /* if the destination is a var */
1681 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1683 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1684 /* if the variable is already bound
1685 then it MUST match with dest */
1693 /* variable not bound we need to bind it */
1694 bindVar (keyForVar (d + 1), &s, vars);
1696 /* in either case go past the variable */
1698 while (ISCHARDIGIT (*d))
1701 while (ISCHARSPACE (*s))
1703 while (ISCHARSPACE (*d))
1707 /* they should be an exact match other wise */
1716 /* get rid of the trailing spaces
1717 in both source & destination */
1719 while (ISCHARSPACE (*s))
1723 while (ISCHARSPACE (*d))
1726 /* after all this if only one of them
1727 has something left over then no match */
1734 /*-----------------------------------------------------------------*/
1735 /* matchRule - matches a all the rule lines */
1736 /*-----------------------------------------------------------------*/
1738 matchRule (lineNode * pl,
1743 lineNode *spl; /* source pl */
1744 lineNode *rpl; /* rule peep line */
1746 /* setToNull((void *) &pr->vars); */
1747 /* pr->vars = newHashTable(100); */
1749 /* for all the lines defined in the rule */
1755 /* if the source line starts with a ';' then
1756 comment line don't process or the source line
1757 contains == . debugger information skip it */
1759 (*spl->line == ';' || spl->isDebug))
1765 if (!matchLine (spl->line, rpl->line, &pr->vars))
1773 /* if rules ended */
1776 /* if this rule has additional conditions */
1779 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1798 reassociate_ic_down (lineNode *shead, lineNode *stail,
1799 lineNode *rhead, lineNode *rtail)
1801 lineNode *csl; /* current source line */
1802 lineNode *crl; /* current replacement line */
1808 /* skip over any comments */
1809 while (csl!=stail->next && csl->isComment)
1811 while (crl!=rtail->next && crl->isComment)
1814 /* quit if we reach the end */
1815 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1818 if (matchLine(csl->line,crl->line,NULL))
1830 reassociate_ic_up (lineNode *shead, lineNode *stail,
1831 lineNode *rhead, lineNode *rtail)
1833 lineNode *csl; /* current source line */
1834 lineNode *crl; /* current replacement line */
1840 /* skip over any comments */
1841 while (csl!=shead->prev && csl->isComment)
1843 while (crl!=rhead->prev && crl->isComment)
1846 /* quit if we reach the end */
1847 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1850 if (matchLine(csl->line,crl->line,NULL))
1861 /*------------------------------------------------------------------*/
1862 /* reassociate_ic - reassociate replacement lines with origin iCode */
1863 /*------------------------------------------------------------------*/
1865 reassociate_ic (lineNode *shead, lineNode *stail,
1866 lineNode *rhead, lineNode *rtail)
1868 lineNode *csl; /* current source line */
1869 lineNode *crl; /* current replacement line */
1873 /* Check to see if all the source lines (excluding comments) came
1874 ** for the same iCode
1877 for (csl=shead;csl!=stail->next;csl=csl->next)
1878 if (csl->ic && !csl->isComment)
1883 single_iCode = (ic!=NULL);
1884 for (csl=shead;csl!=stail->next;csl=csl->next)
1885 if ((csl->ic != ic) && !csl->isComment)
1887 /* More than one iCode was found. However, if it's just the
1888 ** last line with the different iCode and it was not changed
1889 ** in the replacement, everything else must be the first iCode.
1891 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1893 rtail->ic = stail->ic;
1894 for (crl=rhead;crl!=rtail;crl=crl->next)
1899 single_iCode = FALSE;
1903 /* If all of the source lines came from the same iCode, then so have
1904 ** all of the replacement lines too.
1908 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1913 /* The source lines span iCodes, so we may end up with replacement
1914 ** lines that we don't know which iCode(s) to associate with. Do the
1915 ** best we can by using the following strategies:
1916 ** 1) Start at the top and scan down. As long as the source line
1917 ** matches the replacement line, they have the same iCode.
1918 ** 2) Start at the bottom and scan up. As long as the source line
1919 ** matches the replacement line, they have the same iCode.
1920 ** 3) For any label in the source, look for a matching label in
1921 ** the replacment. If found, they have the same iCode. From
1922 ** these matching labels, scan down for additional matching
1923 ** lines; if found, they also have the same iCode.
1926 /* Strategy #1: Start at the top and scan down for matches
1928 reassociate_ic_down(shead,stail,rhead,rtail);
1930 /* Strategy #2: Start at the bottom and scan up for matches
1932 reassociate_ic_up(shead,stail,rhead,rtail);
1934 /* Strategy #3: Try to match labels
1939 /* skip over any comments */
1940 while (csl!=stail->next && csl->isComment)
1942 if (csl==stail->next)
1947 /* found a source line label; look for it in the replacment lines */
1951 while (crl!=rtail->next && crl->isComment)
1953 if (crl==rtail->next)
1955 if (matchLine(csl->line, crl->line, NULL))
1957 reassociate_ic_down(csl,stail,crl,rtail);
1967 /* Try to assign a meaningful iCode to any comment that is missing
1968 one. Since they are comments, it's ok to make mistakes; we are just
1969 trying to improve continuity to simplify other tests.
1972 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1974 if (!crl->ic && ic && crl->isComment)
1981 /*-----------------------------------------------------------------*/
1982 /* replaceRule - does replacement of a matching pattern */
1983 /*-----------------------------------------------------------------*/
1985 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1987 lineNode *cl = NULL;
1988 lineNode *pl = NULL, *lhead = NULL;
1989 /* a long function name and long variable name can evaluate to
1990 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1991 char lb[MAX_PATTERN_LEN*4];
1993 lineNode *comment = NULL;
1995 /* collect all the comment lines in the source */
1996 for (cl = *shead; cl != stail; cl = cl->next)
1998 if (cl->line && (*cl->line == ';' || cl->isDebug))
2000 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2001 (comment = newLineNode (cl->line)));
2002 pl->isDebug = cl->isDebug;
2003 pl->isComment = cl->isComment || (*cl->line == ';');
2008 /* for all the lines in the replacement pattern do */
2009 for (pl = pr->replace; pl; pl = pl->next)
2019 /* if the line contains a variable */
2020 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2022 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2025 fprintf (stderr, "used unbound variable in replacement\n");
2033 while (ISCHARDIGIT (*l)) {
2043 cl = connectLine (cl, newLineNode (lb));
2045 lhead = cl = newLineNode (lb);
2046 cl->isComment = pl->isComment;
2047 cl->isLabel = pl->isLabel;
2050 /* add the comments if any to the head of list */
2053 lineNode *lc = comment;
2064 /* determine which iCodes the replacment lines relate to */
2065 reassociate_ic(*shead,stail,lhead,cl);
2067 /* now we need to connect / replace the original chain */
2068 /* if there is a prev then change it */
2071 (*shead)->prev->next = lhead;
2072 lhead->prev = (*shead)->prev;
2075 /* now for the tail */
2076 if (stail && stail->next)
2078 stail->next->prev = cl;
2080 cl->next = stail->next;
2085 /* the replacement is empty - delete the source lines */
2087 (*shead)->prev->next = stail->next;
2089 stail->next->prev = (*shead)->prev;
2090 *shead = stail->next;
2094 /* Returns TRUE if this line is a label definition.
2096 * If so, start will point to the start of the label name,
2097 * and len will be it's length.
2100 isLabelDefinition (const char *line, const char **start, int *len,
2103 const char *cp = line;
2105 /* This line is a label if if consists of:
2106 * [optional whitespace] followed by identifier chars
2107 * (alnum | $ | _ ) followed by a colon.
2110 while (*cp && ISCHARSPACE (*cp))
2122 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2123 (isPeepRule && (*cp == '%')))
2128 if ((cp == *start) || (*cp != ':'))
2133 *len = (cp - (*start));
2137 /* Quick & dirty string hash function. */
2139 hashSymbolName (const char *name)
2145 hash = (hash << 6) ^ *name;
2154 return hash % HTAB_SIZE;
2157 /* Build a hash of all labels in the passed set of lines
2158 * and how many times they are referenced.
2161 buildLabelRefCountHash (lineNode * head)
2168 assert (labelHash == NULL);
2169 labelHash = newHashTable (HTAB_SIZE);
2171 /* First pass: locate all the labels. */
2172 for (line = head; line; line = line->next)
2174 if (line->isLabel ||
2177 /* run isLabelDefinition to:
2178 - look for labels in inline assembler
2179 - calculate labelLen
2181 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2182 labelLen <= SDCC_NAME_MAX)
2184 labelHashEntry *entry;
2186 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2188 memcpy (entry->name, label, labelLen);
2189 entry->name[labelLen] = 0;
2190 entry->refCount = -1;
2192 /* Assume function entry points are referenced somewhere, */
2193 /* even if we can't find a reference (might be from outside */
2195 if (line->ic && (line->ic->op == FUNCTION))
2198 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2204 /* Second pass: for each line, note all the referenced labels. */
2205 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2209 for (i = 0; i < HTAB_SIZE; i++)
2211 labelHashEntry *thisEntry;
2213 thisEntry = hTabFirstItemWK (labelHash, i);
2217 if (strstr (line->line, thisEntry->name))
2219 thisEntry->refCount++;
2221 thisEntry = hTabNextItemWK (labelHash);
2228 /* Spew the contents of the table. Debugging fun only. */
2229 for (i = 0; i < HTAB_SIZE; i++)
2231 labelHashEntry *thisEntry;
2233 thisEntry = hTabFirstItemWK (labelHash, i);
2237 fprintf (stderr, "label: %s ref %d\n",
2238 thisEntry->name, thisEntry->refCount);
2239 thisEntry = hTabNextItemWK (labelHash);
2245 /* How does this work?
2251 replace and restart.
2256 Where is stuff allocated?
2260 /*-----------------------------------------------------------------*/
2261 /* peepHole - matches & substitutes rules */
2262 /*-----------------------------------------------------------------*/
2264 peepHole (lineNode ** pls)
2268 lineNode *mtail = NULL;
2269 bool restart, replaced;
2271 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2272 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2273 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2277 assert(labelHash == NULL);
2284 for (pr = rootRules; pr; pr = pr->next)
2286 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2290 /* if inline assembler then no peep hole */
2294 /* don't waste time starting a match on debug symbol
2296 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2301 /* Tidy up any data stored in the hTab */
2304 if (matchRule (spl, &mtail, pr, *pls))
2306 /* restart at the replaced line */
2312 replaceRule (pls, mtail, pr);
2316 replaceRule (&spl, mtail, pr);
2318 /* if restart rule type then
2319 start at the top again */
2328 hTabDeleteAll (pr->vars);
2329 Safe_free (pr->vars);
2333 freeTrace (&_G.values);
2336 } while (restart == TRUE);
2340 hTabDeleteAll (labelHash);
2341 freeTrace (&_G.labels);
2347 /*-----------------------------------------------------------------*/
2348 /* readFileIntoBuffer - reads a file into a string buffer */
2349 /*-----------------------------------------------------------------*/
2351 readFileIntoBuffer (char *fname)
2357 char lb[MAX_PATTERN_LEN];
2359 if (!(f = fopen (fname, "r")))
2361 fprintf (stderr, "cannot open peep rule file\n");
2365 while ((ch = fgetc (f)) != EOF)
2369 /* if we maxed out our local buffer */
2370 if (nch >= (MAX_PATTERN_LEN - 2))
2373 /* copy it into allocated buffer */
2376 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2377 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2381 rs = Safe_strdup (lb);
2387 /* if some charaters left over */
2391 /* copy it into allocated buffer */
2394 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2395 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2399 rs = Safe_strdup (lb);
2405 /*-----------------------------------------------------------------*/
2406 /* initPeepHole - initialises the peep hole optimizer stuff */
2407 /*-----------------------------------------------------------------*/
2413 /* read in the default rules */
2414 if (!options.nopeep)
2416 readRules (port->peep.default_rules);
2419 /* if we have any additional file read it too */
2420 if (options.peep_file)
2422 readRules (s = readFileIntoBuffer (options.peep_file));
2423 setToNull ((void *) &s);
2424 /* override nopeep setting, default rules have not been read */
2429 #if !OPT_DISABLE_PIC
2430 /* Convert the peep rules into pcode.
2431 NOTE: this is only support in the PIC port (at the moment)
2434 peepRules2pCode(rootRules);
2437 #if !OPT_DISABLE_PIC16
2438 /* Convert the peep rules into pcode.
2439 NOTE: this is only support in the PIC port (at the moment)
2440 and the PIC16 port (VR 030601)
2442 if (TARGET_IS_PIC16)
2443 pic16_peepRules2pCode(rootRules);