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 &&
826 !strcmp(SPIL_LOC (op)->rname, symname)) ))
828 return !op->isvolatile;
831 op = IC_JTCOND (cl->ic);
833 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
834 (OP_SYMBOL (op)->isspilt &&
836 !strcmp(SPIL_LOC (op)->rname, symname)) ))
838 return !op->isvolatile;
841 op = IC_LEFT (cl->ic);
843 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
844 (OP_SYMBOL (op)->isspilt &&
846 !strcmp(SPIL_LOC (op)->rname, symname)) ))
848 return !op->isvolatile;
850 op = IC_RIGHT (cl->ic);
852 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
853 (OP_SYMBOL (op)->isspilt &&
855 !strcmp(SPIL_LOC (op)->rname, symname)) ))
857 return !op->isvolatile;
859 op = IC_RESULT (cl->ic);
861 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
862 (OP_SYMBOL (op)->isspilt &&
864 !strcmp(SPIL_LOC (op)->rname, symname)) ))
866 return !op->isvolatile;
872 /* Couldn't find the symbol for some reason. Assume volatile. */
878 * This rule restriction has two different behaviours depending on
879 * the number of parameters given.
881 * if notVolatile (no parameters given)
882 * The rule is applied only if none of the iCodes originating
883 * the matched pattern reference a volatile operand.
885 * if notVolatile %1 ... (one or more parameters given)
886 * The rule is applied if the parameters are not expressions
887 * containing volatile symbols and are not pointer accesses.
890 FBYNAME (notVolatile)
901 /* If no parameters given, just scan the iCodes for volatile operands */
902 for (cl = currPl; cl!=endPl->next; cl = cl->next)
909 op = IC_COND (cl->ic);
910 if (IS_SYMOP (op) && op->isvolatile)
913 op = IC_JTCOND (cl->ic);
914 if (IS_SYMOP (op) && op->isvolatile)
917 op = IC_LEFT (cl->ic);
918 if (IS_SYMOP (op) && op->isvolatile)
920 op = IC_RIGHT (cl->ic);
921 if (IS_SYMOP (op) && op->isvolatile)
923 op = IC_RESULT (cl->ic);
924 if (IS_SYMOP (op) && op->isvolatile)
932 /* There were parameters; check the volatility of each */
933 while (*cmdLine && ISCHARSPACE(*cmdLine))
940 if (!ISCHARDIGIT(*cmdLine))
942 varNumber = strtol(cmdLine, &digitend, 10);
944 while (*cmdLine && ISCHARSPACE(*cmdLine))
947 var = hTabItemWithKey (vars, varNumber);
951 notvol = notVolatileVariable (var, currPl, endPl);
957 fprintf (stderr, "*** internal error: var %d not bound"
958 " in peephole notVolatile rule.\n",
968 "*** internal error: notVolatile peephole restriction"
969 " malformed: %s\n", cmdLine);
973 /*------------------------------------------------------------------*/
974 /* setFromConditionArgs - parse a peephole condition's arguments */
975 /* to produce a set of strings, one per argument. Variables %x will */
976 /* be replaced with their values. String literals (in single quotes)*/
977 /* are accepted and return in unquoted form. */
978 /*------------------------------------------------------------------*/
980 setFromConditionArgs (char *cmdLine, hTab * vars)
985 set *operands = NULL;
990 while (*cmdLine && ISCHARSPACE(*cmdLine))
998 if (!ISCHARDIGIT(*cmdLine))
1000 varNumber = strtol(cmdLine, &digitend, 10);
1003 var = hTabItemWithKey (vars, varNumber);
1007 addSetHead (&operands, var);
1012 else if (*cmdLine == '\'' )
1014 char quote = *cmdLine;
1017 while (*cmdLine && *cmdLine != quote)
1019 if (*cmdLine == quote)
1023 addSetHead (&operands, var);
1028 while (*cmdLine && ISCHARSPACE(*cmdLine))
1035 deleteSet (&operands);
1040 operandBaseName (const char *op)
1042 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1044 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1046 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1053 /*-------------------------------------------------------------------*/
1054 /* operandsNotRelated - returns true if the condition's operands are */
1055 /* not related (taking into account register name aliases). N-way */
1056 /* comparison performed between all operands. */
1057 /*-------------------------------------------------------------------*/
1058 FBYNAME (operandsNotRelated)
1061 const char *op1, *op2;
1063 operands = setFromConditionArgs (cmdLine, vars);
1068 "*** internal error: operandsNotRelated peephole restriction"
1069 " malformed: %s\n", cmdLine);
1073 while ((op1 = setFirstItem (operands)))
1075 deleteSetItem (&operands, (void*)op1);
1076 op1 = operandBaseName (op1);
1078 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1080 op2 = operandBaseName (op2);
1081 if (strcmp (op1, op2) == 0)
1083 deleteSet (&operands);
1089 deleteSet (&operands);
1093 /*-------------------------------------------------------------------*/
1094 /* operandsLiteral - returns true of the condition's operands are */
1096 /*-------------------------------------------------------------------*/
1097 FBYNAME (operandsLiteral)
1102 operands = setFromConditionArgs (cmdLine, vars);
1107 "*** internal error: operandsLiteral peephole restriction"
1108 " malformed: %s\n", cmdLine);
1112 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1116 deleteSet (&operands);
1121 deleteSet (&operands);
1125 static const struct ftab
1128 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1130 ftab[] = // sorted on the number of times used
1131 { // in the peephole rules on 2007-10-29
1133 "labelRefCount", labelRefCount //105
1136 "notVolatile", notVolatile //85
1139 "labelRefCountChange", labelRefCountChange //74
1142 "labelInRange", labelInRange //37
1145 "labelJTInRange", labelJTInRange //13
1148 "operandsNotRelated", operandsNotRelated //9
1151 "24bitMode", flat24bitMode //9
1154 "operandsNotSame", operandsNotSame //8
1157 "operandsNotSame3", operandsNotSame3
1160 "operandsNotSame4", operandsNotSame4
1163 "operandsNotSame5", operandsNotSame5
1166 "operandsNotSame6", operandsNotSame6
1169 "operandsNotSame7", operandsNotSame7
1172 "operandsNotSame8", operandsNotSame8
1175 "xramMovcOption", xramMovcOption
1178 "portIsDS390", portIsDS390
1181 "labelIsReturnOnly", labelIsReturnOnly
1184 "labelIsUncondJump", labelIsUncondJump
1187 "okToRemoveSLOC", okToRemoveSLOC
1190 "deadMove", deadMove
1193 "operandsLiteral", operandsLiteral
1196 "useAcallAjmp", useAcallAjmp
1199 /*-----------------------------------------------------------------*/
1200 /* callFuncByName - calls a function as defined in the table */
1201 /*-----------------------------------------------------------------*/
1203 callFuncByName (char *fname,
1210 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1214 /* Isolate the function name part (we are passed the full condition
1215 * string including arguments)
1217 cmdTerm = cmdCopy = Safe_strdup(fname);
1221 funcArgs = funcName = cmdTerm;
1222 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1224 *funcArgs = '\0'; /* terminate the function name */
1228 /* Find the start of the arguments */
1229 if (c == ' ' || c == '\t')
1230 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1233 /* If the arguments started with an opening parenthesis, */
1234 /* use the closing parenthesis for the end of the */
1235 /* arguments and look for the start of another condition */
1236 /* that can optionally follow. If there was no opening */
1237 /* parethesis, then everything that follows are arguments */
1238 /* and there can be no additional conditions. */
1242 while ((c = *cmdTerm) && c != ')')
1244 *cmdTerm = '\0'; /* terminate the arguments */
1248 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1254 cmdTerm = NULL; /* closing parenthesis missing */
1263 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1265 if (strcmp (ftab[i].fname, funcName) == 0)
1267 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1275 "could not find named function \"%s\" in "
1276 "peephole function table\n",
1278 // If the function couldn't be found, let's assume it's
1279 // a bad rule and refuse it.
1284 while (rc && cmdTerm);
1291 /*-----------------------------------------------------------------*/
1292 /* printLine - prints a line chain into a given file */
1293 /*-----------------------------------------------------------------*/
1295 printLine (lineNode * head, struct dbuf_s * oBuf)
1297 iCode *last_ic = NULL;
1298 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1302 if (head->ic!=last_ic)
1305 if (debug_iCode_tracking)
1308 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1309 head->ic->block, head->ic->seq);
1311 dbuf_append_str (oBuf, "; iCode lost\n");
1315 /* don't indent comments & labels */
1317 (head->isComment || head->isLabel)) {
1318 dbuf_printf (oBuf, "%s\n", head->line);
1320 if (head->isInline && *head->line=='#') {
1321 // comment out preprocessor directives in inline asm
1322 dbuf_append_char (oBuf, ';');
1324 dbuf_printf (oBuf, "\t%s\n", head->line);
1330 /*-----------------------------------------------------------------*/
1331 /* newPeepRule - creates a new peeprule and attach it to the root */
1332 /*-----------------------------------------------------------------*/
1334 newPeepRule (lineNode * match,
1341 pr = Safe_alloc ( sizeof (peepRule));
1343 pr->replace = replace;
1344 pr->restart = restart;
1348 pr->cond = Safe_strdup (cond);
1353 pr->vars = newHashTable (100);
1355 /* if root is empty */
1357 rootRules = currRule = pr;
1359 currRule = currRule->next = pr;
1364 /*-----------------------------------------------------------------*/
1365 /* newLineNode - creates a new peep line */
1366 /*-----------------------------------------------------------------*/
1368 newLineNode (const char *line)
1372 pl = Safe_alloc ( sizeof (lineNode));
1373 pl->line = Safe_strdup (line);
1378 /*-----------------------------------------------------------------*/
1379 /* connectLine - connects two lines */
1380 /*-----------------------------------------------------------------*/
1382 connectLine (lineNode * pl1, lineNode * pl2)
1386 fprintf (stderr, "trying to connect null line\n");
1396 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1397 if (!*x) { fprintf(stderr,y); return ; } }
1399 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1400 if (!*x) { fprintf(stderr,z); return ; } }
1401 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1402 if (!*x) { fprintf(stderr,z); return ; } }
1404 /*-----------------------------------------------------------------*/
1405 /* getPeepLine - parses the peep lines */
1406 /*-----------------------------------------------------------------*/
1408 getPeepLine (lineNode ** head, char **bpp)
1410 char lines[MAX_PATTERN_LEN];
1414 lineNode *currL = NULL;
1421 fprintf (stderr, "unexpected end of match pattern\n");
1428 while (ISCHARSPACE (*bp) ||
1439 /* read till end of line */
1441 while ((*bp != '\n' && *bp != '}') && *bp)
1446 while (*lp && ISCHARSPACE(*lp))
1448 isComment = (*lp == ';');
1450 if (!isComment || (isComment && !options.noPeepComments))
1456 *head = currL = newLineNode (lines);
1458 currL = connectLine (currL, newLineNode (lines));
1459 currL->isComment = isComment;
1460 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1469 /*-----------------------------------------------------------------*/
1470 /* readRules - reads the rules from a string buffer */
1471 /*-----------------------------------------------------------------*/
1473 readRules (char *bp)
1476 char lines[MAX_PATTERN_LEN];
1480 lineNode *currL = NULL;
1486 /* look for the token "replace" that is the
1488 while (*bp && strncmp (bp, "replace", 7))
1495 /* then look for either "restart" or '{' */
1496 while (strncmp (bp, "restart", 7) &&
1503 fprintf (stderr, "expected 'restart' or '{'\n");
1511 { /* must be restart */
1513 bp += strlen ("restart");
1515 EXPECT_CHR (bp, '{', "expected '{'\n");
1519 /* skip thru all the blank space */
1520 SKIP_SPACE (bp, "unexpected end of rule\n");
1522 match = replace = currL = NULL;
1523 /* we are the start of a rule */
1524 getPeepLine (&match, &bp);
1526 /* now look for by */
1527 EXPECT_STR (bp, "by", "expected 'by'\n");
1529 /* then look for a '{' */
1530 EXPECT_CHR (bp, '{', "expected '{'\n");
1533 /* save char position (needed for generating error msg) */
1536 SKIP_SPACE (bp, "unexpected end of rule\n");
1537 getPeepLine (&replace, &bp);
1539 /* look for a 'if' */
1540 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1543 if (strncmp (bp, "if", 2) == 0)
1546 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1550 fprintf (stderr, "expected condition name\n");
1554 /* look for the condition */
1556 while (*bp && (*bp != '\n'))
1562 newPeepRule (match, replace, lines, restart);
1566 if (*bp && strncmp (bp, "replace", 7))
1568 /* not the start of a new peeprule, so "if" should be here */
1573 /* go to the start of the line following "{" of the "by" token */
1574 while (*rp && (*rp == '\n'))
1577 /* copy text of rule starting with line after "by {" */
1579 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1582 /* and now the rest of the line */
1583 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1587 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1590 newPeepRule (match, replace, NULL, restart);
1596 /*-----------------------------------------------------------------*/
1597 /* keyForVar - returns the numeric key for a var */
1598 /*-----------------------------------------------------------------*/
1604 while (ISCHARDIGIT (*d))
1613 /*-----------------------------------------------------------------*/
1614 /* bindVar - binds a value to a variable in the given hashtable */
1615 /*-----------------------------------------------------------------*/
1617 bindVar (int key, char **s, hTab ** vtab)
1619 char vval[MAX_PATTERN_LEN];
1623 /* first get the value of the variable */
1625 /* the value is ended by a ',' or space or newline or null or ) */
1628 !ISCHARSPACE (*vvx) &&
1634 /* if we find a '(' then we need to balance it */
1646 // include the trailing ')'
1655 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1657 hTabAddItem (vtab, key, vvx);
1660 /*-----------------------------------------------------------------*/
1661 /* matchLine - matches one line */
1662 /*-----------------------------------------------------------------*/
1664 matchLine (char *s, char *d, hTab ** vars)
1673 /* skip white space in both */
1674 while (ISCHARSPACE (*s))
1676 while (ISCHARSPACE (*d))
1679 /* if the destination is a var */
1680 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1682 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1683 /* if the variable is already bound
1684 then it MUST match with dest */
1692 /* variable not bound we need to bind it */
1693 bindVar (keyForVar (d + 1), &s, vars);
1695 /* in either case go past the variable */
1697 while (ISCHARDIGIT (*d))
1700 while (ISCHARSPACE (*s))
1702 while (ISCHARSPACE (*d))
1706 /* they should be an exact match other wise */
1715 /* get rid of the trailing spaces
1716 in both source & destination */
1718 while (ISCHARSPACE (*s))
1722 while (ISCHARSPACE (*d))
1725 /* after all this if only one of them
1726 has something left over then no match */
1733 /*-----------------------------------------------------------------*/
1734 /* matchRule - matches a all the rule lines */
1735 /*-----------------------------------------------------------------*/
1737 matchRule (lineNode * pl,
1742 lineNode *spl; /* source pl */
1743 lineNode *rpl; /* rule peep line */
1745 /* setToNull((void *) &pr->vars); */
1746 /* pr->vars = newHashTable(100); */
1748 /* for all the lines defined in the rule */
1754 /* if the source line starts with a ';' then
1755 comment line don't process or the source line
1756 contains == . debugger information skip it */
1758 (*spl->line == ';' || spl->isDebug))
1764 if (!matchLine (spl->line, rpl->line, &pr->vars))
1772 /* if rules ended */
1775 /* if this rule has additional conditions */
1778 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1797 reassociate_ic_down (lineNode *shead, lineNode *stail,
1798 lineNode *rhead, lineNode *rtail)
1800 lineNode *csl; /* current source line */
1801 lineNode *crl; /* current replacement line */
1807 /* skip over any comments */
1808 while (csl!=stail->next && csl->isComment)
1810 while (crl!=rtail->next && crl->isComment)
1813 /* quit if we reach the end */
1814 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1817 if (matchLine(csl->line,crl->line,NULL))
1829 reassociate_ic_up (lineNode *shead, lineNode *stail,
1830 lineNode *rhead, lineNode *rtail)
1832 lineNode *csl; /* current source line */
1833 lineNode *crl; /* current replacement line */
1839 /* skip over any comments */
1840 while (csl!=shead->prev && csl->isComment)
1842 while (crl!=rhead->prev && crl->isComment)
1845 /* quit if we reach the end */
1846 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1849 if (matchLine(csl->line,crl->line,NULL))
1860 /*------------------------------------------------------------------*/
1861 /* reassociate_ic - reassociate replacement lines with origin iCode */
1862 /*------------------------------------------------------------------*/
1864 reassociate_ic (lineNode *shead, lineNode *stail,
1865 lineNode *rhead, lineNode *rtail)
1867 lineNode *csl; /* current source line */
1868 lineNode *crl; /* current replacement line */
1872 /* Check to see if all the source lines (excluding comments) came
1873 ** for the same iCode
1876 for (csl=shead;csl!=stail->next;csl=csl->next)
1877 if (csl->ic && !csl->isComment)
1882 single_iCode = (ic!=NULL);
1883 for (csl=shead;csl!=stail->next;csl=csl->next)
1884 if ((csl->ic != ic) && !csl->isComment)
1886 /* More than one iCode was found. However, if it's just the
1887 ** last line with the different iCode and it was not changed
1888 ** in the replacement, everything else must be the first iCode.
1890 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1892 rtail->ic = stail->ic;
1893 for (crl=rhead;crl!=rtail;crl=crl->next)
1898 single_iCode = FALSE;
1902 /* If all of the source lines came from the same iCode, then so have
1903 ** all of the replacement lines too.
1907 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1912 /* The source lines span iCodes, so we may end up with replacement
1913 ** lines that we don't know which iCode(s) to associate with. Do the
1914 ** best we can by using the following strategies:
1915 ** 1) Start at the top and scan down. As long as the source line
1916 ** matches the replacement line, they have the same iCode.
1917 ** 2) Start at the bottom and scan up. As long as the source line
1918 ** matches the replacement line, they have the same iCode.
1919 ** 3) For any label in the source, look for a matching label in
1920 ** the replacment. If found, they have the same iCode. From
1921 ** these matching labels, scan down for additional matching
1922 ** lines; if found, they also have the same iCode.
1925 /* Strategy #1: Start at the top and scan down for matches
1927 reassociate_ic_down(shead,stail,rhead,rtail);
1929 /* Strategy #2: Start at the bottom and scan up for matches
1931 reassociate_ic_up(shead,stail,rhead,rtail);
1933 /* Strategy #3: Try to match labels
1938 /* skip over any comments */
1939 while (csl!=stail->next && csl->isComment)
1941 if (csl==stail->next)
1946 /* found a source line label; look for it in the replacment lines */
1950 while (crl!=rtail->next && crl->isComment)
1952 if (crl==rtail->next)
1954 if (matchLine(csl->line, crl->line, NULL))
1956 reassociate_ic_down(csl,stail,crl,rtail);
1966 /* Try to assign a meaningful iCode to any comment that is missing
1967 one. Since they are comments, it's ok to make mistakes; we are just
1968 trying to improve continuity to simplify other tests.
1971 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1973 if (!crl->ic && ic && crl->isComment)
1980 /*-----------------------------------------------------------------*/
1981 /* replaceRule - does replacement of a matching pattern */
1982 /*-----------------------------------------------------------------*/
1984 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1986 lineNode *cl = NULL;
1987 lineNode *pl = NULL, *lhead = NULL;
1988 /* a long function name and long variable name can evaluate to
1989 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1990 char lb[MAX_PATTERN_LEN*4];
1992 lineNode *comment = NULL;
1994 /* collect all the comment lines in the source */
1995 for (cl = *shead; cl != stail; cl = cl->next)
1997 if (cl->line && (*cl->line == ';' || cl->isDebug))
1999 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2000 (comment = newLineNode (cl->line)));
2001 pl->isDebug = cl->isDebug;
2002 pl->isComment = cl->isComment || (*cl->line == ';');
2007 /* for all the lines in the replacement pattern do */
2008 for (pl = pr->replace; pl; pl = pl->next)
2018 /* if the line contains a variable */
2019 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2021 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2024 fprintf (stderr, "used unbound variable in replacement\n");
2032 while (ISCHARDIGIT (*l)) {
2042 cl = connectLine (cl, newLineNode (lb));
2044 lhead = cl = newLineNode (lb);
2045 cl->isComment = pl->isComment;
2046 cl->isLabel = pl->isLabel;
2049 /* add the comments if any to the head of list */
2052 lineNode *lc = comment;
2063 /* determine which iCodes the replacment lines relate to */
2064 reassociate_ic(*shead,stail,lhead,cl);
2066 /* now we need to connect / replace the original chain */
2067 /* if there is a prev then change it */
2070 (*shead)->prev->next = lhead;
2071 lhead->prev = (*shead)->prev;
2074 /* now for the tail */
2075 if (stail && stail->next)
2077 stail->next->prev = cl;
2079 cl->next = stail->next;
2084 /* the replacement is empty - delete the source lines */
2086 (*shead)->prev->next = stail->next;
2088 stail->next->prev = (*shead)->prev;
2089 *shead = stail->next;
2093 /* Returns TRUE if this line is a label definition.
2095 * If so, start will point to the start of the label name,
2096 * and len will be it's length.
2099 isLabelDefinition (const char *line, const char **start, int *len,
2102 const char *cp = line;
2104 /* This line is a label if if consists of:
2105 * [optional whitespace] followed by identifier chars
2106 * (alnum | $ | _ ) followed by a colon.
2109 while (*cp && ISCHARSPACE (*cp))
2121 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2122 (isPeepRule && (*cp == '%')))
2127 if ((cp == *start) || (*cp != ':'))
2132 *len = (cp - (*start));
2136 /* Quick & dirty string hash function. */
2138 hashSymbolName (const char *name)
2144 hash = (hash << 6) ^ *name;
2153 return hash % HTAB_SIZE;
2156 /* Build a hash of all labels in the passed set of lines
2157 * and how many times they are referenced.
2160 buildLabelRefCountHash (lineNode * head)
2167 assert (labelHash == NULL);
2168 labelHash = newHashTable (HTAB_SIZE);
2170 /* First pass: locate all the labels. */
2171 for (line = head; line; line = line->next)
2173 if (line->isLabel ||
2176 /* run isLabelDefinition to:
2177 - look for labels in inline assembler
2178 - calculate labelLen
2180 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2181 labelLen <= SDCC_NAME_MAX)
2183 labelHashEntry *entry;
2185 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2187 memcpy (entry->name, label, labelLen);
2188 entry->name[labelLen] = 0;
2189 entry->refCount = -1;
2191 /* Assume function entry points are referenced somewhere, */
2192 /* even if we can't find a reference (might be from outside */
2194 if (line->ic && (line->ic->op == FUNCTION))
2197 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2203 /* Second pass: for each line, note all the referenced labels. */
2204 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2208 for (i = 0; i < HTAB_SIZE; i++)
2210 labelHashEntry *thisEntry;
2212 thisEntry = hTabFirstItemWK (labelHash, i);
2216 if (strstr (line->line, thisEntry->name))
2218 thisEntry->refCount++;
2220 thisEntry = hTabNextItemWK (labelHash);
2227 /* Spew the contents of the table. Debugging fun only. */
2228 for (i = 0; i < HTAB_SIZE; i++)
2230 labelHashEntry *thisEntry;
2232 thisEntry = hTabFirstItemWK (labelHash, i);
2236 fprintf (stderr, "label: %s ref %d\n",
2237 thisEntry->name, thisEntry->refCount);
2238 thisEntry = hTabNextItemWK (labelHash);
2244 /* How does this work?
2250 replace and restart.
2255 Where is stuff allocated?
2259 /*-----------------------------------------------------------------*/
2260 /* peepHole - matches & substitutes rules */
2261 /*-----------------------------------------------------------------*/
2263 peepHole (lineNode ** pls)
2267 lineNode *mtail = NULL;
2268 bool restart, replaced;
2270 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2271 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2272 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2276 assert(labelHash == NULL);
2283 for (pr = rootRules; pr; pr = pr->next)
2285 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2289 /* if inline assembler then no peep hole */
2293 /* don't waste time starting a match on debug symbol
2295 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2300 /* Tidy up any data stored in the hTab */
2303 if (matchRule (spl, &mtail, pr, *pls))
2305 /* restart at the replaced line */
2311 replaceRule (pls, mtail, pr);
2315 replaceRule (&spl, mtail, pr);
2317 /* if restart rule type then
2318 start at the top again */
2327 hTabDeleteAll (pr->vars);
2328 Safe_free (pr->vars);
2332 freeTrace (&_G.values);
2335 } while (restart == TRUE);
2339 hTabDeleteAll (labelHash);
2340 freeTrace (&_G.labels);
2346 /*-----------------------------------------------------------------*/
2347 /* readFileIntoBuffer - reads a file into a string buffer */
2348 /*-----------------------------------------------------------------*/
2350 readFileIntoBuffer (char *fname)
2356 char lb[MAX_PATTERN_LEN];
2358 if (!(f = fopen (fname, "r")))
2360 fprintf (stderr, "cannot open peep rule file\n");
2364 while ((ch = fgetc (f)) != EOF)
2368 /* if we maxed out our local buffer */
2369 if (nch >= (MAX_PATTERN_LEN - 2))
2372 /* copy it into allocated buffer */
2375 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2376 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2380 rs = Safe_strdup (lb);
2386 /* if some charaters left over */
2390 /* copy it into allocated buffer */
2393 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2394 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2398 rs = Safe_strdup (lb);
2404 /*-----------------------------------------------------------------*/
2405 /* initPeepHole - initialises the peep hole optimizer stuff */
2406 /*-----------------------------------------------------------------*/
2412 /* read in the default rules */
2413 if (!options.nopeep)
2415 readRules (port->peep.default_rules);
2418 /* if we have any additional file read it too */
2419 if (options.peep_file)
2421 readRules (s = readFileIntoBuffer (options.peep_file));
2422 setToNull ((void *) &s);
2423 /* override nopeep setting, default rules have not been read */
2428 #if !OPT_DISABLE_PIC
2429 /* Convert the peep rules into pcode.
2430 NOTE: this is only support in the PIC port (at the moment)
2433 peepRules2pCode(rootRules);
2436 #if !OPT_DISABLE_PIC16
2437 /* Convert the peep rules into pcode.
2438 NOTE: this is only support in the PIC port (at the moment)
2439 and the PIC16 port (VR 030601)
2441 if (TARGET_IS_PIC16)
2442 pic16_peepRules2pCode(rootRules);