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 /* portIsDS390 - return true if port is DS390 */
103 /*-----------------------------------------------------------------*/
104 FBYNAME (portIsDS390)
106 return ((strcmp(port->target,"ds390") == 0) ||
107 (strcmp(port->target,"ds400") == 0));
110 /*-----------------------------------------------------------------*/
111 /* flat24bitMode - will check to see if we are in flat24 mode */
112 /*-----------------------------------------------------------------*/
113 FBYNAME (flat24bitMode)
115 return (options.model == MODEL_FLAT24);
118 /*-----------------------------------------------------------------*/
119 /* xramMovcOption - check if using movc to read xram */
120 /*-----------------------------------------------------------------*/
121 FBYNAME (xramMovcOption)
123 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
126 /*-----------------------------------------------------------------*/
127 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
128 /*-----------------------------------------------------------------*/
129 FBYNAME (useAcallAjmp)
131 return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
134 /*-----------------------------------------------------------------*/
135 /* labelInRange - will check to see if label %5 is within range */
136 /*-----------------------------------------------------------------*/
137 FBYNAME (labelInRange)
139 /* assumes that %5 pattern variable has the label name */
140 char *lbl = hTabItemWithKey (vars, 5);
146 /* Don't optimize jumps in a jump table; a more generic test */
147 if (currPl->ic && currPl->ic->op == JUMPTABLE)
150 /* if the previous two instructions are "ljmp"s then don't
151 do it since it can be part of a jump table */
152 if (currPl->prev && currPl->prev->prev &&
153 strstr (currPl->prev->line, "ljmp") &&
154 strstr (currPl->prev->prev->line, "ljmp"))
157 /* calculate the label distance : the jump for reladdr can be
158 +/- 127 bytes, here Iam assuming that an average 8051
159 instruction is 2 bytes long, so if the label is more than
160 63 intructions away, the label is considered out of range
161 for a relative jump. we could get more precise this will
162 suffice for now since it catches > 90% cases */
163 dist = (pcDistance (currPl, lbl, TRUE) +
164 pcDistance (currPl, lbl, FALSE));
166 /* changed to 127, now that pcDistance return actual number of bytes */
167 if (!dist || dist > 127)
173 /*-----------------------------------------------------------------*/
174 /* labelJTInRange - will check to see if label %5 and up are */
176 /* Specifically meant to optimize long (3-byte) jumps to short */
177 /* (2-byte) jumps in jumptables */
178 /*-----------------------------------------------------------------*/
179 FBYNAME (labelJTInRange)
184 if (!getenv("SDCC_SJMP_JUMPTABLE"))
187 /* Only optimize within a jump table */
188 if (currPl->ic && currPl->ic->op != JUMPTABLE)
191 count = elementsInSet( IC_JTLABELS (currPl->ic) );
193 /* check all labels (this is needed if the case statements are unsorted) */
194 for (i=0; i<count; i++)
196 /* assumes that the %5 pattern variable has the first ljmp label */
197 lbl = hTabItemWithKey (vars, 5+i);
201 dist = pcDistance (currPl, lbl, FALSE);
203 /* three terms used to calculate allowable distance */
204 // 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);
206 dist > 127+ /* range of sjmp */
207 (7+3*i)+ /* offset between this jump and currPl,
208 should use pcDistance instead? */
209 (count-i-1) /* if peephole applies distance is shortened */
216 /*-----------------------------------------------------------------*/
217 /* labelIsReturnOnly - Check if label %5 is followed by RET */
218 /*-----------------------------------------------------------------*/
219 FBYNAME (labelIsReturnOnly)
221 /* assumes that %5 pattern variable has the label name */
222 const char *label, *p;
227 /* Don't optimize jumps in a jump table; a more generic test */
228 if (currPl->ic && currPl->ic->op == JUMPTABLE)
231 label = hTabItemWithKey (vars, 5);
236 for(pl = currPl; pl; pl = pl->next)
238 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
240 if (strncmp(pl->line, label, len) == 0)
241 break; /* Found Label */
242 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
243 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
244 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
245 *(pl->line+5) != '$')
247 return FALSE; /* non-local label encountered */
252 return FALSE; /* did not find the label */
254 while (pl && (pl->isDebug || pl->isComment))
256 if (!pl || !pl->line || pl->isDebug)
257 return FALSE; /* next line not valid */
259 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
265 if (strcmp(p, retInst) == 0)
270 /*-----------------------------------------------------------------*/
271 /* labelIsUncondJump - Check if label %5 is followed by an */
272 /* unconditional jump and put the destination of that jump in %6 */
273 /*-----------------------------------------------------------------*/
274 FBYNAME (labelIsUncondJump)
276 /* assumes that %5 pattern variable has the label name */
281 char * jpInst = NULL;
283 /* Don't optimize jumps in a jump table; a more generic test */
284 if (currPl->ic && currPl->ic->op == JUMPTABLE)
287 label = hTabItemWithKey (vars, 5);
292 for (pl = currPl; pl; pl = pl->next)
294 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
296 if (strncmp(pl->line, label, len) == 0)
297 break; /* Found Label */
298 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
299 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
300 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
301 *(pl->line+5) != '$')
303 return FALSE; /* non-local label encountered */
308 return FALSE; /* did not find the label */
310 while (pl && (pl->isDebug || pl->isComment))
312 if (!pl || !pl->line)
313 return FALSE; /* next line not valid */
315 while (*p && ISCHARSPACE(*p))
318 if (TARGET_MCS51_LIKE)
324 len = strlen(jpInst);
325 if (strncmp(p, jpInst, len) != 0)
326 return FALSE; /* next line is no jump */
328 while (*p && ISCHARSPACE(*p))
332 while (*q && *q!=';')
334 while (q>p && ISCHARSPACE(*q))
338 return FALSE; /* no destination? */
341 while (q>p && *q!=',')
344 return FALSE; /* conditional jump */
346 if (strcmp(p, q) == 0)
347 return FALSE; /* labels are equal */
348 /* now put the destination in %6 */
349 bindVar (6, &p, &vars);
353 /*-----------------------------------------------------------------*/
354 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
355 /* usage of it in the code depends on a value from this section */
356 /*-----------------------------------------------------------------*/
357 FBYNAME (okToRemoveSLOC)
360 const char *sloc, *p;
361 int dummy1, dummy2, dummy3;
363 /* assumes that %1 as the SLOC name */
364 sloc = hTabItemWithKey (vars, 1);
365 if (sloc == NULL) return FALSE;
366 p = strstr(sloc, "sloc");
367 if (p == NULL) return FALSE;
369 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
370 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
371 /* the sloc name begins with that. Probably not really necessary */
373 /* Look for any occurance of this SLOC before the peephole match */
374 for (pl = currPl->prev; pl; pl = pl->prev) {
375 if (pl->line && !pl->isDebug && !pl->isComment
376 && *pl->line != ';' && strstr(pl->line, sloc))
379 /* Look for any occurance of this SLOC after the peephole match */
380 for (pl = endPl->next; pl; pl = pl->next) {
381 if (pl->line && !pl->isDebug && !pl->isComment
382 && *pl->line != ';' && strstr(pl->line, sloc))
385 return TRUE; /* safe for a peephole to remove it :) */
388 /*-----------------------------------------------------------------*/
389 /* deadMove - Check, if a pop/push pair can be removed */
390 /*-----------------------------------------------------------------*/
393 const char *reg = hTabItemWithKey (vars, 1);
395 if (port->peep.deadMove)
396 return port->peep.deadMove (reg, currPl, head);
398 fprintf (stderr, "Function deadMove not initialized in port structure\n");
402 /*-----------------------------------------------------------------*/
403 /* operandsNotSame - check if %1 & %2 are the same */
404 /*-----------------------------------------------------------------*/
405 FBYNAME (operandsNotSame)
407 char *op1 = hTabItemWithKey (vars, 1);
408 char *op2 = hTabItemWithKey (vars, 2);
410 if (strcmp (op1, op2) == 0)
416 /*-----------------------------------------------------------------*/
417 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
418 /*-----------------------------------------------------------------*/
419 FBYNAME (operandsNotSame3)
421 char *op1 = hTabItemWithKey (vars, 1);
422 char *op2 = hTabItemWithKey (vars, 2);
423 char *op3 = hTabItemWithKey (vars, 3);
425 if ( (strcmp (op1, op2) == 0) ||
426 (strcmp (op1, op3) == 0) ||
427 (strcmp (op2, op3) == 0) )
433 /*-----------------------------------------------------------------*/
434 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
435 /*-----------------------------------------------------------------*/
436 FBYNAME (operandsNotSame4)
438 char *op1 = hTabItemWithKey (vars, 1);
439 char *op2 = hTabItemWithKey (vars, 2);
440 char *op3 = hTabItemWithKey (vars, 3);
441 char *op4 = hTabItemWithKey (vars, 4);
443 if ( (strcmp (op1, op2) == 0) ||
444 (strcmp (op1, op3) == 0) ||
445 (strcmp (op1, op4) == 0) ||
446 (strcmp (op2, op3) == 0) ||
447 (strcmp (op2, op4) == 0) ||
448 (strcmp (op3, op4) == 0) )
454 /*-----------------------------------------------------------------*/
455 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
456 /*-----------------------------------------------------------------*/
457 FBYNAME (operandsNotSame5)
459 char *op1 = hTabItemWithKey (vars, 1);
460 char *op2 = hTabItemWithKey (vars, 2);
461 char *op3 = hTabItemWithKey (vars, 3);
462 char *op4 = hTabItemWithKey (vars, 4);
463 char *op5 = hTabItemWithKey (vars, 5);
465 if ( (strcmp (op1, op2) == 0) ||
466 (strcmp (op1, op3) == 0) ||
467 (strcmp (op1, op4) == 0) ||
468 (strcmp (op1, op5) == 0) ||
469 (strcmp (op2, op3) == 0) ||
470 (strcmp (op2, op4) == 0) ||
471 (strcmp (op2, op5) == 0) ||
472 (strcmp (op3, op4) == 0) ||
473 (strcmp (op3, op5) == 0) ||
474 (strcmp (op4, op5) == 0) )
480 /*-----------------------------------------------------------------*/
481 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
482 /*-----------------------------------------------------------------*/
483 FBYNAME (operandsNotSame6)
485 char *op1 = hTabItemWithKey (vars, 1);
486 char *op2 = hTabItemWithKey (vars, 2);
487 char *op3 = hTabItemWithKey (vars, 3);
488 char *op4 = hTabItemWithKey (vars, 4);
489 char *op5 = hTabItemWithKey (vars, 5);
490 char *op6 = hTabItemWithKey (vars, 6);
492 if ( (strcmp (op1, op2) == 0) ||
493 (strcmp (op1, op3) == 0) ||
494 (strcmp (op1, op4) == 0) ||
495 (strcmp (op1, op5) == 0) ||
496 (strcmp (op1, op6) == 0) ||
497 (strcmp (op2, op3) == 0) ||
498 (strcmp (op2, op4) == 0) ||
499 (strcmp (op2, op5) == 0) ||
500 (strcmp (op2, op6) == 0) ||
501 (strcmp (op3, op4) == 0) ||
502 (strcmp (op3, op5) == 0) ||
503 (strcmp (op3, op6) == 0) ||
504 (strcmp (op4, op5) == 0) ||
505 (strcmp (op4, op6) == 0) ||
506 (strcmp (op5, op6) == 0) )
512 /*-----------------------------------------------------------------*/
513 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
514 /*-----------------------------------------------------------------*/
515 FBYNAME (operandsNotSame7)
517 char *op1 = hTabItemWithKey (vars, 1);
518 char *op2 = hTabItemWithKey (vars, 2);
519 char *op3 = hTabItemWithKey (vars, 3);
520 char *op4 = hTabItemWithKey (vars, 4);
521 char *op5 = hTabItemWithKey (vars, 5);
522 char *op6 = hTabItemWithKey (vars, 6);
523 char *op7 = hTabItemWithKey (vars, 7);
525 if ( (strcmp (op1, op2) == 0) ||
526 (strcmp (op1, op3) == 0) ||
527 (strcmp (op1, op4) == 0) ||
528 (strcmp (op1, op5) == 0) ||
529 (strcmp (op1, op6) == 0) ||
530 (strcmp (op1, op7) == 0) ||
531 (strcmp (op2, op3) == 0) ||
532 (strcmp (op2, op4) == 0) ||
533 (strcmp (op2, op5) == 0) ||
534 (strcmp (op2, op6) == 0) ||
535 (strcmp (op2, op7) == 0) ||
536 (strcmp (op3, op4) == 0) ||
537 (strcmp (op3, op5) == 0) ||
538 (strcmp (op3, op6) == 0) ||
539 (strcmp (op3, op7) == 0) ||
540 (strcmp (op4, op5) == 0) ||
541 (strcmp (op4, op6) == 0) ||
542 (strcmp (op4, op7) == 0) ||
543 (strcmp (op5, op6) == 0) ||
544 (strcmp (op5, op7) == 0) ||
545 (strcmp (op6, op7) == 0) )
551 /*-----------------------------------------------------------------*/
552 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
553 /*-----------------------------------------------------------------*/
554 FBYNAME (operandsNotSame8)
556 char *op1 = hTabItemWithKey (vars, 1);
557 char *op2 = hTabItemWithKey (vars, 2);
558 char *op3 = hTabItemWithKey (vars, 3);
559 char *op4 = hTabItemWithKey (vars, 4);
560 char *op5 = hTabItemWithKey (vars, 5);
561 char *op6 = hTabItemWithKey (vars, 6);
562 char *op7 = hTabItemWithKey (vars, 7);
563 char *op8 = hTabItemWithKey (vars, 8);
565 if ( (strcmp (op1, op2) == 0) ||
566 (strcmp (op1, op3) == 0) ||
567 (strcmp (op1, op4) == 0) ||
568 (strcmp (op1, op5) == 0) ||
569 (strcmp (op1, op6) == 0) ||
570 (strcmp (op1, op7) == 0) ||
571 (strcmp (op1, op8) == 0) ||
572 (strcmp (op2, op3) == 0) ||
573 (strcmp (op2, op4) == 0) ||
574 (strcmp (op2, op5) == 0) ||
575 (strcmp (op2, op6) == 0) ||
576 (strcmp (op2, op7) == 0) ||
577 (strcmp (op2, op8) == 0) ||
578 (strcmp (op3, op4) == 0) ||
579 (strcmp (op3, op5) == 0) ||
580 (strcmp (op3, op6) == 0) ||
581 (strcmp (op3, op7) == 0) ||
582 (strcmp (op3, op8) == 0) ||
583 (strcmp (op4, op5) == 0) ||
584 (strcmp (op4, op6) == 0) ||
585 (strcmp (op4, op7) == 0) ||
586 (strcmp (op4, op8) == 0) ||
587 (strcmp (op5, op6) == 0) ||
588 (strcmp (op5, op7) == 0) ||
589 (strcmp (op5, op8) == 0) ||
590 (strcmp (op6, op7) == 0) ||
591 (strcmp (op6, op8) == 0) ||
592 (strcmp (op7, op8) == 0) )
598 /*-----------------------------------------------------------------*/
599 /* labelHashEntry- searches for a label in the list labelHash */
600 /* Builds labelHash, if it does not yet exist. */
601 /* Returns the labelHashEntry or NULL */
602 /*-----------------------------------------------------------------*/
604 getLabelRef (const char *label, lineNode *head)
606 labelHashEntry *entry;
608 /* If we don't have the label hash table yet, build it. */
611 buildLabelRefCountHash (head);
614 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
618 if (!strcmp (label, entry->name))
622 entry = hTabNextItemWK (labelHash);
629 * takes two parameters: a variable (bound to a label name)
630 * and an expected reference count.
632 * Returns TRUE if that label is defined and referenced exactly
633 * the given number of times.
635 FBYNAME (labelRefCount)
637 int varNumber, expectedRefCount;
640 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
642 char *label = hTabItemWithKey (vars, varNumber);
646 labelHashEntry *entry = getLabelRef (label, head);
652 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
653 label, entry->refCount, expectedRefCount);
656 rc = (expectedRefCount == entry->refCount);
660 fprintf (stderr, "*** internal error: no label has entry for"
661 " %s in labelRefCount peephole.\n",
667 fprintf (stderr, "*** internal error: var %d not bound"
668 " in peephole labelRefCount rule.\n",
676 "*** internal error: labelRefCount peephole restriction"
677 " malformed: %s\n", cmdLine);
682 /* labelRefCountChange:
683 * takes two parameters: a variable (bound to a label name)
684 * and a signed int for changing the reference count.
686 * Please note, this function is not a conditional. It unconditionally
687 * changes the label. It should be passed as the 'last' function
688 * so it only is applied if all other conditions have been met.
690 * should always return TRUE
692 FBYNAME (labelRefCountChange)
694 int varNumber, RefCountDelta;
697 /* If we don't have the label hash table yet, build it. */
700 buildLabelRefCountHash (head);
703 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
705 char *label = hTabItemWithKey (vars, varNumber);
709 labelHashEntry *entry;
711 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
715 if (!strcmp (label, entry->name))
719 entry = hTabNextItemWK (labelHash);
723 if (0 <= entry->refCount + RefCountDelta)
725 entry->refCount += RefCountDelta;
730 fprintf (stderr, "*** internal error: label %s may not get"
731 " negative refCount in %s peephole.\n",
732 label, __FUNCTION__);
737 fprintf (stderr, "*** internal error: no label has entry for"
738 " %s in %s peephole.\n",
739 label, __FUNCTION__);
744 fprintf (stderr, "*** internal error: var %d not bound"
745 " in peephole %s rule.\n",
746 varNumber, __FUNCTION__);
752 "*** internal error: labelRefCount peephole restriction"
753 " malformed: %s\n", cmdLine);
758 /* Within the context of the lines currPl through endPl, determine
759 ** if the variable var contains a symbol that is volatile. Returns
760 ** TRUE only if it is certain that this was not volatile (the symbol
761 ** was found and not volatile, or var was a constant or CPU register).
762 ** Returns FALSE if the symbol was found and volatile, the symbol was
763 ** not found, or var was a indirect/pointer addressing mode.
766 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
768 char symname[SDCC_NAME_MAX + 1];
775 /* Can't tell if indirect accesses are volatile or not, so
776 ** assume they are, just to be safe.
778 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
783 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
785 if (strstr(var,"(bc)"))
787 if (strstr(var,"(de)"))
789 if (strstr(var,"(hl)"))
791 if (strstr(var,"(ix"))
793 if (strstr(var,"(iy"))
797 /* Extract a symbol name from the variable */
798 while (*vp && (*vp!='_'))
800 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
806 /* Nothing resembling a symbol name was found, so it can't
813 for (cl = currPl; cl!=endPl->next; cl = cl->next)
815 if (cl->ic && (cl->ic!=last_ic))
821 op = IC_COND (cl->ic);
823 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
824 (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
826 return !op->isvolatile;
829 op = IC_JTCOND (cl->ic);
831 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
832 (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
834 return !op->isvolatile;
837 op = IC_LEFT (cl->ic);
839 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
840 (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
842 return !op->isvolatile;
844 op = IC_RIGHT (cl->ic);
846 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
847 (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
849 return !op->isvolatile;
851 op = IC_RESULT (cl->ic);
853 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
854 (OP_SYMBOL (op)->isspilt && !strcmp(SPIL_LOC (op)->rname, symname)) ))
856 return !op->isvolatile;
862 /* Couldn't find the symbol for some reason. Assume volatile. */
868 * This rule restriction has two different behaviours depending on
869 * the number of parameters given.
871 * if notVolatile (no parameters given)
872 * The rule is applied only if none of the iCodes originating
873 * the matched pattern reference a volatile operand.
875 * if notVolatile %1 ... (one or more parameters given)
876 * The rule is applied if the parameters are not expressions
877 * containing volatile symbols and are not pointer accesses.
880 FBYNAME (notVolatile)
891 /* If no parameters given, just scan the iCodes for volatile operands */
892 for (cl = currPl; cl!=endPl->next; cl = cl->next)
899 op = IC_COND (cl->ic);
900 if (IS_SYMOP (op) && op->isvolatile)
903 op = IC_JTCOND (cl->ic);
904 if (IS_SYMOP (op) && op->isvolatile)
907 op = IC_LEFT (cl->ic);
908 if (IS_SYMOP (op) && op->isvolatile)
910 op = IC_RIGHT (cl->ic);
911 if (IS_SYMOP (op) && op->isvolatile)
913 op = IC_RESULT (cl->ic);
914 if (IS_SYMOP (op) && op->isvolatile)
922 /* There were parameters; check the volatility of each */
923 while (*cmdLine && ISCHARSPACE(*cmdLine))
930 if (!ISCHARDIGIT(*cmdLine))
932 varNumber = strtol(cmdLine, &digitend, 10);
934 while (*cmdLine && ISCHARSPACE(*cmdLine))
937 var = hTabItemWithKey (vars, varNumber);
941 notvol = notVolatileVariable (var, currPl, endPl);
947 fprintf (stderr, "*** internal error: var %d not bound"
948 " in peephole notVolatile rule.\n",
958 "*** internal error: notVolatile peephole restriction"
959 " malformed: %s\n", cmdLine);
963 /*------------------------------------------------------------------*/
964 /* setFromConditionArgs - parse a peephole condition's arguments */
965 /* to produce a set of strings, one per argument. Variables %x will */
966 /* be replaced with their values. String literals (in single quotes)*/
967 /* are accepted and return in unquoted form. */
968 /*------------------------------------------------------------------*/
970 setFromConditionArgs (char *cmdLine, hTab * vars)
975 set *operands = NULL;
980 while (*cmdLine && ISCHARSPACE(*cmdLine))
988 if (!ISCHARDIGIT(*cmdLine))
990 varNumber = strtol(cmdLine, &digitend, 10);
993 var = hTabItemWithKey (vars, varNumber);
997 addSetHead (&operands, var);
1002 else if (*cmdLine == '\'' )
1004 char quote = *cmdLine;
1007 while (*cmdLine && *cmdLine != quote)
1009 if (*cmdLine == quote)
1013 addSetHead (&operands, var);
1018 while (*cmdLine && ISCHARSPACE(*cmdLine))
1025 deleteSet (&operands);
1030 operandBaseName (const char *op)
1032 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1034 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1036 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1043 /*-------------------------------------------------------------------*/
1044 /* operandsNotRelated - returns true if the condition's operands are */
1045 /* not related (taking into account register name aliases). N-way */
1046 /* comparison performed between all operands. */
1047 /*-------------------------------------------------------------------*/
1048 FBYNAME (operandsNotRelated)
1051 const char *op1, *op2;
1053 operands = setFromConditionArgs (cmdLine, vars);
1058 "*** internal error: operandsNotRelated peephole restriction"
1059 " malformed: %s\n", cmdLine);
1063 while ((op1 = setFirstItem (operands)))
1065 deleteSetItem (&operands, (void*)op1);
1066 op1 = operandBaseName (op1);
1068 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1070 op2 = operandBaseName (op2);
1071 if (strcmp (op1, op2) == 0)
1073 deleteSet (&operands);
1079 deleteSet (&operands);
1083 /*-------------------------------------------------------------------*/
1084 /* operandsLiteral - returns true of the condition's operands are */
1086 /*-------------------------------------------------------------------*/
1087 FBYNAME (operandsLiteral)
1092 operands = setFromConditionArgs (cmdLine, vars);
1097 "*** internal error: operandsLiteral peephole restriction"
1098 " malformed: %s\n", cmdLine);
1102 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1106 deleteSet (&operands);
1111 deleteSet (&operands);
1115 static const struct ftab
1118 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1120 ftab[] = // sorted on the number of times used
1121 { // in the peephole rules on 2007-10-29
1123 "labelRefCount", labelRefCount //105
1126 "notVolatile", notVolatile //85
1129 "labelRefCountChange", labelRefCountChange //74
1132 "labelInRange", labelInRange //37
1135 "labelJTInRange", labelJTInRange //13
1138 "operandsNotRelated", operandsNotRelated //9
1141 "24bitMode", flat24bitMode //9
1144 "operandsNotSame", operandsNotSame //8
1147 "operandsNotSame3", operandsNotSame3
1150 "operandsNotSame4", operandsNotSame4
1153 "operandsNotSame5", operandsNotSame5
1156 "operandsNotSame6", operandsNotSame6
1159 "operandsNotSame7", operandsNotSame7
1162 "operandsNotSame8", operandsNotSame8
1165 "xramMovcOption", xramMovcOption
1168 "portIsDS390", portIsDS390
1171 "labelIsReturnOnly", labelIsReturnOnly
1174 "labelIsUncondJump", labelIsUncondJump
1177 "okToRemoveSLOC", okToRemoveSLOC
1180 "deadMove", deadMove
1183 "operandsLiteral", operandsLiteral
1186 "useAcallAjmp", useAcallAjmp
1189 /*-----------------------------------------------------------------*/
1190 /* callFuncByName - calls a function as defined in the table */
1191 /*-----------------------------------------------------------------*/
1193 callFuncByName (char *fname,
1200 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1204 /* Isolate the function name part (we are passed the full condition
1205 * string including arguments)
1207 cmdTerm = cmdCopy = Safe_strdup(fname);
1211 funcArgs = funcName = cmdTerm;
1212 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1214 *funcArgs = '\0'; /* terminate the function name */
1218 /* Find the start of the arguments */
1219 if (c == ' ' || c == '\t')
1220 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1223 /* If the arguments started with an opening parenthesis, */
1224 /* use the closing parenthesis for the end of the */
1225 /* arguments and look for the start of another condition */
1226 /* that can optionally follow. If there was no opening */
1227 /* parethesis, then everything that follows are arguments */
1228 /* and there can be no additional conditions. */
1232 while ((c = *cmdTerm) && c != ')')
1234 *cmdTerm = '\0'; /* terminate the arguments */
1238 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1244 cmdTerm = NULL; /* closing parenthesis missing */
1253 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1255 if (strcmp (ftab[i].fname, funcName) == 0)
1257 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1265 "could not find named function \"%s\" in "
1266 "peephole function table\n",
1268 // If the function couldn't be found, let's assume it's
1269 // a bad rule and refuse it.
1274 while (rc && cmdTerm);
1281 /*-----------------------------------------------------------------*/
1282 /* printLine - prints a line chain into a given file */
1283 /*-----------------------------------------------------------------*/
1285 printLine (lineNode * head, struct dbuf_s * oBuf)
1287 iCode *last_ic = NULL;
1288 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1292 if (head->ic!=last_ic)
1295 if (debug_iCode_tracking)
1298 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1299 head->ic->block, head->ic->seq);
1301 dbuf_append_str (oBuf, "; iCode lost\n");
1305 /* don't indent comments & labels */
1307 (head->isComment || head->isLabel)) {
1308 dbuf_printf (oBuf, "%s\n", head->line);
1310 if (head->isInline && *head->line=='#') {
1311 // comment out preprocessor directives in inline asm
1312 dbuf_append_char (oBuf, ';');
1314 dbuf_printf (oBuf, "\t%s\n", head->line);
1320 /*-----------------------------------------------------------------*/
1321 /* newPeepRule - creates a new peeprule and attach it to the root */
1322 /*-----------------------------------------------------------------*/
1324 newPeepRule (lineNode * match,
1331 pr = Safe_alloc ( sizeof (peepRule));
1333 pr->replace = replace;
1334 pr->restart = restart;
1338 pr->cond = Safe_strdup (cond);
1343 pr->vars = newHashTable (100);
1345 /* if root is empty */
1347 rootRules = currRule = pr;
1349 currRule = currRule->next = pr;
1354 /*-----------------------------------------------------------------*/
1355 /* newLineNode - creates a new peep line */
1356 /*-----------------------------------------------------------------*/
1358 newLineNode (const char *line)
1362 pl = Safe_alloc ( sizeof (lineNode));
1363 pl->line = Safe_strdup (line);
1368 /*-----------------------------------------------------------------*/
1369 /* connectLine - connects two lines */
1370 /*-----------------------------------------------------------------*/
1372 connectLine (lineNode * pl1, lineNode * pl2)
1376 fprintf (stderr, "trying to connect null line\n");
1386 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1387 if (!*x) { fprintf(stderr,y); return ; } }
1389 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1390 if (!*x) { fprintf(stderr,z); return ; } }
1391 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1392 if (!*x) { fprintf(stderr,z); return ; } }
1394 /*-----------------------------------------------------------------*/
1395 /* getPeepLine - parses the peep lines */
1396 /*-----------------------------------------------------------------*/
1398 getPeepLine (lineNode ** head, char **bpp)
1400 char lines[MAX_PATTERN_LEN];
1404 lineNode *currL = NULL;
1411 fprintf (stderr, "unexpected end of match pattern\n");
1418 while (ISCHARSPACE (*bp) ||
1429 /* read till end of line */
1431 while ((*bp != '\n' && *bp != '}') && *bp)
1436 while (*lp && ISCHARSPACE(*lp))
1438 isComment = (*lp == ';');
1440 if (!isComment || (isComment && !options.noPeepComments))
1446 *head = currL = newLineNode (lines);
1448 currL = connectLine (currL, newLineNode (lines));
1449 currL->isComment = isComment;
1450 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1459 /*-----------------------------------------------------------------*/
1460 /* readRules - reads the rules from a string buffer */
1461 /*-----------------------------------------------------------------*/
1463 readRules (char *bp)
1466 char lines[MAX_PATTERN_LEN];
1470 lineNode *currL = NULL;
1476 /* look for the token "replace" that is the
1478 while (*bp && strncmp (bp, "replace", 7))
1485 /* then look for either "restart" or '{' */
1486 while (strncmp (bp, "restart", 7) &&
1493 fprintf (stderr, "expected 'restart' or '{'\n");
1501 { /* must be restart */
1503 bp += strlen ("restart");
1505 EXPECT_CHR (bp, '{', "expected '{'\n");
1509 /* skip thru all the blank space */
1510 SKIP_SPACE (bp, "unexpected end of rule\n");
1512 match = replace = currL = NULL;
1513 /* we are the start of a rule */
1514 getPeepLine (&match, &bp);
1516 /* now look for by */
1517 EXPECT_STR (bp, "by", "expected 'by'\n");
1519 /* then look for a '{' */
1520 EXPECT_CHR (bp, '{', "expected '{'\n");
1523 /* save char position (needed for generating error msg) */
1526 SKIP_SPACE (bp, "unexpected end of rule\n");
1527 getPeepLine (&replace, &bp);
1529 /* look for a 'if' */
1530 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1533 if (strncmp (bp, "if", 2) == 0)
1536 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1540 fprintf (stderr, "expected condition name\n");
1544 /* look for the condition */
1546 while (*bp && (*bp != '\n'))
1552 newPeepRule (match, replace, lines, restart);
1556 if (*bp && strncmp (bp, "replace", 7))
1558 /* not the start of a new peeprule, so "if" should be here */
1563 /* go to the start of the line following "{" of the "by" token */
1564 while (*rp && (*rp == '\n'))
1567 /* copy text of rule starting with line after "by {" */
1569 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1572 /* and now the rest of the line */
1573 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1577 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1580 newPeepRule (match, replace, NULL, restart);
1586 /*-----------------------------------------------------------------*/
1587 /* keyForVar - returns the numeric key for a var */
1588 /*-----------------------------------------------------------------*/
1594 while (ISCHARDIGIT (*d))
1603 /*-----------------------------------------------------------------*/
1604 /* bindVar - binds a value to a variable in the given hashtable */
1605 /*-----------------------------------------------------------------*/
1607 bindVar (int key, char **s, hTab ** vtab)
1609 char vval[MAX_PATTERN_LEN];
1613 /* first get the value of the variable */
1615 /* the value is ended by a ',' or space or newline or null or ) */
1618 !ISCHARSPACE (*vvx) &&
1624 /* if we find a '(' then we need to balance it */
1636 // include the trailing ')'
1645 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1647 hTabAddItem (vtab, key, vvx);
1650 /*-----------------------------------------------------------------*/
1651 /* matchLine - matches one line */
1652 /*-----------------------------------------------------------------*/
1654 matchLine (char *s, char *d, hTab ** vars)
1663 /* skip white space in both */
1664 while (ISCHARSPACE (*s))
1666 while (ISCHARSPACE (*d))
1669 /* if the destination is a var */
1670 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1672 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1673 /* if the variable is already bound
1674 then it MUST match with dest */
1682 /* variable not bound we need to bind it */
1683 bindVar (keyForVar (d + 1), &s, vars);
1685 /* in either case go past the variable */
1687 while (ISCHARDIGIT (*d))
1690 while (ISCHARSPACE (*s))
1692 while (ISCHARSPACE (*d))
1696 /* they should be an exact match other wise */
1705 /* get rid of the trailing spaces
1706 in both source & destination */
1708 while (ISCHARSPACE (*s))
1712 while (ISCHARSPACE (*d))
1715 /* after all this if only one of them
1716 has something left over then no match */
1723 /*-----------------------------------------------------------------*/
1724 /* matchRule - matches a all the rule lines */
1725 /*-----------------------------------------------------------------*/
1727 matchRule (lineNode * pl,
1732 lineNode *spl; /* source pl */
1733 lineNode *rpl; /* rule peep line */
1735 /* setToNull((void *) &pr->vars); */
1736 /* pr->vars = newHashTable(100); */
1738 /* for all the lines defined in the rule */
1744 /* if the source line starts with a ';' then
1745 comment line don't process or the source line
1746 contains == . debugger information skip it */
1748 (*spl->line == ';' || spl->isDebug))
1754 if (!matchLine (spl->line, rpl->line, &pr->vars))
1762 /* if rules ended */
1765 /* if this rule has additional conditions */
1768 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1787 reassociate_ic_down (lineNode *shead, lineNode *stail,
1788 lineNode *rhead, lineNode *rtail)
1790 lineNode *csl; /* current source line */
1791 lineNode *crl; /* current replacement line */
1797 /* skip over any comments */
1798 while (csl!=stail->next && csl->isComment)
1800 while (crl!=rtail->next && crl->isComment)
1803 /* quit if we reach the end */
1804 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1807 if (matchLine(csl->line,crl->line,NULL))
1819 reassociate_ic_up (lineNode *shead, lineNode *stail,
1820 lineNode *rhead, lineNode *rtail)
1822 lineNode *csl; /* current source line */
1823 lineNode *crl; /* current replacement line */
1829 /* skip over any comments */
1830 while (csl!=shead->prev && csl->isComment)
1832 while (crl!=rhead->prev && crl->isComment)
1835 /* quit if we reach the end */
1836 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1839 if (matchLine(csl->line,crl->line,NULL))
1850 /*------------------------------------------------------------------*/
1851 /* reassociate_ic - reassociate replacement lines with origin iCode */
1852 /*------------------------------------------------------------------*/
1854 reassociate_ic (lineNode *shead, lineNode *stail,
1855 lineNode *rhead, lineNode *rtail)
1857 lineNode *csl; /* current source line */
1858 lineNode *crl; /* current replacement line */
1862 /* Check to see if all the source lines (excluding comments) came
1863 ** for the same iCode
1866 for (csl=shead;csl!=stail->next;csl=csl->next)
1867 if (csl->ic && !csl->isComment)
1872 single_iCode = (ic!=NULL);
1873 for (csl=shead;csl!=stail->next;csl=csl->next)
1874 if ((csl->ic != ic) && !csl->isComment)
1876 /* More than one iCode was found. However, if it's just the
1877 ** last line with the different iCode and it was not changed
1878 ** in the replacement, everything else must be the first iCode.
1880 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1882 rtail->ic = stail->ic;
1883 for (crl=rhead;crl!=rtail;crl=crl->next)
1888 single_iCode = FALSE;
1892 /* If all of the source lines came from the same iCode, then so have
1893 ** all of the replacement lines too.
1897 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1902 /* The source lines span iCodes, so we may end up with replacement
1903 ** lines that we don't know which iCode(s) to associate with. Do the
1904 ** best we can by using the following strategies:
1905 ** 1) Start at the top and scan down. As long as the source line
1906 ** matches the replacement line, they have the same iCode.
1907 ** 2) Start at the bottom and scan up. As long as the source line
1908 ** matches the replacement line, they have the same iCode.
1909 ** 3) For any label in the source, look for a matching label in
1910 ** the replacment. If found, they have the same iCode. From
1911 ** these matching labels, scan down for additional matching
1912 ** lines; if found, they also have the same iCode.
1915 /* Strategy #1: Start at the top and scan down for matches
1917 reassociate_ic_down(shead,stail,rhead,rtail);
1919 /* Strategy #2: Start at the bottom and scan up for matches
1921 reassociate_ic_up(shead,stail,rhead,rtail);
1923 /* Strategy #3: Try to match labels
1928 /* skip over any comments */
1929 while (csl!=stail->next && csl->isComment)
1931 if (csl==stail->next)
1936 /* found a source line label; look for it in the replacment lines */
1940 while (crl!=rtail->next && crl->isComment)
1942 if (crl==rtail->next)
1944 if (matchLine(csl->line, crl->line, NULL))
1946 reassociate_ic_down(csl,stail,crl,rtail);
1956 /* Try to assign a meaningful iCode to any comment that is missing
1957 one. Since they are comments, it's ok to make mistakes; we are just
1958 trying to improve continuity to simplify other tests.
1961 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1963 if (!crl->ic && ic && crl->isComment)
1970 /*-----------------------------------------------------------------*/
1971 /* replaceRule - does replacement of a matching pattern */
1972 /*-----------------------------------------------------------------*/
1974 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1976 lineNode *cl = NULL;
1977 lineNode *pl = NULL, *lhead = NULL;
1978 /* a long function name and long variable name can evaluate to
1979 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1980 char lb[MAX_PATTERN_LEN*4];
1982 lineNode *comment = NULL;
1984 /* collect all the comment lines in the source */
1985 for (cl = *shead; cl != stail; cl = cl->next)
1987 if (cl->line && (*cl->line == ';' || cl->isDebug))
1989 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1990 (comment = newLineNode (cl->line)));
1991 pl->isDebug = cl->isDebug;
1992 pl->isComment = cl->isComment || (*cl->line == ';');
1997 /* for all the lines in the replacement pattern do */
1998 for (pl = pr->replace; pl; pl = pl->next)
2008 /* if the line contains a variable */
2009 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2011 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2014 fprintf (stderr, "used unbound variable in replacement\n");
2022 while (ISCHARDIGIT (*l)) {
2032 cl = connectLine (cl, newLineNode (lb));
2034 lhead = cl = newLineNode (lb);
2035 cl->isComment = pl->isComment;
2036 cl->isLabel = pl->isLabel;
2039 /* add the comments if any to the head of list */
2042 lineNode *lc = comment;
2053 /* determine which iCodes the replacment lines relate to */
2054 reassociate_ic(*shead,stail,lhead,cl);
2056 /* now we need to connect / replace the original chain */
2057 /* if there is a prev then change it */
2060 (*shead)->prev->next = lhead;
2061 lhead->prev = (*shead)->prev;
2064 /* now for the tail */
2065 if (stail && stail->next)
2067 stail->next->prev = cl;
2069 cl->next = stail->next;
2074 /* the replacement is empty - delete the source lines */
2076 (*shead)->prev->next = stail->next;
2078 stail->next->prev = (*shead)->prev;
2079 *shead = stail->next;
2083 /* Returns TRUE if this line is a label definition.
2085 * If so, start will point to the start of the label name,
2086 * and len will be it's length.
2089 isLabelDefinition (const char *line, const char **start, int *len,
2092 const char *cp = line;
2094 /* This line is a label if if consists of:
2095 * [optional whitespace] followed by identifier chars
2096 * (alnum | $ | _ ) followed by a colon.
2099 while (*cp && ISCHARSPACE (*cp))
2111 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2112 (isPeepRule && (*cp == '%')))
2117 if ((cp == *start) || (*cp != ':'))
2122 *len = (cp - (*start));
2126 /* Quick & dirty string hash function. */
2128 hashSymbolName (const char *name)
2134 hash = (hash << 6) ^ *name;
2143 return hash % HTAB_SIZE;
2146 /* Build a hash of all labels in the passed set of lines
2147 * and how many times they are referenced.
2150 buildLabelRefCountHash (lineNode * head)
2157 assert (labelHash == NULL);
2158 labelHash = newHashTable (HTAB_SIZE);
2160 /* First pass: locate all the labels. */
2161 for (line = head; line; line = line->next)
2163 if (line->isLabel ||
2166 /* run isLabelDefinition to:
2167 - look for labels in inline assembler
2168 - calculate labelLen
2170 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2171 labelLen <= SDCC_NAME_MAX)
2173 labelHashEntry *entry;
2175 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2177 memcpy (entry->name, label, labelLen);
2178 entry->name[labelLen] = 0;
2179 entry->refCount = -1;
2181 /* Assume function entry points are referenced somewhere, */
2182 /* even if we can't find a reference (might be from outside */
2184 if (line->ic && (line->ic->op == FUNCTION))
2187 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2193 /* Second pass: for each line, note all the referenced labels. */
2194 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2198 for (i = 0; i < HTAB_SIZE; i++)
2200 labelHashEntry *thisEntry;
2202 thisEntry = hTabFirstItemWK (labelHash, i);
2206 if (strstr (line->line, thisEntry->name))
2208 thisEntry->refCount++;
2210 thisEntry = hTabNextItemWK (labelHash);
2217 /* Spew the contents of the table. Debugging fun only. */
2218 for (i = 0; i < HTAB_SIZE; i++)
2220 labelHashEntry *thisEntry;
2222 thisEntry = hTabFirstItemWK (labelHash, i);
2226 fprintf (stderr, "label: %s ref %d\n",
2227 thisEntry->name, thisEntry->refCount);
2228 thisEntry = hTabNextItemWK (labelHash);
2234 /* How does this work?
2240 replace and restart.
2245 Where is stuff allocated?
2249 /*-----------------------------------------------------------------*/
2250 /* peepHole - matches & substitutes rules */
2251 /*-----------------------------------------------------------------*/
2253 peepHole (lineNode ** pls)
2257 lineNode *mtail = NULL;
2258 bool restart, replaced;
2260 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2261 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2262 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2266 assert(labelHash == NULL);
2273 for (pr = rootRules; pr; pr = pr->next)
2275 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2279 /* if inline assembler then no peep hole */
2283 /* don't waste time starting a match on debug symbol
2285 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2290 /* Tidy up any data stored in the hTab */
2293 if (matchRule (spl, &mtail, pr, *pls))
2295 /* restart at the replaced line */
2301 replaceRule (pls, mtail, pr);
2305 replaceRule (&spl, mtail, pr);
2307 /* if restart rule type then
2308 start at the top again */
2317 hTabDeleteAll (pr->vars);
2318 Safe_free (pr->vars);
2322 freeTrace (&_G.values);
2325 } while (restart == TRUE);
2329 hTabDeleteAll (labelHash);
2330 freeTrace (&_G.labels);
2336 /*-----------------------------------------------------------------*/
2337 /* readFileIntoBuffer - reads a file into a string buffer */
2338 /*-----------------------------------------------------------------*/
2340 readFileIntoBuffer (char *fname)
2346 char lb[MAX_PATTERN_LEN];
2348 if (!(f = fopen (fname, "r")))
2350 fprintf (stderr, "cannot open peep rule file\n");
2354 while ((ch = fgetc (f)) != EOF)
2358 /* if we maxed out our local buffer */
2359 if (nch >= (MAX_PATTERN_LEN - 2))
2362 /* copy it into allocated buffer */
2365 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2366 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2370 rs = Safe_strdup (lb);
2376 /* if some charaters left over */
2380 /* copy it into allocated buffer */
2383 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2384 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2388 rs = Safe_strdup (lb);
2394 /*-----------------------------------------------------------------*/
2395 /* initPeepHole - initialises the peep hole optimizer stuff */
2396 /*-----------------------------------------------------------------*/
2402 /* read in the default rules */
2403 if (!options.nopeep)
2405 readRules (port->peep.default_rules);
2408 /* if we have any additional file read it too */
2409 if (options.peep_file)
2411 readRules (s = readFileIntoBuffer (options.peep_file));
2412 setToNull ((void *) &s);
2413 /* override nopeep setting, default rules have not been read */
2418 #if !OPT_DISABLE_PIC
2419 /* Convert the peep rules into pcode.
2420 NOTE: this is only support in the PIC port (at the moment)
2423 peepRules2pCode(rootRules);
2426 #if !OPT_DISABLE_PIC16
2427 /* Convert the peep rules into pcode.
2428 NOTE: this is only support in the PIC port (at the moment)
2429 and the PIC16 port (VR 030601)
2431 if (TARGET_IS_PIC16)
2432 pic16_peepRules2pCode(rootRules);