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 /* notUsed - Check, if value in register is not read again */
407 /*-----------------------------------------------------------------*/
412 if(cmdLine[0] != '\'')
413 what = hTabItemWithKey (vars, 1);
416 cmdLine[strlen(cmdLine) - 1] = 0;
420 if (port->peep.notUsed)
421 return port->peep.notUsed (what, endPl, head);
423 fprintf (stderr, "Function notUsed not initialized in port structure\n");
427 /*-----------------------------------------------------------------*/
428 /* operandsNotSame - check if %1 & %2 are the same */
429 /*-----------------------------------------------------------------*/
430 FBYNAME (operandsNotSame)
432 char *op1 = hTabItemWithKey (vars, 1);
433 char *op2 = hTabItemWithKey (vars, 2);
435 if (strcmp (op1, op2) == 0)
441 /*-----------------------------------------------------------------*/
442 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
443 /*-----------------------------------------------------------------*/
444 FBYNAME (operandsNotSame3)
446 char *op1 = hTabItemWithKey (vars, 1);
447 char *op2 = hTabItemWithKey (vars, 2);
448 char *op3 = hTabItemWithKey (vars, 3);
450 if ( (strcmp (op1, op2) == 0) ||
451 (strcmp (op1, op3) == 0) ||
452 (strcmp (op2, op3) == 0) )
458 /*-----------------------------------------------------------------*/
459 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
460 /*-----------------------------------------------------------------*/
461 FBYNAME (operandsNotSame4)
463 char *op1 = hTabItemWithKey (vars, 1);
464 char *op2 = hTabItemWithKey (vars, 2);
465 char *op3 = hTabItemWithKey (vars, 3);
466 char *op4 = hTabItemWithKey (vars, 4);
468 if ( (strcmp (op1, op2) == 0) ||
469 (strcmp (op1, op3) == 0) ||
470 (strcmp (op1, op4) == 0) ||
471 (strcmp (op2, op3) == 0) ||
472 (strcmp (op2, op4) == 0) ||
473 (strcmp (op3, op4) == 0) )
479 /*-----------------------------------------------------------------*/
480 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
481 /*-----------------------------------------------------------------*/
482 FBYNAME (operandsNotSame5)
484 char *op1 = hTabItemWithKey (vars, 1);
485 char *op2 = hTabItemWithKey (vars, 2);
486 char *op3 = hTabItemWithKey (vars, 3);
487 char *op4 = hTabItemWithKey (vars, 4);
488 char *op5 = hTabItemWithKey (vars, 5);
490 if ( (strcmp (op1, op2) == 0) ||
491 (strcmp (op1, op3) == 0) ||
492 (strcmp (op1, op4) == 0) ||
493 (strcmp (op1, op5) == 0) ||
494 (strcmp (op2, op3) == 0) ||
495 (strcmp (op2, op4) == 0) ||
496 (strcmp (op2, op5) == 0) ||
497 (strcmp (op3, op4) == 0) ||
498 (strcmp (op3, op5) == 0) ||
499 (strcmp (op4, op5) == 0) )
505 /*-----------------------------------------------------------------*/
506 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
507 /*-----------------------------------------------------------------*/
508 FBYNAME (operandsNotSame6)
510 char *op1 = hTabItemWithKey (vars, 1);
511 char *op2 = hTabItemWithKey (vars, 2);
512 char *op3 = hTabItemWithKey (vars, 3);
513 char *op4 = hTabItemWithKey (vars, 4);
514 char *op5 = hTabItemWithKey (vars, 5);
515 char *op6 = hTabItemWithKey (vars, 6);
517 if ( (strcmp (op1, op2) == 0) ||
518 (strcmp (op1, op3) == 0) ||
519 (strcmp (op1, op4) == 0) ||
520 (strcmp (op1, op5) == 0) ||
521 (strcmp (op1, op6) == 0) ||
522 (strcmp (op2, op3) == 0) ||
523 (strcmp (op2, op4) == 0) ||
524 (strcmp (op2, op5) == 0) ||
525 (strcmp (op2, op6) == 0) ||
526 (strcmp (op3, op4) == 0) ||
527 (strcmp (op3, op5) == 0) ||
528 (strcmp (op3, op6) == 0) ||
529 (strcmp (op4, op5) == 0) ||
530 (strcmp (op4, op6) == 0) ||
531 (strcmp (op5, op6) == 0) )
537 /*-----------------------------------------------------------------*/
538 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
539 /*-----------------------------------------------------------------*/
540 FBYNAME (operandsNotSame7)
542 char *op1 = hTabItemWithKey (vars, 1);
543 char *op2 = hTabItemWithKey (vars, 2);
544 char *op3 = hTabItemWithKey (vars, 3);
545 char *op4 = hTabItemWithKey (vars, 4);
546 char *op5 = hTabItemWithKey (vars, 5);
547 char *op6 = hTabItemWithKey (vars, 6);
548 char *op7 = hTabItemWithKey (vars, 7);
550 if ( (strcmp (op1, op2) == 0) ||
551 (strcmp (op1, op3) == 0) ||
552 (strcmp (op1, op4) == 0) ||
553 (strcmp (op1, op5) == 0) ||
554 (strcmp (op1, op6) == 0) ||
555 (strcmp (op1, op7) == 0) ||
556 (strcmp (op2, op3) == 0) ||
557 (strcmp (op2, op4) == 0) ||
558 (strcmp (op2, op5) == 0) ||
559 (strcmp (op2, op6) == 0) ||
560 (strcmp (op2, op7) == 0) ||
561 (strcmp (op3, op4) == 0) ||
562 (strcmp (op3, op5) == 0) ||
563 (strcmp (op3, op6) == 0) ||
564 (strcmp (op3, op7) == 0) ||
565 (strcmp (op4, op5) == 0) ||
566 (strcmp (op4, op6) == 0) ||
567 (strcmp (op4, op7) == 0) ||
568 (strcmp (op5, op6) == 0) ||
569 (strcmp (op5, op7) == 0) ||
570 (strcmp (op6, op7) == 0) )
576 /*-----------------------------------------------------------------*/
577 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
578 /*-----------------------------------------------------------------*/
579 FBYNAME (operandsNotSame8)
581 char *op1 = hTabItemWithKey (vars, 1);
582 char *op2 = hTabItemWithKey (vars, 2);
583 char *op3 = hTabItemWithKey (vars, 3);
584 char *op4 = hTabItemWithKey (vars, 4);
585 char *op5 = hTabItemWithKey (vars, 5);
586 char *op6 = hTabItemWithKey (vars, 6);
587 char *op7 = hTabItemWithKey (vars, 7);
588 char *op8 = hTabItemWithKey (vars, 8);
590 if ( (strcmp (op1, op2) == 0) ||
591 (strcmp (op1, op3) == 0) ||
592 (strcmp (op1, op4) == 0) ||
593 (strcmp (op1, op5) == 0) ||
594 (strcmp (op1, op6) == 0) ||
595 (strcmp (op1, op7) == 0) ||
596 (strcmp (op1, op8) == 0) ||
597 (strcmp (op2, op3) == 0) ||
598 (strcmp (op2, op4) == 0) ||
599 (strcmp (op2, op5) == 0) ||
600 (strcmp (op2, op6) == 0) ||
601 (strcmp (op2, op7) == 0) ||
602 (strcmp (op2, op8) == 0) ||
603 (strcmp (op3, op4) == 0) ||
604 (strcmp (op3, op5) == 0) ||
605 (strcmp (op3, op6) == 0) ||
606 (strcmp (op3, op7) == 0) ||
607 (strcmp (op3, op8) == 0) ||
608 (strcmp (op4, op5) == 0) ||
609 (strcmp (op4, op6) == 0) ||
610 (strcmp (op4, op7) == 0) ||
611 (strcmp (op4, op8) == 0) ||
612 (strcmp (op5, op6) == 0) ||
613 (strcmp (op5, op7) == 0) ||
614 (strcmp (op5, op8) == 0) ||
615 (strcmp (op6, op7) == 0) ||
616 (strcmp (op6, op8) == 0) ||
617 (strcmp (op7, op8) == 0) )
623 /*-----------------------------------------------------------------*/
624 /* labelHashEntry- searches for a label in the list labelHash */
625 /* Builds labelHash, if it does not yet exist. */
626 /* Returns the labelHashEntry or NULL */
627 /*-----------------------------------------------------------------*/
629 getLabelRef (const char *label, lineNode *head)
631 labelHashEntry *entry;
633 /* If we don't have the label hash table yet, build it. */
636 buildLabelRefCountHash (head);
639 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
643 if (!strcmp (label, entry->name))
647 entry = hTabNextItemWK (labelHash);
654 * takes two parameters: a variable (bound to a label name)
655 * and an expected reference count.
657 * Returns TRUE if that label is defined and referenced exactly
658 * the given number of times.
660 FBYNAME (labelRefCount)
662 int varNumber, expectedRefCount;
665 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
667 char *label = hTabItemWithKey (vars, varNumber);
671 labelHashEntry *entry = getLabelRef (label, head);
677 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
678 label, entry->refCount, expectedRefCount);
681 rc = (expectedRefCount == entry->refCount);
685 fprintf (stderr, "*** internal error: no label has entry for"
686 " %s in labelRefCount peephole.\n",
692 fprintf (stderr, "*** internal error: var %d not bound"
693 " in peephole labelRefCount rule.\n",
701 "*** internal error: labelRefCount peephole restriction"
702 " malformed: %s\n", cmdLine);
707 /* labelRefCountChange:
708 * takes two parameters: a variable (bound to a label name)
709 * and a signed int for changing the reference count.
711 * Please note, this function is not a conditional. It unconditionally
712 * changes the label. It should be passed as the 'last' function
713 * so it only is applied if all other conditions have been met.
715 * should always return TRUE
717 FBYNAME (labelRefCountChange)
719 int varNumber, RefCountDelta;
722 /* If we don't have the label hash table yet, build it. */
725 buildLabelRefCountHash (head);
728 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
730 char *label = hTabItemWithKey (vars, varNumber);
734 labelHashEntry *entry;
736 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
740 if (!strcmp (label, entry->name))
744 entry = hTabNextItemWK (labelHash);
748 if (0 <= entry->refCount + RefCountDelta)
750 entry->refCount += RefCountDelta;
755 fprintf (stderr, "*** internal error: label %s may not get"
756 " negative refCount in %s peephole.\n",
757 label, __FUNCTION__);
762 fprintf (stderr, "*** internal error: no label has entry for"
763 " %s in %s peephole.\n",
764 label, __FUNCTION__);
769 fprintf (stderr, "*** internal error: var %d not bound"
770 " in peephole %s rule.\n",
771 varNumber, __FUNCTION__);
777 "*** internal error: labelRefCount peephole restriction"
778 " malformed: %s\n", cmdLine);
783 /* Within the context of the lines currPl through endPl, determine
784 ** if the variable var contains a symbol that is volatile. Returns
785 ** TRUE only if it is certain that this was not volatile (the symbol
786 ** was found and not volatile, or var was a constant or CPU register).
787 ** Returns FALSE if the symbol was found and volatile, the symbol was
788 ** not found, or var was a indirect/pointer addressing mode.
791 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
793 char symname[SDCC_NAME_MAX + 1];
800 /* Can't tell if indirect accesses are volatile or not, so
801 ** assume they are, just to be safe.
803 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
808 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
810 if (strstr(var,"(bc)"))
812 if (strstr(var,"(de)"))
814 if (strstr(var,"(hl)"))
816 if (strstr(var,"(ix"))
818 if (strstr(var,"(iy"))
822 /* Extract a symbol name from the variable */
823 while (*vp && (*vp!='_'))
825 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
831 /* Nothing resembling a symbol name was found, so it can't
838 for (cl = currPl; cl!=endPl->next; cl = cl->next)
840 if (cl->ic && (cl->ic!=last_ic))
846 op = IC_COND (cl->ic);
848 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
849 (OP_SYMBOL (op)->isspilt &&
851 !strcmp(SPIL_LOC (op)->rname, symname)) ))
853 return !op->isvolatile;
856 op = IC_JTCOND (cl->ic);
858 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
859 (OP_SYMBOL (op)->isspilt &&
861 !strcmp(SPIL_LOC (op)->rname, symname)) ))
863 return !op->isvolatile;
866 op = IC_LEFT (cl->ic);
868 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
869 (OP_SYMBOL (op)->isspilt &&
871 !strcmp(SPIL_LOC (op)->rname, symname)) ))
873 return !op->isvolatile;
875 op = IC_RIGHT (cl->ic);
877 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
878 (OP_SYMBOL (op)->isspilt &&
880 !strcmp(SPIL_LOC (op)->rname, symname)) ))
882 return !op->isvolatile;
884 op = IC_RESULT (cl->ic);
886 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
887 (OP_SYMBOL (op)->isspilt &&
889 !strcmp(SPIL_LOC (op)->rname, symname)) ))
891 return !op->isvolatile;
897 /* Couldn't find the symbol for some reason. Assume volatile. */
903 * This rule restriction has two different behaviours depending on
904 * the number of parameters given.
906 * if notVolatile (no parameters given)
907 * The rule is applied only if none of the iCodes originating
908 * the matched pattern reference a volatile operand.
910 * if notVolatile %1 ... (one or more parameters given)
911 * The rule is applied if the parameters are not expressions
912 * containing volatile symbols and are not pointer accesses.
915 FBYNAME (notVolatile)
926 /* If no parameters given, just scan the iCodes for volatile operands */
927 for (cl = currPl; cl!=endPl->next; cl = cl->next)
934 op = IC_COND (cl->ic);
935 if (IS_SYMOP (op) && op->isvolatile)
938 op = IC_JTCOND (cl->ic);
939 if (IS_SYMOP (op) && op->isvolatile)
942 op = IC_LEFT (cl->ic);
943 if (IS_SYMOP (op) && op->isvolatile)
945 op = IC_RIGHT (cl->ic);
946 if (IS_SYMOP (op) && op->isvolatile)
948 op = IC_RESULT (cl->ic);
949 if (IS_SYMOP (op) && op->isvolatile)
957 /* There were parameters; check the volatility of each */
958 while (*cmdLine && ISCHARSPACE(*cmdLine))
965 if (!ISCHARDIGIT(*cmdLine))
967 varNumber = strtol(cmdLine, &digitend, 10);
969 while (*cmdLine && ISCHARSPACE(*cmdLine))
972 var = hTabItemWithKey (vars, varNumber);
976 notvol = notVolatileVariable (var, currPl, endPl);
982 fprintf (stderr, "*** internal error: var %d not bound"
983 " in peephole notVolatile rule.\n",
993 "*** internal error: notVolatile peephole restriction"
994 " malformed: %s\n", cmdLine);
998 /*------------------------------------------------------------------*/
999 /* setFromConditionArgs - parse a peephole condition's arguments */
1000 /* to produce a set of strings, one per argument. Variables %x will */
1001 /* be replaced with their values. String literals (in single quotes)*/
1002 /* are accepted and return in unquoted form. */
1003 /*------------------------------------------------------------------*/
1005 setFromConditionArgs (char *cmdLine, hTab * vars)
1010 set *operands = NULL;
1015 while (*cmdLine && ISCHARSPACE(*cmdLine))
1020 if (*cmdLine == '%')
1023 if (!ISCHARDIGIT(*cmdLine))
1025 varNumber = strtol(cmdLine, &digitend, 10);
1028 var = hTabItemWithKey (vars, varNumber);
1032 addSetHead (&operands, var);
1037 else if (*cmdLine == '\'' )
1039 char quote = *cmdLine;
1042 while (*cmdLine && *cmdLine != quote)
1044 if (*cmdLine == quote)
1048 addSetHead (&operands, var);
1053 while (*cmdLine && ISCHARSPACE(*cmdLine))
1060 deleteSet (&operands);
1065 operandBaseName (const char *op)
1067 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1069 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1071 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1073 // bug 1739475, temp fix
1075 return operandBaseName(op+1);
1081 /*-------------------------------------------------------------------*/
1082 /* operandsNotRelated - returns true if the condition's operands are */
1083 /* not related (taking into account register name aliases). N-way */
1084 /* comparison performed between all operands. */
1085 /*-------------------------------------------------------------------*/
1086 FBYNAME (operandsNotRelated)
1089 const char *op1, *op2;
1091 operands = setFromConditionArgs (cmdLine, vars);
1096 "*** internal error: operandsNotRelated peephole restriction"
1097 " malformed: %s\n", cmdLine);
1101 while ((op1 = setFirstItem (operands)))
1103 deleteSetItem (&operands, (void*)op1);
1104 op1 = operandBaseName (op1);
1106 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1108 op2 = operandBaseName (op2);
1109 if (strcmp (op1, op2) == 0)
1111 deleteSet (&operands);
1117 deleteSet (&operands);
1121 /*-------------------------------------------------------------------*/
1122 /* operandsLiteral - returns true of the condition's operands are */
1124 /*-------------------------------------------------------------------*/
1125 FBYNAME (operandsLiteral)
1130 operands = setFromConditionArgs (cmdLine, vars);
1135 "*** internal error: operandsLiteral peephole restriction"
1136 " malformed: %s\n", cmdLine);
1140 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1144 deleteSet (&operands);
1149 deleteSet (&operands);
1153 static const struct ftab
1156 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1158 ftab[] = // sorted on the number of times used
1159 { // in the peephole rules on 2007-10-29
1161 "labelRefCount", labelRefCount //105
1164 "notVolatile", notVolatile //85
1167 "labelRefCountChange", labelRefCountChange //74
1170 "labelInRange", labelInRange //37
1173 "labelJTInRange", labelJTInRange //13
1176 "operandsNotRelated", operandsNotRelated //9
1179 "24bitMode", flat24bitMode //9
1182 "operandsNotSame", operandsNotSame //8
1185 "operandsNotSame3", operandsNotSame3
1188 "operandsNotSame4", operandsNotSame4
1191 "operandsNotSame5", operandsNotSame5
1194 "operandsNotSame6", operandsNotSame6
1197 "operandsNotSame7", operandsNotSame7
1200 "operandsNotSame8", operandsNotSame8
1203 "xramMovcOption", xramMovcOption
1206 "portIsDS390", portIsDS390
1209 "labelIsReturnOnly", labelIsReturnOnly
1212 "labelIsUncondJump", labelIsUncondJump
1215 "okToRemoveSLOC", okToRemoveSLOC
1218 "deadMove", deadMove
1221 "operandsLiteral", operandsLiteral
1224 "useAcallAjmp", useAcallAjmp
1230 /*-----------------------------------------------------------------*/
1231 /* callFuncByName - calls a function as defined in the table */
1232 /*-----------------------------------------------------------------*/
1234 callFuncByName (char *fname,
1236 lineNode * currPl, /* first source line matched */
1237 lineNode * endPl, /* last source line matched */
1241 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1245 /* Isolate the function name part (we are passed the full condition
1246 * string including arguments)
1248 cmdTerm = cmdCopy = Safe_strdup(fname);
1252 funcArgs = funcName = cmdTerm;
1253 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1255 *funcArgs = '\0'; /* terminate the function name */
1259 /* Find the start of the arguments */
1260 if (c == ' ' || c == '\t')
1261 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1264 /* If the arguments started with an opening parenthesis, */
1265 /* use the closing parenthesis for the end of the */
1266 /* arguments and look for the start of another condition */
1267 /* that can optionally follow. If there was no opening */
1268 /* parethesis, then everything that follows are arguments */
1269 /* and there can be no additional conditions. */
1273 int num_parenthesis = 0;
1276 while ((c = *cmdTerm) && (c != ')' || num_parenthesis))
1284 *cmdTerm = '\0'; /* terminate the arguments */
1288 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1294 cmdTerm = NULL; /* closing parenthesis missing */
1303 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1305 if (strcmp (ftab[i].fname, funcName) == 0)
1307 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1315 "could not find named function \"%s\" in "
1316 "peephole function table\n",
1318 // If the function couldn't be found, let's assume it's
1319 // a bad rule and refuse it.
1324 while (rc && cmdTerm);
1331 /*-----------------------------------------------------------------*/
1332 /* printLine - prints a line chain into a given file */
1333 /*-----------------------------------------------------------------*/
1335 printLine (lineNode * head, struct dbuf_s * oBuf)
1337 iCode *last_ic = NULL;
1338 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1342 if (head->ic!=last_ic)
1345 if (debug_iCode_tracking)
1348 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1349 head->ic->block, head->ic->seq);
1351 dbuf_append_str (oBuf, "; iCode lost\n");
1355 /* don't indent comments & labels */
1357 (head->isComment || head->isLabel)) {
1358 dbuf_printf (oBuf, "%s\n", head->line);
1360 if (head->isInline && *head->line=='#') {
1361 // comment out preprocessor directives in inline asm
1362 dbuf_append_char (oBuf, ';');
1364 dbuf_printf (oBuf, "\t%s\n", head->line);
1370 /*-----------------------------------------------------------------*/
1371 /* newPeepRule - creates a new peeprule and attach it to the root */
1372 /*-----------------------------------------------------------------*/
1374 newPeepRule (lineNode * match,
1381 pr = Safe_alloc ( sizeof (peepRule));
1383 pr->replace = replace;
1384 pr->restart = restart;
1388 pr->cond = Safe_strdup (cond);
1393 pr->vars = newHashTable (100);
1395 /* if root is empty */
1397 rootRules = currRule = pr;
1399 currRule = currRule->next = pr;
1404 /*-----------------------------------------------------------------*/
1405 /* newLineNode - creates a new peep line */
1406 /*-----------------------------------------------------------------*/
1408 newLineNode (const char *line)
1412 pl = Safe_alloc ( sizeof (lineNode));
1413 pl->line = Safe_strdup (line);
1418 /*-----------------------------------------------------------------*/
1419 /* connectLine - connects two lines */
1420 /*-----------------------------------------------------------------*/
1422 connectLine (lineNode * pl1, lineNode * pl2)
1426 fprintf (stderr, "trying to connect null line\n");
1436 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1437 if (!*x) { fprintf(stderr,y); return ; } }
1439 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1440 if (!*x) { fprintf(stderr,z); return ; } }
1441 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1442 if (!*x) { fprintf(stderr,z); return ; } }
1444 /*-----------------------------------------------------------------*/
1445 /* getPeepLine - parses the peep lines */
1446 /*-----------------------------------------------------------------*/
1448 getPeepLine (lineNode ** head, char **bpp)
1450 char lines[MAX_PATTERN_LEN];
1454 lineNode *currL = NULL;
1461 fprintf (stderr, "unexpected end of match pattern\n");
1468 while (ISCHARSPACE (*bp) ||
1479 /* read till end of line */
1481 while ((*bp != '\n' && *bp != '}') && *bp)
1486 while (*lp && ISCHARSPACE(*lp))
1488 isComment = (*lp == ';');
1490 if (!isComment || (isComment && !options.noPeepComments))
1496 *head = currL = newLineNode (lines);
1498 currL = connectLine (currL, newLineNode (lines));
1499 currL->isComment = isComment;
1500 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1509 /*-----------------------------------------------------------------*/
1510 /* readRules - reads the rules from a string buffer */
1511 /*-----------------------------------------------------------------*/
1513 readRules (char *bp)
1516 char lines[MAX_PATTERN_LEN];
1520 lineNode *currL = NULL;
1526 /* look for the token "replace" that is the
1528 while (*bp && strncmp (bp, "replace", 7))
1535 /* then look for either "restart" or '{' */
1536 while (strncmp (bp, "restart", 7) &&
1543 fprintf (stderr, "expected 'restart' or '{'\n");
1551 { /* must be restart */
1553 bp += strlen ("restart");
1555 EXPECT_CHR (bp, '{', "expected '{'\n");
1559 /* skip thru all the blank space */
1560 SKIP_SPACE (bp, "unexpected end of rule\n");
1562 match = replace = currL = NULL;
1563 /* we are the start of a rule */
1564 getPeepLine (&match, &bp);
1566 /* now look for by */
1567 EXPECT_STR (bp, "by", "expected 'by'\n");
1569 /* then look for a '{' */
1570 EXPECT_CHR (bp, '{', "expected '{'\n");
1573 /* save char position (needed for generating error msg) */
1576 SKIP_SPACE (bp, "unexpected end of rule\n");
1577 getPeepLine (&replace, &bp);
1579 /* look for a 'if' */
1580 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1583 if (strncmp (bp, "if", 2) == 0)
1586 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1590 fprintf (stderr, "expected condition name\n");
1594 /* look for the condition */
1596 while (*bp && (*bp != '\n'))
1602 newPeepRule (match, replace, lines, restart);
1606 if (*bp && strncmp (bp, "replace", 7))
1608 /* not the start of a new peeprule, so "if" should be here */
1613 /* go to the start of the line following "{" of the "by" token */
1614 while (*rp && (*rp == '\n'))
1617 /* copy text of rule starting with line after "by {" */
1619 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1622 /* and now the rest of the line */
1623 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1627 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1630 newPeepRule (match, replace, NULL, restart);
1636 /*-----------------------------------------------------------------*/
1637 /* keyForVar - returns the numeric key for a var */
1638 /*-----------------------------------------------------------------*/
1644 while (ISCHARDIGIT (*d))
1653 /*-----------------------------------------------------------------*/
1654 /* bindVar - binds a value to a variable in the given hashtable */
1655 /*-----------------------------------------------------------------*/
1657 bindVar (int key, char **s, hTab ** vtab)
1659 char vval[MAX_PATTERN_LEN];
1663 /* first get the value of the variable */
1665 /* the value is ended by a ',' or space or newline or null or ) */
1668 !ISCHARSPACE (*vvx) &&
1674 /* if we find a '(' then we need to balance it */
1686 // include the trailing ')'
1695 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1697 hTabAddItem (vtab, key, vvx);
1700 /*-----------------------------------------------------------------*/
1701 /* matchLine - matches one line */
1702 /*-----------------------------------------------------------------*/
1704 matchLine (char *s, char *d, hTab ** vars)
1713 /* skip white space in both */
1714 while (ISCHARSPACE (*s))
1716 while (ISCHARSPACE (*d))
1719 /* if the destination is a var */
1720 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1722 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1723 /* if the variable is already bound
1724 then it MUST match with dest */
1732 /* variable not bound we need to bind it */
1733 bindVar (keyForVar (d + 1), &s, vars);
1735 /* in either case go past the variable */
1737 while (ISCHARDIGIT (*d))
1740 while (ISCHARSPACE (*s))
1742 while (ISCHARSPACE (*d))
1746 /* they should be an exact match other wise */
1755 /* get rid of the trailing spaces
1756 in both source & destination */
1758 while (ISCHARSPACE (*s))
1762 while (ISCHARSPACE (*d))
1765 /* after all this if only one of them
1766 has something left over then no match */
1773 /*-----------------------------------------------------------------*/
1774 /* matchRule - matches a all the rule lines */
1775 /*-----------------------------------------------------------------*/
1777 matchRule (lineNode * pl,
1782 lineNode *spl; /* source pl */
1783 lineNode *rpl; /* rule peep line */
1785 /* setToNull((void *) &pr->vars); */
1786 /* pr->vars = newHashTable(100); */
1788 /* for all the lines defined in the rule */
1794 /* if the source line starts with a ';' then
1795 comment line don't process or the source line
1796 contains == . debugger information skip it */
1798 (*spl->line == ';' || spl->isDebug))
1804 if (!matchLine (spl->line, rpl->line, &pr->vars))
1812 /* if rules ended */
1815 /* if this rule has additional conditions */
1818 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1837 reassociate_ic_down (lineNode *shead, lineNode *stail,
1838 lineNode *rhead, lineNode *rtail)
1840 lineNode *csl; /* current source line */
1841 lineNode *crl; /* current replacement line */
1847 /* skip over any comments */
1848 while (csl!=stail->next && csl->isComment)
1850 while (crl!=rtail->next && crl->isComment)
1853 /* quit if we reach the end */
1854 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1857 if (matchLine(csl->line,crl->line,NULL))
1869 reassociate_ic_up (lineNode *shead, lineNode *stail,
1870 lineNode *rhead, lineNode *rtail)
1872 lineNode *csl; /* current source line */
1873 lineNode *crl; /* current replacement line */
1879 /* skip over any comments */
1880 while (csl!=shead->prev && csl->isComment)
1882 while (crl!=rhead->prev && crl->isComment)
1885 /* quit if we reach the end */
1886 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1889 if (matchLine(csl->line,crl->line,NULL))
1900 /*------------------------------------------------------------------*/
1901 /* reassociate_ic - reassociate replacement lines with origin iCode */
1902 /*------------------------------------------------------------------*/
1904 reassociate_ic (lineNode *shead, lineNode *stail,
1905 lineNode *rhead, lineNode *rtail)
1907 lineNode *csl; /* current source line */
1908 lineNode *crl; /* current replacement line */
1912 /* Check to see if all the source lines (excluding comments) came
1913 ** for the same iCode
1916 for (csl=shead;csl!=stail->next;csl=csl->next)
1917 if (csl->ic && !csl->isComment)
1922 single_iCode = (ic!=NULL);
1923 for (csl=shead;csl!=stail->next;csl=csl->next)
1924 if ((csl->ic != ic) && !csl->isComment)
1926 /* More than one iCode was found. However, if it's just the
1927 ** last line with the different iCode and it was not changed
1928 ** in the replacement, everything else must be the first iCode.
1930 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1932 rtail->ic = stail->ic;
1933 for (crl=rhead;crl!=rtail;crl=crl->next)
1938 single_iCode = FALSE;
1942 /* If all of the source lines came from the same iCode, then so have
1943 ** all of the replacement lines too.
1947 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1952 /* The source lines span iCodes, so we may end up with replacement
1953 ** lines that we don't know which iCode(s) to associate with. Do the
1954 ** best we can by using the following strategies:
1955 ** 1) Start at the top and scan down. As long as the source line
1956 ** matches the replacement line, they have the same iCode.
1957 ** 2) Start at the bottom and scan up. As long as the source line
1958 ** matches the replacement line, they have the same iCode.
1959 ** 3) For any label in the source, look for a matching label in
1960 ** the replacment. If found, they have the same iCode. From
1961 ** these matching labels, scan down for additional matching
1962 ** lines; if found, they also have the same iCode.
1965 /* Strategy #1: Start at the top and scan down for matches
1967 reassociate_ic_down(shead,stail,rhead,rtail);
1969 /* Strategy #2: Start at the bottom and scan up for matches
1971 reassociate_ic_up(shead,stail,rhead,rtail);
1973 /* Strategy #3: Try to match labels
1978 /* skip over any comments */
1979 while (csl!=stail->next && csl->isComment)
1981 if (csl==stail->next)
1986 /* found a source line label; look for it in the replacment lines */
1990 while (crl!=rtail->next && crl->isComment)
1992 if (crl==rtail->next)
1994 if (matchLine(csl->line, crl->line, NULL))
1996 reassociate_ic_down(csl,stail,crl,rtail);
2006 /* Try to assign a meaningful iCode to any comment that is missing
2007 one. Since they are comments, it's ok to make mistakes; we are just
2008 trying to improve continuity to simplify other tests.
2011 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
2013 if (!crl->ic && ic && crl->isComment)
2020 /*-----------------------------------------------------------------*/
2021 /* replaceRule - does replacement of a matching pattern */
2022 /*-----------------------------------------------------------------*/
2024 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
2026 lineNode *cl = NULL;
2027 lineNode *pl = NULL, *lhead = NULL;
2028 /* a long function name and long variable name can evaluate to
2029 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
2030 char lb[MAX_PATTERN_LEN*4];
2032 lineNode *comment = NULL;
2034 /* collect all the comment lines in the source */
2035 for (cl = *shead; cl != stail; cl = cl->next)
2037 if (cl->line && (*cl->line == ';' || cl->isDebug))
2039 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2040 (comment = newLineNode (cl->line)));
2041 pl->isDebug = cl->isDebug;
2042 pl->isComment = cl->isComment || (*cl->line == ';');
2047 /* for all the lines in the replacement pattern do */
2048 for (pl = pr->replace; pl; pl = pl->next)
2058 /* if the line contains a variable */
2059 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2061 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2064 fprintf (stderr, "used unbound variable in replacement\n");
2072 while (ISCHARDIGIT (*l)) {
2082 cl = connectLine (cl, newLineNode (lb));
2084 lhead = cl = newLineNode (lb);
2085 cl->isComment = pl->isComment;
2086 cl->isLabel = pl->isLabel;
2089 /* add the comments if any to the head of list */
2092 lineNode *lc = comment;
2103 /* determine which iCodes the replacment lines relate to */
2104 reassociate_ic(*shead,stail,lhead,cl);
2106 /* now we need to connect / replace the original chain */
2107 /* if there is a prev then change it */
2110 (*shead)->prev->next = lhead;
2111 lhead->prev = (*shead)->prev;
2114 /* now for the tail */
2115 if (stail && stail->next)
2117 stail->next->prev = cl;
2119 cl->next = stail->next;
2124 /* the replacement is empty - delete the source lines */
2126 (*shead)->prev->next = stail->next;
2128 stail->next->prev = (*shead)->prev;
2129 *shead = stail->next;
2133 /* Returns TRUE if this line is a label definition.
2135 * If so, start will point to the start of the label name,
2136 * and len will be it's length.
2139 isLabelDefinition (const char *line, const char **start, int *len,
2142 const char *cp = line;
2144 /* This line is a label if if consists of:
2145 * [optional whitespace] followed by identifier chars
2146 * (alnum | $ | _ ) followed by a colon.
2149 while (*cp && ISCHARSPACE (*cp))
2161 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2162 (isPeepRule && (*cp == '%')))
2167 if ((cp == *start) || (*cp != ':'))
2172 *len = (cp - (*start));
2176 /* Quick & dirty string hash function. */
2178 hashSymbolName (const char *name)
2184 hash = (hash << 6) ^ *name;
2193 return hash % HTAB_SIZE;
2196 /* Build a hash of all labels in the passed set of lines
2197 * and how many times they are referenced.
2200 buildLabelRefCountHash (lineNode * head)
2207 assert (labelHash == NULL);
2208 labelHash = newHashTable (HTAB_SIZE);
2210 /* First pass: locate all the labels. */
2211 for (line = head; line; line = line->next)
2213 if (line->isLabel ||
2216 /* run isLabelDefinition to:
2217 - look for labels in inline assembler
2218 - calculate labelLen
2220 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2221 labelLen <= SDCC_NAME_MAX)
2223 labelHashEntry *entry;
2225 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2227 memcpy (entry->name, label, labelLen);
2228 entry->name[labelLen] = 0;
2229 entry->refCount = -1;
2231 /* Assume function entry points are referenced somewhere, */
2232 /* even if we can't find a reference (might be from outside */
2234 if (line->ic && (line->ic->op == FUNCTION))
2237 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2243 /* Second pass: for each line, note all the referenced labels. */
2244 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2248 for (i = 0; i < HTAB_SIZE; i++)
2250 labelHashEntry *thisEntry;
2252 thisEntry = hTabFirstItemWK (labelHash, i);
2256 if (strstr (line->line, thisEntry->name))
2258 thisEntry->refCount++;
2260 thisEntry = hTabNextItemWK (labelHash);
2267 /* Spew the contents of the table. Debugging fun only. */
2268 for (i = 0; i < HTAB_SIZE; i++)
2270 labelHashEntry *thisEntry;
2272 thisEntry = hTabFirstItemWK (labelHash, i);
2276 fprintf (stderr, "label: %s ref %d\n",
2277 thisEntry->name, thisEntry->refCount);
2278 thisEntry = hTabNextItemWK (labelHash);
2284 /* How does this work?
2290 replace and restart.
2295 Where is stuff allocated?
2299 /*-----------------------------------------------------------------*/
2300 /* peepHole - matches & substitutes rules */
2301 /*-----------------------------------------------------------------*/
2303 peepHole (lineNode ** pls)
2307 lineNode *mtail = NULL;
2308 bool restart, replaced;
2310 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2311 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2312 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2316 assert(labelHash == NULL);
2323 for (pr = rootRules; pr; pr = pr->next)
2325 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2329 /* if inline assembler then no peep hole */
2333 /* don't waste time starting a match on debug symbol
2335 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2340 /* Tidy up any data stored in the hTab */
2343 if (matchRule (spl, &mtail, pr, *pls))
2345 /* restart at the replaced line */
2351 replaceRule (pls, mtail, pr);
2355 replaceRule (&spl, mtail, pr);
2357 /* if restart rule type then
2358 start at the top again */
2367 hTabDeleteAll (pr->vars);
2368 Safe_free (pr->vars);
2372 freeTrace (&_G.values);
2375 } while (restart == TRUE);
2379 hTabDeleteAll (labelHash);
2380 freeTrace (&_G.labels);
2386 /*-----------------------------------------------------------------*/
2387 /* readFileIntoBuffer - reads a file into a string buffer */
2388 /*-----------------------------------------------------------------*/
2390 readFileIntoBuffer (char *fname)
2396 char lb[MAX_PATTERN_LEN];
2398 if (!(f = fopen (fname, "r")))
2400 fprintf (stderr, "cannot open peep rule file\n");
2404 while ((ch = fgetc (f)) != EOF)
2408 /* if we maxed out our local buffer */
2409 if (nch >= (MAX_PATTERN_LEN - 2))
2412 /* copy it into allocated buffer */
2415 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2416 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2420 rs = Safe_strdup (lb);
2426 /* if some charaters left over */
2430 /* copy it into allocated buffer */
2433 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2434 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2438 rs = Safe_strdup (lb);
2444 /*-----------------------------------------------------------------*/
2445 /* initPeepHole - initialises the peep hole optimizer stuff */
2446 /*-----------------------------------------------------------------*/
2452 /* read in the default rules */
2453 if (!options.nopeep)
2455 readRules (port->peep.default_rules);
2458 /* if we have any additional file read it too */
2459 if (options.peep_file)
2461 readRules (s = readFileIntoBuffer (options.peep_file));
2462 setToNull ((void *) &s);
2463 /* override nopeep setting, default rules have not been read */
2468 #if !OPT_DISABLE_PIC
2469 /* Convert the peep rules into pcode.
2470 NOTE: this is only support in the PIC port (at the moment)
2473 peepRules2pCode(rootRules);
2476 #if !OPT_DISABLE_PIC16
2477 /* Convert the peep rules into pcode.
2478 NOTE: this is only support in the PIC port (at the moment)
2479 and the PIC16 port (VR 030601)
2481 if (TARGET_IS_PIC16)
2482 pic16_peepRules2pCode(rootRules);