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 - finds a label backward 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)
84 dist += port->peep.getSize(pl);
92 if (strncmp (pl->line, buff, strlen (buff)) == 0)
104 /*-----------------------------------------------------------------*/
105 /* portIsDS390 - return true if port is DS390 */
106 /*-----------------------------------------------------------------*/
107 FBYNAME (portIsDS390)
109 return ((strcmp(port->target,"ds390") == 0) ||
110 (strcmp(port->target,"ds400") == 0));
113 /*-----------------------------------------------------------------*/
114 /* flat24bitMode - will check to see if we are in flat24 mode */
115 /*-----------------------------------------------------------------*/
116 FBYNAME (flat24bitMode)
118 return (options.model == MODEL_FLAT24);
121 /*-----------------------------------------------------------------*/
122 /* xramMovcOption - check if using movc to read xram */
123 /*-----------------------------------------------------------------*/
124 FBYNAME (xramMovcOption)
126 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
129 /*-----------------------------------------------------------------*/
130 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
131 /*-----------------------------------------------------------------*/
132 FBYNAME (useAcallAjmp)
134 return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
137 /*-----------------------------------------------------------------*/
138 /* labelInRange - will check to see if label %5 is within range */
139 /*-----------------------------------------------------------------*/
140 FBYNAME (labelInRange)
142 /* assumes that %5 pattern variable has the label name */
143 char *lbl = hTabItemWithKey (vars, 5);
149 /* Don't optimize jumps in a jump table; a more generic test */
150 if (currPl->ic && currPl->ic->op == JUMPTABLE)
153 /* if the previous two instructions are "ljmp"s then don't
154 do it since it can be part of a jump table */
155 if (currPl->prev && currPl->prev->prev &&
156 strstr (currPl->prev->line, "ljmp") &&
157 strstr (currPl->prev->prev->line, "ljmp"))
160 /* calculate the label distance : the jump for reladdr can be
161 +/- 127 bytes, here I am assuming that an average 8051
162 instruction is 2 bytes long, so if the label is more than
163 63 intructions away, the label is considered out of range
164 for a relative jump. we could get more precise this will
165 suffice for now since it catches > 90% cases */
166 dist = (pcDistance (currPl, lbl, TRUE) +
167 pcDistance (currPl, lbl, FALSE));
169 /* changed to 127, now that pcDistance return actual number of bytes */
170 if (!dist || dist > 127)
176 /*-----------------------------------------------------------------*/
177 /* labelJTInRange - will check to see if label %5 and up are */
179 /* Specifically meant to optimize long (3-byte) jumps to short */
180 /* (2-byte) jumps in jumptables */
181 /*-----------------------------------------------------------------*/
182 FBYNAME (labelJTInRange)
187 if (!getenv("SDCC_SJMP_JUMPTABLE"))
190 /* Only optimize within a jump table */
191 if (currPl->ic && currPl->ic->op != JUMPTABLE)
194 count = elementsInSet( IC_JTLABELS (currPl->ic) );
196 /* check all labels (this is needed if the case statements are unsorted) */
197 for (i=0; i<count; i++)
199 /* assumes that the %5 pattern variable has the first ljmp label */
200 lbl = hTabItemWithKey (vars, 5+i);
204 dist = pcDistance (currPl, lbl, FALSE);
206 /* three terms used to calculate allowable distance */
207 // 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);
209 dist > 127+ /* range of sjmp */
210 (7+3*i)+ /* offset between this jump and currPl,
211 should use pcDistance instead? */
212 (count-i-1) /* if peephole applies distance is shortened */
219 /*-----------------------------------------------------------------*/
220 /* labelIsReturnOnly - Check if label %5 is followed by RET */
221 /*-----------------------------------------------------------------*/
222 FBYNAME (labelIsReturnOnly)
224 /* assumes that %5 pattern variable has the label name */
225 const char *label, *p;
230 /* Don't optimize jumps in a jump table; a more generic test */
231 if (currPl->ic && currPl->ic->op == JUMPTABLE)
234 label = hTabItemWithKey (vars, 5);
239 for(pl = currPl; pl; pl = pl->next)
241 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
243 if (strncmp(pl->line, label, len) == 0)
244 break; /* Found Label */
245 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
246 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
247 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
248 *(pl->line+5) != '$')
250 return FALSE; /* non-local label encountered */
255 return FALSE; /* did not find the label */
257 while (pl && (pl->isDebug || pl->isComment))
259 if (!pl || !pl->line || pl->isDebug)
260 return FALSE; /* next line not valid */
262 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
268 if (strcmp(p, retInst) == 0)
273 /*-----------------------------------------------------------------*/
274 /* labelIsUncondJump - Check if label %5 is followed by an */
275 /* unconditional jump and put the destination of that jump in %6 */
276 /*-----------------------------------------------------------------*/
277 FBYNAME (labelIsUncondJump)
279 /* assumes that %5 pattern variable has the label name */
284 char * jpInst = NULL;
286 /* Don't optimize jumps in a jump table; a more generic test */
287 if (currPl->ic && currPl->ic->op == JUMPTABLE)
290 label = hTabItemWithKey (vars, 5);
295 for (pl = currPl; pl; pl = pl->next)
297 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
299 if (strncmp(pl->line, label, len) == 0)
300 break; /* Found Label */
301 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
302 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
303 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
304 *(pl->line+5) != '$')
306 return FALSE; /* non-local label encountered */
311 return FALSE; /* did not find the label */
313 while (pl && (pl->isDebug || pl->isComment))
315 if (!pl || !pl->line)
316 return FALSE; /* next line not valid */
318 while (*p && ISCHARSPACE(*p))
321 if (TARGET_MCS51_LIKE)
327 len = strlen(jpInst);
328 if (strncmp(p, jpInst, len) != 0)
329 return FALSE; /* next line is no jump */
331 while (*p && ISCHARSPACE(*p))
335 while (*q && *q!=';')
337 while (q>p && ISCHARSPACE(*q))
341 return FALSE; /* no destination? */
344 while (q>p && *q!=',')
347 return FALSE; /* conditional jump */
349 if (strcmp(p, q) == 0)
350 return FALSE; /* labels are equal */
351 /* now put the destination in %6 */
352 bindVar (6, &p, &vars);
356 /*-----------------------------------------------------------------*/
357 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
358 /* usage of it in the code depends on a value from this section */
359 /*-----------------------------------------------------------------*/
360 FBYNAME (okToRemoveSLOC)
363 const char *sloc, *p;
364 int dummy1, dummy2, dummy3;
366 /* assumes that %1 as the SLOC name */
367 sloc = hTabItemWithKey (vars, 1);
368 if (sloc == NULL) return FALSE;
369 p = strstr(sloc, "sloc");
370 if (p == NULL) return FALSE;
372 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
373 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
374 /* the sloc name begins with that. Probably not really necessary */
376 /* Look for any occurance of this SLOC before the peephole match */
377 for (pl = currPl->prev; pl; pl = pl->prev) {
378 if (pl->line && !pl->isDebug && !pl->isComment
379 && *pl->line != ';' && strstr(pl->line, sloc))
382 /* Look for any occurance of this SLOC after the peephole match */
383 for (pl = endPl->next; pl; pl = pl->next) {
384 if (pl->line && !pl->isDebug && !pl->isComment
385 && *pl->line != ';' && strstr(pl->line, sloc))
388 return TRUE; /* safe for a peephole to remove it :) */
391 /*-----------------------------------------------------------------*/
392 /* deadMove - Check, if a pop/push pair can be removed */
393 /*-----------------------------------------------------------------*/
396 const char *reg = hTabItemWithKey (vars, 1);
398 if (port->peep.deadMove)
399 return port->peep.deadMove (reg, currPl, head);
401 fprintf (stderr, "Function deadMove not initialized in port structure\n");
405 /*-----------------------------------------------------------------*/
406 /* operandsNotSame - check if %1 & %2 are the same */
407 /*-----------------------------------------------------------------*/
408 FBYNAME (operandsNotSame)
410 char *op1 = hTabItemWithKey (vars, 1);
411 char *op2 = hTabItemWithKey (vars, 2);
413 if (strcmp (op1, op2) == 0)
419 /*-----------------------------------------------------------------*/
420 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
421 /*-----------------------------------------------------------------*/
422 FBYNAME (operandsNotSame3)
424 char *op1 = hTabItemWithKey (vars, 1);
425 char *op2 = hTabItemWithKey (vars, 2);
426 char *op3 = hTabItemWithKey (vars, 3);
428 if ( (strcmp (op1, op2) == 0) ||
429 (strcmp (op1, op3) == 0) ||
430 (strcmp (op2, op3) == 0) )
436 /*-----------------------------------------------------------------*/
437 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
438 /*-----------------------------------------------------------------*/
439 FBYNAME (operandsNotSame4)
441 char *op1 = hTabItemWithKey (vars, 1);
442 char *op2 = hTabItemWithKey (vars, 2);
443 char *op3 = hTabItemWithKey (vars, 3);
444 char *op4 = hTabItemWithKey (vars, 4);
446 if ( (strcmp (op1, op2) == 0) ||
447 (strcmp (op1, op3) == 0) ||
448 (strcmp (op1, op4) == 0) ||
449 (strcmp (op2, op3) == 0) ||
450 (strcmp (op2, op4) == 0) ||
451 (strcmp (op3, op4) == 0) )
457 /*-----------------------------------------------------------------*/
458 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
459 /*-----------------------------------------------------------------*/
460 FBYNAME (operandsNotSame5)
462 char *op1 = hTabItemWithKey (vars, 1);
463 char *op2 = hTabItemWithKey (vars, 2);
464 char *op3 = hTabItemWithKey (vars, 3);
465 char *op4 = hTabItemWithKey (vars, 4);
466 char *op5 = hTabItemWithKey (vars, 5);
468 if ( (strcmp (op1, op2) == 0) ||
469 (strcmp (op1, op3) == 0) ||
470 (strcmp (op1, op4) == 0) ||
471 (strcmp (op1, op5) == 0) ||
472 (strcmp (op2, op3) == 0) ||
473 (strcmp (op2, op4) == 0) ||
474 (strcmp (op2, op5) == 0) ||
475 (strcmp (op3, op4) == 0) ||
476 (strcmp (op3, op5) == 0) ||
477 (strcmp (op4, op5) == 0) )
483 /*-----------------------------------------------------------------*/
484 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
485 /*-----------------------------------------------------------------*/
486 FBYNAME (operandsNotSame6)
488 char *op1 = hTabItemWithKey (vars, 1);
489 char *op2 = hTabItemWithKey (vars, 2);
490 char *op3 = hTabItemWithKey (vars, 3);
491 char *op4 = hTabItemWithKey (vars, 4);
492 char *op5 = hTabItemWithKey (vars, 5);
493 char *op6 = hTabItemWithKey (vars, 6);
495 if ( (strcmp (op1, op2) == 0) ||
496 (strcmp (op1, op3) == 0) ||
497 (strcmp (op1, op4) == 0) ||
498 (strcmp (op1, op5) == 0) ||
499 (strcmp (op1, op6) == 0) ||
500 (strcmp (op2, op3) == 0) ||
501 (strcmp (op2, op4) == 0) ||
502 (strcmp (op2, op5) == 0) ||
503 (strcmp (op2, op6) == 0) ||
504 (strcmp (op3, op4) == 0) ||
505 (strcmp (op3, op5) == 0) ||
506 (strcmp (op3, op6) == 0) ||
507 (strcmp (op4, op5) == 0) ||
508 (strcmp (op4, op6) == 0) ||
509 (strcmp (op5, op6) == 0) )
515 /*-----------------------------------------------------------------*/
516 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
517 /*-----------------------------------------------------------------*/
518 FBYNAME (operandsNotSame7)
520 char *op1 = hTabItemWithKey (vars, 1);
521 char *op2 = hTabItemWithKey (vars, 2);
522 char *op3 = hTabItemWithKey (vars, 3);
523 char *op4 = hTabItemWithKey (vars, 4);
524 char *op5 = hTabItemWithKey (vars, 5);
525 char *op6 = hTabItemWithKey (vars, 6);
526 char *op7 = hTabItemWithKey (vars, 7);
528 if ( (strcmp (op1, op2) == 0) ||
529 (strcmp (op1, op3) == 0) ||
530 (strcmp (op1, op4) == 0) ||
531 (strcmp (op1, op5) == 0) ||
532 (strcmp (op1, op6) == 0) ||
533 (strcmp (op1, op7) == 0) ||
534 (strcmp (op2, op3) == 0) ||
535 (strcmp (op2, op4) == 0) ||
536 (strcmp (op2, op5) == 0) ||
537 (strcmp (op2, op6) == 0) ||
538 (strcmp (op2, op7) == 0) ||
539 (strcmp (op3, op4) == 0) ||
540 (strcmp (op3, op5) == 0) ||
541 (strcmp (op3, op6) == 0) ||
542 (strcmp (op3, op7) == 0) ||
543 (strcmp (op4, op5) == 0) ||
544 (strcmp (op4, op6) == 0) ||
545 (strcmp (op4, op7) == 0) ||
546 (strcmp (op5, op6) == 0) ||
547 (strcmp (op5, op7) == 0) ||
548 (strcmp (op6, op7) == 0) )
554 /*-----------------------------------------------------------------*/
555 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
556 /*-----------------------------------------------------------------*/
557 FBYNAME (operandsNotSame8)
559 char *op1 = hTabItemWithKey (vars, 1);
560 char *op2 = hTabItemWithKey (vars, 2);
561 char *op3 = hTabItemWithKey (vars, 3);
562 char *op4 = hTabItemWithKey (vars, 4);
563 char *op5 = hTabItemWithKey (vars, 5);
564 char *op6 = hTabItemWithKey (vars, 6);
565 char *op7 = hTabItemWithKey (vars, 7);
566 char *op8 = hTabItemWithKey (vars, 8);
568 if ( (strcmp (op1, op2) == 0) ||
569 (strcmp (op1, op3) == 0) ||
570 (strcmp (op1, op4) == 0) ||
571 (strcmp (op1, op5) == 0) ||
572 (strcmp (op1, op6) == 0) ||
573 (strcmp (op1, op7) == 0) ||
574 (strcmp (op1, op8) == 0) ||
575 (strcmp (op2, op3) == 0) ||
576 (strcmp (op2, op4) == 0) ||
577 (strcmp (op2, op5) == 0) ||
578 (strcmp (op2, op6) == 0) ||
579 (strcmp (op2, op7) == 0) ||
580 (strcmp (op2, op8) == 0) ||
581 (strcmp (op3, op4) == 0) ||
582 (strcmp (op3, op5) == 0) ||
583 (strcmp (op3, op6) == 0) ||
584 (strcmp (op3, op7) == 0) ||
585 (strcmp (op3, op8) == 0) ||
586 (strcmp (op4, op5) == 0) ||
587 (strcmp (op4, op6) == 0) ||
588 (strcmp (op4, op7) == 0) ||
589 (strcmp (op4, op8) == 0) ||
590 (strcmp (op5, op6) == 0) ||
591 (strcmp (op5, op7) == 0) ||
592 (strcmp (op5, op8) == 0) ||
593 (strcmp (op6, op7) == 0) ||
594 (strcmp (op6, op8) == 0) ||
595 (strcmp (op7, op8) == 0) )
601 /*-----------------------------------------------------------------*/
602 /* labelHashEntry- searches for a label in the list labelHash */
603 /* Builds labelHash, if it does not yet exist. */
604 /* Returns the labelHashEntry or NULL */
605 /*-----------------------------------------------------------------*/
607 getLabelRef (const char *label, lineNode *head)
609 labelHashEntry *entry;
611 /* If we don't have the label hash table yet, build it. */
614 buildLabelRefCountHash (head);
617 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
621 if (!strcmp (label, entry->name))
625 entry = hTabNextItemWK (labelHash);
632 * takes two parameters: a variable (bound to a label name)
633 * and an expected reference count.
635 * Returns TRUE if that label is defined and referenced exactly
636 * the given number of times.
638 FBYNAME (labelRefCount)
640 int varNumber, expectedRefCount;
643 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
645 char *label = hTabItemWithKey (vars, varNumber);
649 labelHashEntry *entry = getLabelRef (label, head);
655 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
656 label, entry->refCount, expectedRefCount);
659 rc = (expectedRefCount == entry->refCount);
663 fprintf (stderr, "*** internal error: no label has entry for"
664 " %s in labelRefCount peephole.\n",
670 fprintf (stderr, "*** internal error: var %d not bound"
671 " in peephole labelRefCount rule.\n",
679 "*** internal error: labelRefCount peephole restriction"
680 " malformed: %s\n", cmdLine);
685 /* labelRefCountChange:
686 * takes two parameters: a variable (bound to a label name)
687 * and a signed int for changing the reference count.
689 * Please note, this function is not a conditional. It unconditionally
690 * changes the label. It should be passed as the 'last' function
691 * so it only is applied if all other conditions have been met.
693 * should always return TRUE
695 FBYNAME (labelRefCountChange)
697 int varNumber, RefCountDelta;
700 /* If we don't have the label hash table yet, build it. */
703 buildLabelRefCountHash (head);
706 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
708 char *label = hTabItemWithKey (vars, varNumber);
712 labelHashEntry *entry;
714 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
718 if (!strcmp (label, entry->name))
722 entry = hTabNextItemWK (labelHash);
726 if (0 <= entry->refCount + RefCountDelta)
728 entry->refCount += RefCountDelta;
733 fprintf (stderr, "*** internal error: label %s may not get"
734 " negative refCount in %s peephole.\n",
735 label, __FUNCTION__);
740 fprintf (stderr, "*** internal error: no label has entry for"
741 " %s in %s peephole.\n",
742 label, __FUNCTION__);
747 fprintf (stderr, "*** internal error: var %d not bound"
748 " in peephole %s rule.\n",
749 varNumber, __FUNCTION__);
755 "*** internal error: labelRefCount peephole restriction"
756 " malformed: %s\n", cmdLine);
761 /* Within the context of the lines currPl through endPl, determine
762 ** if the variable var contains a symbol that is volatile. Returns
763 ** TRUE only if it is certain that this was not volatile (the symbol
764 ** was found and not volatile, or var was a constant or CPU register).
765 ** Returns FALSE if the symbol was found and volatile, the symbol was
766 ** not found, or var was a indirect/pointer addressing mode.
769 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
771 char symname[SDCC_NAME_MAX + 1];
778 /* Can't tell if indirect accesses are volatile or not, so
779 ** assume they are, just to be safe.
781 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
786 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
788 if (strstr(var,"(bc)"))
790 if (strstr(var,"(de)"))
792 if (strstr(var,"(hl)"))
794 if (strstr(var,"(ix"))
796 if (strstr(var,"(iy"))
800 /* Extract a symbol name from the variable */
801 while (*vp && (*vp!='_'))
803 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
809 /* Nothing resembling a symbol name was found, so it can't
816 for (cl = currPl; cl!=endPl->next; cl = cl->next)
818 if (cl->ic && (cl->ic!=last_ic))
824 op = IC_COND (cl->ic);
826 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
827 (OP_SYMBOL (op)->isspilt &&
829 !strcmp(SPIL_LOC (op)->rname, symname)) ))
831 return !op->isvolatile;
834 op = IC_JTCOND (cl->ic);
836 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
837 (OP_SYMBOL (op)->isspilt &&
839 !strcmp(SPIL_LOC (op)->rname, symname)) ))
841 return !op->isvolatile;
844 op = IC_LEFT (cl->ic);
846 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
847 (OP_SYMBOL (op)->isspilt &&
849 !strcmp(SPIL_LOC (op)->rname, symname)) ))
851 return !op->isvolatile;
853 op = IC_RIGHT (cl->ic);
855 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
856 (OP_SYMBOL (op)->isspilt &&
858 !strcmp(SPIL_LOC (op)->rname, symname)) ))
860 return !op->isvolatile;
862 op = IC_RESULT (cl->ic);
864 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
865 (OP_SYMBOL (op)->isspilt &&
867 !strcmp(SPIL_LOC (op)->rname, symname)) ))
869 return !op->isvolatile;
875 /* Couldn't find the symbol for some reason. Assume volatile. */
881 * This rule restriction has two different behaviours depending on
882 * the number of parameters given.
884 * if notVolatile (no parameters given)
885 * The rule is applied only if none of the iCodes originating
886 * the matched pattern reference a volatile operand.
888 * if notVolatile %1 ... (one or more parameters given)
889 * The rule is applied if the parameters are not expressions
890 * containing volatile symbols and are not pointer accesses.
893 FBYNAME (notVolatile)
904 /* If no parameters given, just scan the iCodes for volatile operands */
905 for (cl = currPl; cl!=endPl->next; cl = cl->next)
912 op = IC_COND (cl->ic);
913 if (IS_SYMOP (op) && op->isvolatile)
916 op = IC_JTCOND (cl->ic);
917 if (IS_SYMOP (op) && op->isvolatile)
920 op = IC_LEFT (cl->ic);
921 if (IS_SYMOP (op) && op->isvolatile)
923 op = IC_RIGHT (cl->ic);
924 if (IS_SYMOP (op) && op->isvolatile)
926 op = IC_RESULT (cl->ic);
927 if (IS_SYMOP (op) && op->isvolatile)
935 /* There were parameters; check the volatility of each */
936 while (*cmdLine && ISCHARSPACE(*cmdLine))
943 if (!ISCHARDIGIT(*cmdLine))
945 varNumber = strtol(cmdLine, &digitend, 10);
947 while (*cmdLine && ISCHARSPACE(*cmdLine))
950 var = hTabItemWithKey (vars, varNumber);
954 notvol = notVolatileVariable (var, currPl, endPl);
960 fprintf (stderr, "*** internal error: var %d not bound"
961 " in peephole notVolatile rule.\n",
971 "*** internal error: notVolatile peephole restriction"
972 " malformed: %s\n", cmdLine);
976 /*------------------------------------------------------------------*/
977 /* setFromConditionArgs - parse a peephole condition's arguments */
978 /* to produce a set of strings, one per argument. Variables %x will */
979 /* be replaced with their values. String literals (in single quotes)*/
980 /* are accepted and return in unquoted form. */
981 /*------------------------------------------------------------------*/
983 setFromConditionArgs (char *cmdLine, hTab * vars)
988 set *operands = NULL;
993 while (*cmdLine && ISCHARSPACE(*cmdLine))
1001 if (!ISCHARDIGIT(*cmdLine))
1003 varNumber = strtol(cmdLine, &digitend, 10);
1006 var = hTabItemWithKey (vars, varNumber);
1010 addSetHead (&operands, var);
1015 else if (*cmdLine == '\'' )
1017 char quote = *cmdLine;
1020 while (*cmdLine && *cmdLine != quote)
1022 if (*cmdLine == quote)
1026 addSetHead (&operands, var);
1031 while (*cmdLine && ISCHARSPACE(*cmdLine))
1038 deleteSet (&operands);
1043 operandBaseName (const char *op)
1045 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1047 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1049 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1051 // bug 1739475, temp fix
1053 return operandBaseName(op+1);
1059 /*-------------------------------------------------------------------*/
1060 /* operandsNotRelated - returns true if the condition's operands are */
1061 /* not related (taking into account register name aliases). N-way */
1062 /* comparison performed between all operands. */
1063 /*-------------------------------------------------------------------*/
1064 FBYNAME (operandsNotRelated)
1067 const char *op1, *op2;
1069 operands = setFromConditionArgs (cmdLine, vars);
1074 "*** internal error: operandsNotRelated peephole restriction"
1075 " malformed: %s\n", cmdLine);
1079 while ((op1 = setFirstItem (operands)))
1081 deleteSetItem (&operands, (void*)op1);
1082 op1 = operandBaseName (op1);
1084 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1086 op2 = operandBaseName (op2);
1087 if (strcmp (op1, op2) == 0)
1089 deleteSet (&operands);
1095 deleteSet (&operands);
1099 /*-------------------------------------------------------------------*/
1100 /* operandsLiteral - returns true of the condition's operands are */
1102 /*-------------------------------------------------------------------*/
1103 FBYNAME (operandsLiteral)
1108 operands = setFromConditionArgs (cmdLine, vars);
1113 "*** internal error: operandsLiteral peephole restriction"
1114 " malformed: %s\n", cmdLine);
1118 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1122 deleteSet (&operands);
1127 deleteSet (&operands);
1131 static const struct ftab
1134 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1136 ftab[] = // sorted on the number of times used
1137 { // in the peephole rules on 2007-10-29
1139 "labelRefCount", labelRefCount //105
1142 "notVolatile", notVolatile //85
1145 "labelRefCountChange", labelRefCountChange //74
1148 "labelInRange", labelInRange //37
1151 "labelJTInRange", labelJTInRange //13
1154 "operandsNotRelated", operandsNotRelated //9
1157 "24bitMode", flat24bitMode //9
1160 "operandsNotSame", operandsNotSame //8
1163 "operandsNotSame3", operandsNotSame3
1166 "operandsNotSame4", operandsNotSame4
1169 "operandsNotSame5", operandsNotSame5
1172 "operandsNotSame6", operandsNotSame6
1175 "operandsNotSame7", operandsNotSame7
1178 "operandsNotSame8", operandsNotSame8
1181 "xramMovcOption", xramMovcOption
1184 "portIsDS390", portIsDS390
1187 "labelIsReturnOnly", labelIsReturnOnly
1190 "labelIsUncondJump", labelIsUncondJump
1193 "okToRemoveSLOC", okToRemoveSLOC
1196 "deadMove", deadMove
1199 "operandsLiteral", operandsLiteral
1202 "useAcallAjmp", useAcallAjmp
1205 /*-----------------------------------------------------------------*/
1206 /* callFuncByName - calls a function as defined in the table */
1207 /*-----------------------------------------------------------------*/
1209 callFuncByName (char *fname,
1216 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1220 /* Isolate the function name part (we are passed the full condition
1221 * string including arguments)
1223 cmdTerm = cmdCopy = Safe_strdup(fname);
1227 funcArgs = funcName = cmdTerm;
1228 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1230 *funcArgs = '\0'; /* terminate the function name */
1234 /* Find the start of the arguments */
1235 if (c == ' ' || c == '\t')
1236 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1239 /* If the arguments started with an opening parenthesis, */
1240 /* use the closing parenthesis for the end of the */
1241 /* arguments and look for the start of another condition */
1242 /* that can optionally follow. If there was no opening */
1243 /* parethesis, then everything that follows are arguments */
1244 /* and there can be no additional conditions. */
1248 while ((c = *cmdTerm) && c != ')')
1250 *cmdTerm = '\0'; /* terminate the arguments */
1254 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1260 cmdTerm = NULL; /* closing parenthesis missing */
1269 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1271 if (strcmp (ftab[i].fname, funcName) == 0)
1273 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1281 "could not find named function \"%s\" in "
1282 "peephole function table\n",
1284 // If the function couldn't be found, let's assume it's
1285 // a bad rule and refuse it.
1290 while (rc && cmdTerm);
1297 /*-----------------------------------------------------------------*/
1298 /* printLine - prints a line chain into a given file */
1299 /*-----------------------------------------------------------------*/
1301 printLine (lineNode * head, struct dbuf_s * oBuf)
1303 iCode *last_ic = NULL;
1304 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1308 if (head->ic!=last_ic)
1311 if (debug_iCode_tracking)
1314 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1315 head->ic->block, head->ic->seq);
1317 dbuf_append_str (oBuf, "; iCode lost\n");
1321 /* don't indent comments & labels */
1323 (head->isComment || head->isLabel)) {
1324 dbuf_printf (oBuf, "%s\n", head->line);
1326 if (head->isInline && *head->line=='#') {
1327 // comment out preprocessor directives in inline asm
1328 dbuf_append_char (oBuf, ';');
1330 dbuf_printf (oBuf, "\t%s\n", head->line);
1336 /*-----------------------------------------------------------------*/
1337 /* newPeepRule - creates a new peeprule and attach it to the root */
1338 /*-----------------------------------------------------------------*/
1340 newPeepRule (lineNode * match,
1347 pr = Safe_alloc ( sizeof (peepRule));
1349 pr->replace = replace;
1350 pr->restart = restart;
1354 pr->cond = Safe_strdup (cond);
1359 pr->vars = newHashTable (100);
1361 /* if root is empty */
1363 rootRules = currRule = pr;
1365 currRule = currRule->next = pr;
1370 /*-----------------------------------------------------------------*/
1371 /* newLineNode - creates a new peep line */
1372 /*-----------------------------------------------------------------*/
1374 newLineNode (const char *line)
1378 pl = Safe_alloc ( sizeof (lineNode));
1379 pl->line = Safe_strdup (line);
1384 /*-----------------------------------------------------------------*/
1385 /* connectLine - connects two lines */
1386 /*-----------------------------------------------------------------*/
1388 connectLine (lineNode * pl1, lineNode * pl2)
1392 fprintf (stderr, "trying to connect null line\n");
1402 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1403 if (!*x) { fprintf(stderr,y); return ; } }
1405 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1406 if (!*x) { fprintf(stderr,z); return ; } }
1407 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1408 if (!*x) { fprintf(stderr,z); return ; } }
1410 /*-----------------------------------------------------------------*/
1411 /* getPeepLine - parses the peep lines */
1412 /*-----------------------------------------------------------------*/
1414 getPeepLine (lineNode ** head, char **bpp)
1416 char lines[MAX_PATTERN_LEN];
1420 lineNode *currL = NULL;
1427 fprintf (stderr, "unexpected end of match pattern\n");
1434 while (ISCHARSPACE (*bp) ||
1445 /* read till end of line */
1447 while ((*bp != '\n' && *bp != '}') && *bp)
1452 while (*lp && ISCHARSPACE(*lp))
1454 isComment = (*lp == ';');
1456 if (!isComment || (isComment && !options.noPeepComments))
1462 *head = currL = newLineNode (lines);
1464 currL = connectLine (currL, newLineNode (lines));
1465 currL->isComment = isComment;
1466 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1475 /*-----------------------------------------------------------------*/
1476 /* readRules - reads the rules from a string buffer */
1477 /*-----------------------------------------------------------------*/
1479 readRules (char *bp)
1482 char lines[MAX_PATTERN_LEN];
1486 lineNode *currL = NULL;
1492 /* look for the token "replace" that is the
1494 while (*bp && strncmp (bp, "replace", 7))
1501 /* then look for either "restart" or '{' */
1502 while (strncmp (bp, "restart", 7) &&
1509 fprintf (stderr, "expected 'restart' or '{'\n");
1517 { /* must be restart */
1519 bp += strlen ("restart");
1521 EXPECT_CHR (bp, '{', "expected '{'\n");
1525 /* skip thru all the blank space */
1526 SKIP_SPACE (bp, "unexpected end of rule\n");
1528 match = replace = currL = NULL;
1529 /* we are the start of a rule */
1530 getPeepLine (&match, &bp);
1532 /* now look for by */
1533 EXPECT_STR (bp, "by", "expected 'by'\n");
1535 /* then look for a '{' */
1536 EXPECT_CHR (bp, '{', "expected '{'\n");
1539 /* save char position (needed for generating error msg) */
1542 SKIP_SPACE (bp, "unexpected end of rule\n");
1543 getPeepLine (&replace, &bp);
1545 /* look for a 'if' */
1546 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1549 if (strncmp (bp, "if", 2) == 0)
1552 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1556 fprintf (stderr, "expected condition name\n");
1560 /* look for the condition */
1562 while (*bp && (*bp != '\n'))
1568 newPeepRule (match, replace, lines, restart);
1572 if (*bp && strncmp (bp, "replace", 7))
1574 /* not the start of a new peeprule, so "if" should be here */
1579 /* go to the start of the line following "{" of the "by" token */
1580 while (*rp && (*rp == '\n'))
1583 /* copy text of rule starting with line after "by {" */
1585 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1588 /* and now the rest of the line */
1589 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1593 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1596 newPeepRule (match, replace, NULL, restart);
1602 /*-----------------------------------------------------------------*/
1603 /* keyForVar - returns the numeric key for a var */
1604 /*-----------------------------------------------------------------*/
1610 while (ISCHARDIGIT (*d))
1619 /*-----------------------------------------------------------------*/
1620 /* bindVar - binds a value to a variable in the given hashtable */
1621 /*-----------------------------------------------------------------*/
1623 bindVar (int key, char **s, hTab ** vtab)
1625 char vval[MAX_PATTERN_LEN];
1629 /* first get the value of the variable */
1631 /* the value is ended by a ',' or space or newline or null or ) */
1634 !ISCHARSPACE (*vvx) &&
1640 /* if we find a '(' then we need to balance it */
1652 // include the trailing ')'
1661 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1663 hTabAddItem (vtab, key, vvx);
1666 /*-----------------------------------------------------------------*/
1667 /* matchLine - matches one line */
1668 /*-----------------------------------------------------------------*/
1670 matchLine (char *s, char *d, hTab ** vars)
1679 /* skip white space in both */
1680 while (ISCHARSPACE (*s))
1682 while (ISCHARSPACE (*d))
1685 /* if the destination is a var */
1686 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1688 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1689 /* if the variable is already bound
1690 then it MUST match with dest */
1698 /* variable not bound we need to bind it */
1699 bindVar (keyForVar (d + 1), &s, vars);
1701 /* in either case go past the variable */
1703 while (ISCHARDIGIT (*d))
1706 while (ISCHARSPACE (*s))
1708 while (ISCHARSPACE (*d))
1712 /* they should be an exact match other wise */
1721 /* get rid of the trailing spaces
1722 in both source & destination */
1724 while (ISCHARSPACE (*s))
1728 while (ISCHARSPACE (*d))
1731 /* after all this if only one of them
1732 has something left over then no match */
1739 /*-----------------------------------------------------------------*/
1740 /* matchRule - matches a all the rule lines */
1741 /*-----------------------------------------------------------------*/
1743 matchRule (lineNode * pl,
1748 lineNode *spl; /* source pl */
1749 lineNode *rpl; /* rule peep line */
1751 /* setToNull((void *) &pr->vars); */
1752 /* pr->vars = newHashTable(100); */
1754 /* for all the lines defined in the rule */
1760 /* if the source line starts with a ';' then
1761 comment line don't process or the source line
1762 contains == . debugger information skip it */
1764 (*spl->line == ';' || spl->isDebug))
1770 if (!matchLine (spl->line, rpl->line, &pr->vars))
1778 /* if rules ended */
1781 /* if this rule has additional conditions */
1784 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1803 reassociate_ic_down (lineNode *shead, lineNode *stail,
1804 lineNode *rhead, lineNode *rtail)
1806 lineNode *csl; /* current source line */
1807 lineNode *crl; /* current replacement line */
1813 /* skip over any comments */
1814 while (csl!=stail->next && csl->isComment)
1816 while (crl!=rtail->next && crl->isComment)
1819 /* quit if we reach the end */
1820 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1823 if (matchLine(csl->line,crl->line,NULL))
1835 reassociate_ic_up (lineNode *shead, lineNode *stail,
1836 lineNode *rhead, lineNode *rtail)
1838 lineNode *csl; /* current source line */
1839 lineNode *crl; /* current replacement line */
1845 /* skip over any comments */
1846 while (csl!=shead->prev && csl->isComment)
1848 while (crl!=rhead->prev && crl->isComment)
1851 /* quit if we reach the end */
1852 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1855 if (matchLine(csl->line,crl->line,NULL))
1866 /*------------------------------------------------------------------*/
1867 /* reassociate_ic - reassociate replacement lines with origin iCode */
1868 /*------------------------------------------------------------------*/
1870 reassociate_ic (lineNode *shead, lineNode *stail,
1871 lineNode *rhead, lineNode *rtail)
1873 lineNode *csl; /* current source line */
1874 lineNode *crl; /* current replacement line */
1878 /* Check to see if all the source lines (excluding comments) came
1879 ** for the same iCode
1882 for (csl=shead;csl!=stail->next;csl=csl->next)
1883 if (csl->ic && !csl->isComment)
1888 single_iCode = (ic!=NULL);
1889 for (csl=shead;csl!=stail->next;csl=csl->next)
1890 if ((csl->ic != ic) && !csl->isComment)
1892 /* More than one iCode was found. However, if it's just the
1893 ** last line with the different iCode and it was not changed
1894 ** in the replacement, everything else must be the first iCode.
1896 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1898 rtail->ic = stail->ic;
1899 for (crl=rhead;crl!=rtail;crl=crl->next)
1904 single_iCode = FALSE;
1908 /* If all of the source lines came from the same iCode, then so have
1909 ** all of the replacement lines too.
1913 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1918 /* The source lines span iCodes, so we may end up with replacement
1919 ** lines that we don't know which iCode(s) to associate with. Do the
1920 ** best we can by using the following strategies:
1921 ** 1) Start at the top and scan down. As long as the source line
1922 ** matches the replacement line, they have the same iCode.
1923 ** 2) Start at the bottom and scan up. As long as the source line
1924 ** matches the replacement line, they have the same iCode.
1925 ** 3) For any label in the source, look for a matching label in
1926 ** the replacment. If found, they have the same iCode. From
1927 ** these matching labels, scan down for additional matching
1928 ** lines; if found, they also have the same iCode.
1931 /* Strategy #1: Start at the top and scan down for matches
1933 reassociate_ic_down(shead,stail,rhead,rtail);
1935 /* Strategy #2: Start at the bottom and scan up for matches
1937 reassociate_ic_up(shead,stail,rhead,rtail);
1939 /* Strategy #3: Try to match labels
1944 /* skip over any comments */
1945 while (csl!=stail->next && csl->isComment)
1947 if (csl==stail->next)
1952 /* found a source line label; look for it in the replacment lines */
1956 while (crl!=rtail->next && crl->isComment)
1958 if (crl==rtail->next)
1960 if (matchLine(csl->line, crl->line, NULL))
1962 reassociate_ic_down(csl,stail,crl,rtail);
1972 /* Try to assign a meaningful iCode to any comment that is missing
1973 one. Since they are comments, it's ok to make mistakes; we are just
1974 trying to improve continuity to simplify other tests.
1977 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1979 if (!crl->ic && ic && crl->isComment)
1986 /*-----------------------------------------------------------------*/
1987 /* replaceRule - does replacement of a matching pattern */
1988 /*-----------------------------------------------------------------*/
1990 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1992 lineNode *cl = NULL;
1993 lineNode *pl = NULL, *lhead = NULL;
1994 /* a long function name and long variable name can evaluate to
1995 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1996 char lb[MAX_PATTERN_LEN*4];
1998 lineNode *comment = NULL;
2000 /* collect all the comment lines in the source */
2001 for (cl = *shead; cl != stail; cl = cl->next)
2003 if (cl->line && (*cl->line == ';' || cl->isDebug))
2005 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2006 (comment = newLineNode (cl->line)));
2007 pl->isDebug = cl->isDebug;
2008 pl->isComment = cl->isComment || (*cl->line == ';');
2013 /* for all the lines in the replacement pattern do */
2014 for (pl = pr->replace; pl; pl = pl->next)
2024 /* if the line contains a variable */
2025 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2027 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2030 fprintf (stderr, "used unbound variable in replacement\n");
2038 while (ISCHARDIGIT (*l)) {
2048 cl = connectLine (cl, newLineNode (lb));
2050 lhead = cl = newLineNode (lb);
2051 cl->isComment = pl->isComment;
2052 cl->isLabel = pl->isLabel;
2055 /* add the comments if any to the head of list */
2058 lineNode *lc = comment;
2069 /* determine which iCodes the replacment lines relate to */
2070 reassociate_ic(*shead,stail,lhead,cl);
2072 /* now we need to connect / replace the original chain */
2073 /* if there is a prev then change it */
2076 (*shead)->prev->next = lhead;
2077 lhead->prev = (*shead)->prev;
2080 /* now for the tail */
2081 if (stail && stail->next)
2083 stail->next->prev = cl;
2085 cl->next = stail->next;
2090 /* the replacement is empty - delete the source lines */
2092 (*shead)->prev->next = stail->next;
2094 stail->next->prev = (*shead)->prev;
2095 *shead = stail->next;
2099 /* Returns TRUE if this line is a label definition.
2101 * If so, start will point to the start of the label name,
2102 * and len will be it's length.
2105 isLabelDefinition (const char *line, const char **start, int *len,
2108 const char *cp = line;
2110 /* This line is a label if if consists of:
2111 * [optional whitespace] followed by identifier chars
2112 * (alnum | $ | _ ) followed by a colon.
2115 while (*cp && ISCHARSPACE (*cp))
2127 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2128 (isPeepRule && (*cp == '%')))
2133 if ((cp == *start) || (*cp != ':'))
2138 *len = (cp - (*start));
2142 /* Quick & dirty string hash function. */
2144 hashSymbolName (const char *name)
2150 hash = (hash << 6) ^ *name;
2159 return hash % HTAB_SIZE;
2162 /* Build a hash of all labels in the passed set of lines
2163 * and how many times they are referenced.
2166 buildLabelRefCountHash (lineNode * head)
2173 assert (labelHash == NULL);
2174 labelHash = newHashTable (HTAB_SIZE);
2176 /* First pass: locate all the labels. */
2177 for (line = head; line; line = line->next)
2179 if (line->isLabel ||
2182 /* run isLabelDefinition to:
2183 - look for labels in inline assembler
2184 - calculate labelLen
2186 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2187 labelLen <= SDCC_NAME_MAX)
2189 labelHashEntry *entry;
2191 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2193 memcpy (entry->name, label, labelLen);
2194 entry->name[labelLen] = 0;
2195 entry->refCount = -1;
2197 /* Assume function entry points are referenced somewhere, */
2198 /* even if we can't find a reference (might be from outside */
2200 if (line->ic && (line->ic->op == FUNCTION))
2203 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2209 /* Second pass: for each line, note all the referenced labels. */
2210 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2214 for (i = 0; i < HTAB_SIZE; i++)
2216 labelHashEntry *thisEntry;
2218 thisEntry = hTabFirstItemWK (labelHash, i);
2222 if (strstr (line->line, thisEntry->name))
2224 thisEntry->refCount++;
2226 thisEntry = hTabNextItemWK (labelHash);
2233 /* Spew the contents of the table. Debugging fun only. */
2234 for (i = 0; i < HTAB_SIZE; i++)
2236 labelHashEntry *thisEntry;
2238 thisEntry = hTabFirstItemWK (labelHash, i);
2242 fprintf (stderr, "label: %s ref %d\n",
2243 thisEntry->name, thisEntry->refCount);
2244 thisEntry = hTabNextItemWK (labelHash);
2250 /* How does this work?
2256 replace and restart.
2261 Where is stuff allocated?
2265 /*-----------------------------------------------------------------*/
2266 /* peepHole - matches & substitutes rules */
2267 /*-----------------------------------------------------------------*/
2269 peepHole (lineNode ** pls)
2273 lineNode *mtail = NULL;
2274 bool restart, replaced;
2276 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2277 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2278 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2282 assert(labelHash == NULL);
2289 for (pr = rootRules; pr; pr = pr->next)
2291 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2295 /* if inline assembler then no peep hole */
2299 /* don't waste time starting a match on debug symbol
2301 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2306 /* Tidy up any data stored in the hTab */
2309 if (matchRule (spl, &mtail, pr, *pls))
2311 /* restart at the replaced line */
2317 replaceRule (pls, mtail, pr);
2321 replaceRule (&spl, mtail, pr);
2323 /* if restart rule type then
2324 start at the top again */
2333 hTabDeleteAll (pr->vars);
2334 Safe_free (pr->vars);
2338 freeTrace (&_G.values);
2341 } while (restart == TRUE);
2345 hTabDeleteAll (labelHash);
2346 freeTrace (&_G.labels);
2352 /*-----------------------------------------------------------------*/
2353 /* readFileIntoBuffer - reads a file into a string buffer */
2354 /*-----------------------------------------------------------------*/
2356 readFileIntoBuffer (char *fname)
2362 char lb[MAX_PATTERN_LEN];
2364 if (!(f = fopen (fname, "r")))
2366 fprintf (stderr, "cannot open peep rule file\n");
2370 while ((ch = fgetc (f)) != EOF)
2374 /* if we maxed out our local buffer */
2375 if (nch >= (MAX_PATTERN_LEN - 2))
2378 /* copy it into allocated buffer */
2381 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2382 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2386 rs = Safe_strdup (lb);
2392 /* if some charaters left over */
2396 /* copy it into allocated buffer */
2399 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2400 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2404 rs = Safe_strdup (lb);
2410 /*-----------------------------------------------------------------*/
2411 /* initPeepHole - initialises the peep hole optimizer stuff */
2412 /*-----------------------------------------------------------------*/
2418 /* read in the default rules */
2419 if (!options.nopeep)
2421 readRules (port->peep.default_rules);
2424 /* if we have any additional file read it too */
2425 if (options.peep_file)
2427 readRules (s = readFileIntoBuffer (options.peep_file));
2428 setToNull ((void *) &s);
2429 /* override nopeep setting, default rules have not been read */
2434 #if !OPT_DISABLE_PIC
2435 /* Convert the peep rules into pcode.
2436 NOTE: this is only support in the PIC port (at the moment)
2439 peepRules2pCode(rootRules);
2442 #if !OPT_DISABLE_PIC16
2443 /* Convert the peep rules into pcode.
2444 NOTE: this is only support in the PIC port (at the moment)
2445 and the PIC16 port (VR 030601)
2447 if (TARGET_IS_PIC16)
2448 pic16_peepRules2pCode(rootRules);