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 /* getPatternVar - finds a pattern variable */
65 /*-----------------------------------------------------------------*/
68 getPatternVar (hTab *vars, char **cmdLine)
73 if (!cmdLine || !*cmdLine || !**cmdLine)
74 return NULL; /* no parameters given */
76 while (**cmdLine && ISCHARSPACE(**cmdLine))
77 (*cmdLine)++; /* skip whitespace */
82 if (!ISCHARDIGIT (**cmdLine))
84 varNumber = strtol (*cmdLine, &digitend, 10);
86 return hTabItemWithKey (vars, varNumber);
90 "*** internal error: peephole restriction malformed: %s\n", *cmdLine);
94 /*-----------------------------------------------------------------*/
95 /* pcDistance - finds a label backward or forward */
96 /*-----------------------------------------------------------------*/
99 pcDistance (lineNode * cpos, char *lbl, bool back)
102 char buff[MAX_PATTERN_LEN];
105 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
113 if (port->peep.getSize)
115 dist += port->peep.getSize(pl);
123 if (strncmp (pl->line, buff, strlen (buff)) == 0)
135 /*-----------------------------------------------------------------*/
136 /* portIsDS390 - return true if port is DS390 */
137 /*-----------------------------------------------------------------*/
138 FBYNAME (portIsDS390)
140 return ((strcmp(port->target,"ds390") == 0) ||
141 (strcmp(port->target,"ds400") == 0));
144 /*-----------------------------------------------------------------*/
145 /* flat24bitMode - will check to see if we are in flat24 mode */
146 /*-----------------------------------------------------------------*/
147 FBYNAME (flat24bitMode)
149 return (options.model == MODEL_FLAT24);
152 /*-----------------------------------------------------------------*/
153 /* xramMovcOption - check if using movc to read xram */
154 /*-----------------------------------------------------------------*/
155 FBYNAME (xramMovcOption)
157 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
160 /*-----------------------------------------------------------------*/
161 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
162 /*-----------------------------------------------------------------*/
163 FBYNAME (useAcallAjmp)
165 return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
168 /*-----------------------------------------------------------------*/
169 /* labelInRange - will check to see if label is within range */
170 /*-----------------------------------------------------------------*/
171 FBYNAME (labelInRange)
174 char *lbl = getPatternVar (vars, &cmdLine);
178 /* If no parameters given, assume that %5 pattern variable
179 has the label name for backward compatibility */
180 lbl = hTabItemWithKey (vars, 5);
188 /* Don't optimize jumps in a jump table; a more generic test */
189 if (currPl->ic && currPl->ic->op == JUMPTABLE)
192 /* if the previous two instructions are "ljmp"s then don't
193 do it since it can be part of a jump table */
194 if (currPl->prev && currPl->prev->prev &&
195 strstr (currPl->prev->line, "ljmp") &&
196 strstr (currPl->prev->prev->line, "ljmp"))
199 /* calculate the label distance : the jump for reladdr can be
200 +/- 127 bytes, here I am assuming that an average 8051
201 instruction is 2 bytes long, so if the label is more than
202 63 intructions away, the label is considered out of range
203 for a relative jump. we could get more precise this will
204 suffice for now since it catches > 90% cases */
205 dist = (pcDistance (currPl, lbl, TRUE) +
206 pcDistance (currPl, lbl, FALSE));
208 /* changed to 127, now that pcDistance return actual number of bytes */
209 if (!dist || dist > 127)
212 lbl = getPatternVar (vars, &cmdLine);
219 /*-----------------------------------------------------------------*/
220 /* labelJTInRange - will check to see if label %5 and up are */
222 /* Specifically meant to optimize long (3-byte) jumps to short */
223 /* (2-byte) jumps in jumptables */
224 /*-----------------------------------------------------------------*/
225 FBYNAME (labelJTInRange)
230 if (!getenv("SDCC_SJMP_JUMPTABLE"))
233 /* Only optimize within a jump table */
234 if (currPl->ic && currPl->ic->op != JUMPTABLE)
237 count = elementsInSet( IC_JTLABELS (currPl->ic) );
239 /* check all labels (this is needed if the case statements are unsorted) */
240 for (i=0; i<count; i++)
242 /* assumes that the %5 pattern variable has the first ljmp label */
243 lbl = hTabItemWithKey (vars, 5+i);
247 dist = pcDistance (currPl, lbl, FALSE);
249 /* three terms used to calculate allowable distance */
250 // 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);
252 dist > 127+ /* range of sjmp */
253 (7+3*i)+ /* offset between this jump and currPl,
254 should use pcDistance instead? */
255 (count-i-1) /* if peephole applies distance is shortened */
262 /*-----------------------------------------------------------------*/
263 /* labelIsReturnOnly - Check if label %5 is followed by RET */
264 /*-----------------------------------------------------------------*/
265 FBYNAME (labelIsReturnOnly)
267 /* assumes that %5 pattern variable has the label name */
268 const char *label, *p;
273 /* Don't optimize jumps in a jump table; a more generic test */
274 if (currPl->ic && currPl->ic->op == JUMPTABLE)
277 label = hTabItemWithKey (vars, 5);
282 for(pl = currPl; pl; pl = pl->next)
284 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
286 if (strncmp(pl->line, label, len) == 0)
287 break; /* Found Label */
288 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
289 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
290 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
291 *(pl->line+5) != '$')
293 return FALSE; /* non-local label encountered */
298 return FALSE; /* did not find the label */
300 while (pl && (pl->isDebug || pl->isComment))
302 if (!pl || !pl->line || pl->isDebug)
303 return FALSE; /* next line not valid */
305 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
311 if (strcmp(p, retInst) == 0)
316 /*-----------------------------------------------------------------*/
317 /* labelIsUncondJump - Check if label %5 is followed by an */
318 /* unconditional jump and put the destination of that jump in %6 */
319 /*-----------------------------------------------------------------*/
320 FBYNAME (labelIsUncondJump)
322 /* assumes that %5 pattern variable has the label name */
327 char * jpInst = NULL;
329 /* Don't optimize jumps in a jump table; a more generic test */
330 if (currPl->ic && currPl->ic->op == JUMPTABLE)
333 label = hTabItemWithKey (vars, 5);
338 for (pl = currPl; pl; pl = pl->next)
340 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
342 if (strncmp(pl->line, label, len) == 0)
343 break; /* Found Label */
344 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
345 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
346 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
347 *(pl->line+5) != '$')
349 return FALSE; /* non-local label encountered */
354 return FALSE; /* did not find the label */
356 while (pl && (pl->isDebug || pl->isComment))
358 if (!pl || !pl->line)
359 return FALSE; /* next line not valid */
361 while (*p && ISCHARSPACE(*p))
364 if (TARGET_MCS51_LIKE)
370 len = strlen(jpInst);
371 if (strncmp(p, jpInst, len) != 0)
372 return FALSE; /* next line is no jump */
374 while (*p && ISCHARSPACE(*p))
378 while (*q && *q!=';')
380 while (q>p && ISCHARSPACE(*q))
384 return FALSE; /* no destination? */
387 while (q>p && *q!=',')
390 return FALSE; /* conditional jump */
392 if (strcmp(p, q) == 0)
393 return FALSE; /* labels are equal */
394 /* now put the destination in %6 */
395 bindVar (6, &p, &vars);
399 /*-----------------------------------------------------------------*/
400 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
401 /* usage of it in the code depends on a value from this section */
402 /*-----------------------------------------------------------------*/
403 FBYNAME (okToRemoveSLOC)
406 const char *sloc, *p;
407 int dummy1, dummy2, dummy3;
409 /* assumes that %1 as the SLOC name */
410 sloc = hTabItemWithKey (vars, 1);
411 if (sloc == NULL) return FALSE;
412 p = strstr(sloc, "sloc");
413 if (p == NULL) return FALSE;
415 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
416 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
417 /* the sloc name begins with that. Probably not really necessary */
419 /* Look for any occurance of this SLOC before the peephole match */
420 for (pl = currPl->prev; pl; pl = pl->prev) {
421 if (pl->line && !pl->isDebug && !pl->isComment
422 && *pl->line != ';' && strstr(pl->line, sloc))
425 /* Look for any occurance of this SLOC after the peephole match */
426 for (pl = endPl->next; pl; pl = pl->next) {
427 if (pl->line && !pl->isDebug && !pl->isComment
428 && *pl->line != ';' && strstr(pl->line, sloc))
431 return TRUE; /* safe for a peephole to remove it :) */
434 /*-----------------------------------------------------------------*/
435 /* deadMove - Check, if a pop/push pair can be removed */
436 /*-----------------------------------------------------------------*/
439 const char *reg = hTabItemWithKey (vars, 1);
441 if (port->peep.deadMove)
442 return port->peep.deadMove (reg, currPl, head);
444 fprintf (stderr, "Function deadMove not initialized in port structure\n");
448 /*-----------------------------------------------------------------*/
449 /* notUsed - Check, if value in register is not read again */
450 /*-----------------------------------------------------------------*/
455 if(cmdLine[0] != '\'')
456 what = hTabItemWithKey (vars, 1);
459 cmdLine[strlen(cmdLine) - 1] = 0;
463 if (port->peep.notUsed)
464 return port->peep.notUsed (what, endPl, head);
466 fprintf (stderr, "Function notUsed not initialized in port structure\n");
470 /*-----------------------------------------------------------------*/
471 /* operandsNotSame - check if %1 & %2 are the same */
472 /*-----------------------------------------------------------------*/
473 FBYNAME (operandsNotSame)
475 char *op1 = hTabItemWithKey (vars, 1);
476 char *op2 = hTabItemWithKey (vars, 2);
478 if (strcmp (op1, op2) == 0)
484 /*-----------------------------------------------------------------*/
485 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
486 /*-----------------------------------------------------------------*/
487 FBYNAME (operandsNotSame3)
489 char *op1 = hTabItemWithKey (vars, 1);
490 char *op2 = hTabItemWithKey (vars, 2);
491 char *op3 = hTabItemWithKey (vars, 3);
493 if ( (strcmp (op1, op2) == 0) ||
494 (strcmp (op1, op3) == 0) ||
495 (strcmp (op2, op3) == 0) )
501 /*-----------------------------------------------------------------*/
502 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
503 /*-----------------------------------------------------------------*/
504 FBYNAME (operandsNotSame4)
506 char *op1 = hTabItemWithKey (vars, 1);
507 char *op2 = hTabItemWithKey (vars, 2);
508 char *op3 = hTabItemWithKey (vars, 3);
509 char *op4 = hTabItemWithKey (vars, 4);
511 if ( (strcmp (op1, op2) == 0) ||
512 (strcmp (op1, op3) == 0) ||
513 (strcmp (op1, op4) == 0) ||
514 (strcmp (op2, op3) == 0) ||
515 (strcmp (op2, op4) == 0) ||
516 (strcmp (op3, op4) == 0) )
522 /*-----------------------------------------------------------------*/
523 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
524 /*-----------------------------------------------------------------*/
525 FBYNAME (operandsNotSame5)
527 char *op1 = hTabItemWithKey (vars, 1);
528 char *op2 = hTabItemWithKey (vars, 2);
529 char *op3 = hTabItemWithKey (vars, 3);
530 char *op4 = hTabItemWithKey (vars, 4);
531 char *op5 = hTabItemWithKey (vars, 5);
533 if ( (strcmp (op1, op2) == 0) ||
534 (strcmp (op1, op3) == 0) ||
535 (strcmp (op1, op4) == 0) ||
536 (strcmp (op1, op5) == 0) ||
537 (strcmp (op2, op3) == 0) ||
538 (strcmp (op2, op4) == 0) ||
539 (strcmp (op2, op5) == 0) ||
540 (strcmp (op3, op4) == 0) ||
541 (strcmp (op3, op5) == 0) ||
542 (strcmp (op4, op5) == 0) )
548 /*-----------------------------------------------------------------*/
549 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
550 /*-----------------------------------------------------------------*/
551 FBYNAME (operandsNotSame6)
553 char *op1 = hTabItemWithKey (vars, 1);
554 char *op2 = hTabItemWithKey (vars, 2);
555 char *op3 = hTabItemWithKey (vars, 3);
556 char *op4 = hTabItemWithKey (vars, 4);
557 char *op5 = hTabItemWithKey (vars, 5);
558 char *op6 = hTabItemWithKey (vars, 6);
560 if ( (strcmp (op1, op2) == 0) ||
561 (strcmp (op1, op3) == 0) ||
562 (strcmp (op1, op4) == 0) ||
563 (strcmp (op1, op5) == 0) ||
564 (strcmp (op1, op6) == 0) ||
565 (strcmp (op2, op3) == 0) ||
566 (strcmp (op2, op4) == 0) ||
567 (strcmp (op2, op5) == 0) ||
568 (strcmp (op2, op6) == 0) ||
569 (strcmp (op3, op4) == 0) ||
570 (strcmp (op3, op5) == 0) ||
571 (strcmp (op3, op6) == 0) ||
572 (strcmp (op4, op5) == 0) ||
573 (strcmp (op4, op6) == 0) ||
574 (strcmp (op5, op6) == 0) )
580 /*-----------------------------------------------------------------*/
581 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
582 /*-----------------------------------------------------------------*/
583 FBYNAME (operandsNotSame7)
585 char *op1 = hTabItemWithKey (vars, 1);
586 char *op2 = hTabItemWithKey (vars, 2);
587 char *op3 = hTabItemWithKey (vars, 3);
588 char *op4 = hTabItemWithKey (vars, 4);
589 char *op5 = hTabItemWithKey (vars, 5);
590 char *op6 = hTabItemWithKey (vars, 6);
591 char *op7 = hTabItemWithKey (vars, 7);
593 if ( (strcmp (op1, op2) == 0) ||
594 (strcmp (op1, op3) == 0) ||
595 (strcmp (op1, op4) == 0) ||
596 (strcmp (op1, op5) == 0) ||
597 (strcmp (op1, op6) == 0) ||
598 (strcmp (op1, op7) == 0) ||
599 (strcmp (op2, op3) == 0) ||
600 (strcmp (op2, op4) == 0) ||
601 (strcmp (op2, op5) == 0) ||
602 (strcmp (op2, op6) == 0) ||
603 (strcmp (op2, op7) == 0) ||
604 (strcmp (op3, op4) == 0) ||
605 (strcmp (op3, op5) == 0) ||
606 (strcmp (op3, op6) == 0) ||
607 (strcmp (op3, op7) == 0) ||
608 (strcmp (op4, op5) == 0) ||
609 (strcmp (op4, op6) == 0) ||
610 (strcmp (op4, op7) == 0) ||
611 (strcmp (op5, op6) == 0) ||
612 (strcmp (op5, op7) == 0) ||
613 (strcmp (op6, op7) == 0) )
619 /*-----------------------------------------------------------------*/
620 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
621 /*-----------------------------------------------------------------*/
622 FBYNAME (operandsNotSame8)
624 char *op1 = hTabItemWithKey (vars, 1);
625 char *op2 = hTabItemWithKey (vars, 2);
626 char *op3 = hTabItemWithKey (vars, 3);
627 char *op4 = hTabItemWithKey (vars, 4);
628 char *op5 = hTabItemWithKey (vars, 5);
629 char *op6 = hTabItemWithKey (vars, 6);
630 char *op7 = hTabItemWithKey (vars, 7);
631 char *op8 = hTabItemWithKey (vars, 8);
633 if ( (strcmp (op1, op2) == 0) ||
634 (strcmp (op1, op3) == 0) ||
635 (strcmp (op1, op4) == 0) ||
636 (strcmp (op1, op5) == 0) ||
637 (strcmp (op1, op6) == 0) ||
638 (strcmp (op1, op7) == 0) ||
639 (strcmp (op1, op8) == 0) ||
640 (strcmp (op2, op3) == 0) ||
641 (strcmp (op2, op4) == 0) ||
642 (strcmp (op2, op5) == 0) ||
643 (strcmp (op2, op6) == 0) ||
644 (strcmp (op2, op7) == 0) ||
645 (strcmp (op2, op8) == 0) ||
646 (strcmp (op3, op4) == 0) ||
647 (strcmp (op3, op5) == 0) ||
648 (strcmp (op3, op6) == 0) ||
649 (strcmp (op3, op7) == 0) ||
650 (strcmp (op3, op8) == 0) ||
651 (strcmp (op4, op5) == 0) ||
652 (strcmp (op4, op6) == 0) ||
653 (strcmp (op4, op7) == 0) ||
654 (strcmp (op4, op8) == 0) ||
655 (strcmp (op5, op6) == 0) ||
656 (strcmp (op5, op7) == 0) ||
657 (strcmp (op5, op8) == 0) ||
658 (strcmp (op6, op7) == 0) ||
659 (strcmp (op6, op8) == 0) ||
660 (strcmp (op7, op8) == 0) )
666 /*-----------------------------------------------------------------*/
667 /* labelHashEntry- searches for a label in the list labelHash */
668 /* Builds labelHash, if it does not yet exist. */
669 /* Returns the labelHashEntry or NULL */
670 /*-----------------------------------------------------------------*/
672 getLabelRef (const char *label, lineNode *head)
674 labelHashEntry *entry;
676 /* If we don't have the label hash table yet, build it. */
679 buildLabelRefCountHash (head);
682 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
686 if (!strcmp (label, entry->name))
690 entry = hTabNextItemWK (labelHash);
697 * takes two parameters: a variable (bound to a label name)
698 * and an expected reference count.
700 * Returns TRUE if that label is defined and referenced exactly
701 * the given number of times.
703 FBYNAME (labelRefCount)
705 int varNumber, expectedRefCount;
708 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
710 char *label = hTabItemWithKey (vars, varNumber);
714 labelHashEntry *entry = getLabelRef (label, head);
720 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
721 label, entry->refCount, expectedRefCount);
724 rc = (expectedRefCount == entry->refCount);
728 fprintf (stderr, "*** internal error: no label has entry for"
729 " %s in labelRefCount peephole.\n",
735 fprintf (stderr, "*** internal error: var %d not bound"
736 " in peephole labelRefCount rule.\n",
744 "*** internal error: labelRefCount peephole restriction"
745 " malformed: %s\n", cmdLine);
750 /* labelRefCountChange:
751 * takes two parameters: a variable (bound to a label name)
752 * and a signed int for changing the reference count.
754 * Please note, this function is not a conditional. It unconditionally
755 * changes the label. It should be passed as the 'last' function
756 * so it only is applied if all other conditions have been met.
758 * should always return TRUE
760 FBYNAME (labelRefCountChange)
762 int varNumber, RefCountDelta;
765 /* If we don't have the label hash table yet, build it. */
768 buildLabelRefCountHash (head);
771 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
773 char *label = hTabItemWithKey (vars, varNumber);
777 labelHashEntry *entry;
779 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
783 if (!strcmp (label, entry->name))
787 entry = hTabNextItemWK (labelHash);
791 if (0 <= entry->refCount + RefCountDelta)
793 entry->refCount += RefCountDelta;
798 fprintf (stderr, "*** internal error: label %s may not get"
799 " negative refCount in %s peephole.\n",
800 label, __FUNCTION__);
805 fprintf (stderr, "*** internal error: no label has entry for"
806 " %s in %s peephole.\n",
807 label, __FUNCTION__);
812 fprintf (stderr, "*** internal error: var %d not bound"
813 " in peephole %s rule.\n",
814 varNumber, __FUNCTION__);
820 "*** internal error: labelRefCount peephole restriction"
821 " malformed: %s\n", cmdLine);
826 /* Within the context of the lines currPl through endPl, determine
827 ** if the variable var contains a symbol that is volatile. Returns
828 ** TRUE only if it is certain that this was not volatile (the symbol
829 ** was found and not volatile, or var was a constant or CPU register).
830 ** Returns FALSE if the symbol was found and volatile, the symbol was
831 ** not found, or var was a indirect/pointer addressing mode.
834 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
836 char symname[SDCC_NAME_MAX + 1];
843 /* Can't tell if indirect accesses are volatile or not, so
844 ** assume they are, just to be safe.
846 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
851 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
853 if (strstr(var,"(bc)"))
855 if (strstr(var,"(de)"))
857 if (strstr(var,"(hl)"))
859 if (strstr(var,"(ix"))
861 if (strstr(var,"(iy"))
865 /* Extract a symbol name from the variable */
866 while (*vp && (*vp!='_'))
868 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
874 /* Nothing resembling a symbol name was found, so it can't
881 for (cl = currPl; cl!=endPl->next; cl = cl->next)
883 if (cl->ic && (cl->ic!=last_ic))
889 op = IC_COND (cl->ic);
891 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
892 (OP_SYMBOL (op)->isspilt &&
894 !strcmp(SPIL_LOC (op)->rname, symname)) ))
896 return !op->isvolatile;
899 op = IC_JTCOND (cl->ic);
901 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
902 (OP_SYMBOL (op)->isspilt &&
904 !strcmp(SPIL_LOC (op)->rname, symname)) ))
906 return !op->isvolatile;
909 op = IC_LEFT (cl->ic);
911 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
912 (OP_SYMBOL (op)->isspilt &&
914 !strcmp(SPIL_LOC (op)->rname, symname)) ))
916 return !op->isvolatile;
918 op = IC_RIGHT (cl->ic);
920 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
921 (OP_SYMBOL (op)->isspilt &&
923 !strcmp(SPIL_LOC (op)->rname, symname)) ))
925 return !op->isvolatile;
927 op = IC_RESULT (cl->ic);
929 ( !strcmp(OP_SYMBOL (op)->rname, symname) ||
930 (OP_SYMBOL (op)->isspilt &&
932 !strcmp(SPIL_LOC (op)->rname, symname)) ))
934 return !op->isvolatile;
940 /* Couldn't find the symbol for some reason. Assume volatile. */
946 * This rule restriction has two different behaviours depending on
947 * the number of parameters given.
949 * if notVolatile (no parameters given)
950 * The rule is applied only if none of the iCodes originating
951 * the matched pattern reference a volatile operand.
953 * if notVolatile %1 ... (one or more parameters given)
954 * The rule is applied if the parameters are not expressions
955 * containing volatile symbols and are not pointer accesses.
958 FBYNAME (notVolatile)
969 /* If no parameters given, just scan the iCodes for volatile operands */
970 for (cl = currPl; cl!=endPl->next; cl = cl->next)
977 op = IC_COND (cl->ic);
978 if (IS_SYMOP (op) && op->isvolatile)
981 op = IC_JTCOND (cl->ic);
982 if (IS_SYMOP (op) && op->isvolatile)
985 op = IC_LEFT (cl->ic);
986 if (IS_SYMOP (op) && op->isvolatile)
988 op = IC_RIGHT (cl->ic);
989 if (IS_SYMOP (op) && op->isvolatile)
991 op = IC_RESULT (cl->ic);
992 if (IS_SYMOP (op) && op->isvolatile)
1000 /* There were parameters; check the volatility of each */
1001 while (*cmdLine && ISCHARSPACE(*cmdLine))
1008 if (!ISCHARDIGIT(*cmdLine))
1010 varNumber = strtol(cmdLine, &digitend, 10);
1012 while (*cmdLine && ISCHARSPACE(*cmdLine))
1015 var = hTabItemWithKey (vars, varNumber);
1019 notvol = notVolatileVariable (var, currPl, endPl);
1025 fprintf (stderr, "*** internal error: var %d not bound"
1026 " in peephole notVolatile rule.\n",
1036 "*** internal error: notVolatile peephole restriction"
1037 " malformed: %s\n", cmdLine);
1041 /*------------------------------------------------------------------*/
1042 /* setFromConditionArgs - parse a peephole condition's arguments */
1043 /* to produce a set of strings, one per argument. Variables %x will */
1044 /* be replaced with their values. String literals (in single quotes)*/
1045 /* are accepted and return in unquoted form. */
1046 /*------------------------------------------------------------------*/
1048 setFromConditionArgs (char *cmdLine, hTab * vars)
1053 set *operands = NULL;
1058 while (*cmdLine && ISCHARSPACE(*cmdLine))
1063 if (*cmdLine == '%')
1066 if (!ISCHARDIGIT(*cmdLine))
1068 varNumber = strtol(cmdLine, &digitend, 10);
1071 var = hTabItemWithKey (vars, varNumber);
1075 addSetHead (&operands, var);
1080 else if (*cmdLine == '\'' )
1082 char quote = *cmdLine;
1085 while (*cmdLine && *cmdLine != quote)
1087 if (*cmdLine == quote)
1091 addSetHead (&operands, var);
1096 while (*cmdLine && ISCHARSPACE(*cmdLine))
1103 deleteSet (&operands);
1108 operandBaseName (const char *op)
1110 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1112 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1114 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1116 // bug 1739475, temp fix
1118 return operandBaseName(op+1);
1124 /*-------------------------------------------------------------------*/
1125 /* operandsNotRelated - returns true if the condition's operands are */
1126 /* not related (taking into account register name aliases). N-way */
1127 /* comparison performed between all operands. */
1128 /*-------------------------------------------------------------------*/
1129 FBYNAME (operandsNotRelated)
1132 const char *op1, *op2;
1134 operands = setFromConditionArgs (cmdLine, vars);
1139 "*** internal error: operandsNotRelated peephole restriction"
1140 " malformed: %s\n", cmdLine);
1144 while ((op1 = setFirstItem (operands)))
1146 deleteSetItem (&operands, (void*)op1);
1147 op1 = operandBaseName (op1);
1149 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1151 op2 = operandBaseName (op2);
1152 if (strcmp (op1, op2) == 0)
1154 deleteSet (&operands);
1160 deleteSet (&operands);
1164 /*-------------------------------------------------------------------*/
1165 /* operandsLiteral - returns true of the condition's operands are */
1167 /*-------------------------------------------------------------------*/
1168 FBYNAME (operandsLiteral)
1173 operands = setFromConditionArgs (cmdLine, vars);
1178 "*** internal error: operandsLiteral peephole restriction"
1179 " malformed: %s\n", cmdLine);
1183 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1187 deleteSet (&operands);
1192 deleteSet (&operands);
1196 static const struct ftab
1199 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1201 ftab[] = // sorted on the number of times used
1202 { // in the peephole rules on 2007-10-29
1204 "labelRefCount", labelRefCount //105
1207 "notVolatile", notVolatile //85
1210 "labelRefCountChange", labelRefCountChange //74
1213 "labelInRange", labelInRange //37
1216 "labelJTInRange", labelJTInRange //13
1219 "operandsNotRelated", operandsNotRelated //9
1222 "24bitMode", flat24bitMode //9
1225 "operandsNotSame", operandsNotSame //8
1228 "operandsNotSame3", operandsNotSame3
1231 "operandsNotSame4", operandsNotSame4
1234 "operandsNotSame5", operandsNotSame5
1237 "operandsNotSame6", operandsNotSame6
1240 "operandsNotSame7", operandsNotSame7
1243 "operandsNotSame8", operandsNotSame8
1246 "xramMovcOption", xramMovcOption
1249 "portIsDS390", portIsDS390
1252 "labelIsReturnOnly", labelIsReturnOnly
1255 "labelIsUncondJump", labelIsUncondJump
1258 "okToRemoveSLOC", okToRemoveSLOC
1261 "deadMove", deadMove
1264 "operandsLiteral", operandsLiteral
1267 "useAcallAjmp", useAcallAjmp
1273 /*-----------------------------------------------------------------*/
1274 /* callFuncByName - calls a function as defined in the table */
1275 /*-----------------------------------------------------------------*/
1277 callFuncByName (char *fname,
1279 lineNode * currPl, /* first source line matched */
1280 lineNode * endPl, /* last source line matched */
1284 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1288 /* Isolate the function name part (we are passed the full condition
1289 * string including arguments)
1291 cmdTerm = cmdCopy = Safe_strdup(fname);
1295 funcArgs = funcName = cmdTerm;
1296 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1298 *funcArgs = '\0'; /* terminate the function name */
1302 /* Find the start of the arguments */
1303 if (c == ' ' || c == '\t')
1304 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1307 /* If the arguments started with an opening parenthesis, */
1308 /* use the closing parenthesis for the end of the */
1309 /* arguments and look for the start of another condition */
1310 /* that can optionally follow. If there was no opening */
1311 /* parethesis, then everything that follows are arguments */
1312 /* and there can be no additional conditions. */
1316 int num_parenthesis = 0;
1319 while ((c = *cmdTerm) && (c != ')' || num_parenthesis))
1327 *cmdTerm = '\0'; /* terminate the arguments */
1331 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1337 cmdTerm = NULL; /* closing parenthesis missing */
1346 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1348 if (strcmp (ftab[i].fname, funcName) == 0)
1350 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1358 "could not find named function \"%s\" in "
1359 "peephole function table\n",
1361 // If the function couldn't be found, let's assume it's
1362 // a bad rule and refuse it.
1367 while (rc && cmdTerm);
1374 /*-----------------------------------------------------------------*/
1375 /* printLine - prints a line chain into a given file */
1376 /*-----------------------------------------------------------------*/
1378 printLine (lineNode * head, struct dbuf_s * oBuf)
1380 iCode *last_ic = NULL;
1381 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1385 if (head->ic!=last_ic)
1388 if (debug_iCode_tracking)
1391 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1392 head->ic->block, head->ic->seq);
1394 dbuf_append_str (oBuf, "; iCode lost\n");
1398 /* don't indent comments & labels */
1400 (head->isComment || head->isLabel)) {
1401 dbuf_printf (oBuf, "%s\n", head->line);
1403 if (head->isInline && *head->line=='#') {
1404 // comment out preprocessor directives in inline asm
1405 dbuf_append_char (oBuf, ';');
1407 dbuf_printf (oBuf, "\t%s\n", head->line);
1413 /*-----------------------------------------------------------------*/
1414 /* newPeepRule - creates a new peeprule and attach it to the root */
1415 /*-----------------------------------------------------------------*/
1417 newPeepRule (lineNode * match,
1424 pr = Safe_alloc ( sizeof (peepRule));
1426 pr->replace = replace;
1427 pr->restart = restart;
1431 pr->cond = Safe_strdup (cond);
1436 pr->vars = newHashTable (100);
1438 /* if root is empty */
1440 rootRules = currRule = pr;
1442 currRule = currRule->next = pr;
1447 /*-----------------------------------------------------------------*/
1448 /* newLineNode - creates a new peep line */
1449 /*-----------------------------------------------------------------*/
1451 newLineNode (const char *line)
1455 pl = Safe_alloc ( sizeof (lineNode));
1456 pl->line = Safe_strdup (line);
1461 /*-----------------------------------------------------------------*/
1462 /* connectLine - connects two lines */
1463 /*-----------------------------------------------------------------*/
1465 connectLine (lineNode * pl1, lineNode * pl2)
1469 fprintf (stderr, "trying to connect null line\n");
1479 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1480 if (!*x) { fprintf(stderr,y); return ; } }
1482 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1483 if (!*x) { fprintf(stderr,z); return ; } }
1484 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1485 if (!*x) { fprintf(stderr,z); return ; } }
1487 /*-----------------------------------------------------------------*/
1488 /* getPeepLine - parses the peep lines */
1489 /*-----------------------------------------------------------------*/
1491 getPeepLine (lineNode ** head, char **bpp)
1493 char lines[MAX_PATTERN_LEN];
1497 lineNode *currL = NULL;
1504 fprintf (stderr, "unexpected end of match pattern\n");
1511 while (ISCHARSPACE (*bp) ||
1522 /* read till end of line */
1524 while ((*bp != '\n' && *bp != '}') && *bp)
1529 while (*lp && ISCHARSPACE(*lp))
1531 isComment = (*lp == ';');
1533 if (!isComment || (isComment && !options.noPeepComments))
1539 *head = currL = newLineNode (lines);
1541 currL = connectLine (currL, newLineNode (lines));
1542 currL->isComment = isComment;
1543 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1552 /*-----------------------------------------------------------------*/
1553 /* readRules - reads the rules from a string buffer */
1554 /*-----------------------------------------------------------------*/
1556 readRules (char *bp)
1559 char lines[MAX_PATTERN_LEN];
1563 lineNode *currL = NULL;
1569 /* look for the token "replace" that is the
1571 while (*bp && strncmp (bp, "replace", 7))
1578 /* then look for either "restart" or '{' */
1579 while (strncmp (bp, "restart", 7) &&
1586 fprintf (stderr, "expected 'restart' or '{'\n");
1594 { /* must be restart */
1596 bp += strlen ("restart");
1598 EXPECT_CHR (bp, '{', "expected '{'\n");
1602 /* skip thru all the blank space */
1603 SKIP_SPACE (bp, "unexpected end of rule\n");
1605 match = replace = currL = NULL;
1606 /* we are the start of a rule */
1607 getPeepLine (&match, &bp);
1609 /* now look for by */
1610 EXPECT_STR (bp, "by", "expected 'by'\n");
1612 /* then look for a '{' */
1613 EXPECT_CHR (bp, '{', "expected '{'\n");
1616 /* save char position (needed for generating error msg) */
1619 SKIP_SPACE (bp, "unexpected end of rule\n");
1620 getPeepLine (&replace, &bp);
1622 /* look for a 'if' */
1623 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1626 if (strncmp (bp, "if", 2) == 0)
1629 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1633 fprintf (stderr, "expected condition name\n");
1637 /* look for the condition */
1639 while (*bp && (*bp != '\n'))
1645 newPeepRule (match, replace, lines, restart);
1649 if (*bp && strncmp (bp, "replace", 7))
1651 /* not the start of a new peeprule, so "if" should be here */
1656 /* go to the start of the line following "{" of the "by" token */
1657 while (*rp && (*rp == '\n'))
1660 /* copy text of rule starting with line after "by {" */
1662 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1665 /* and now the rest of the line */
1666 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1670 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1673 newPeepRule (match, replace, NULL, restart);
1679 /*-----------------------------------------------------------------*/
1680 /* keyForVar - returns the numeric key for a var */
1681 /*-----------------------------------------------------------------*/
1687 while (ISCHARDIGIT (*d))
1696 /*-----------------------------------------------------------------*/
1697 /* bindVar - binds a value to a variable in the given hashtable */
1698 /*-----------------------------------------------------------------*/
1700 bindVar (int key, char **s, hTab ** vtab)
1702 char vval[MAX_PATTERN_LEN];
1706 /* first get the value of the variable */
1708 /* the value is ended by a ',' or space or newline or null or ) */
1711 !ISCHARSPACE (*vvx) &&
1717 /* if we find a '(' then we need to balance it */
1729 // include the trailing ')'
1738 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1740 hTabAddItem (vtab, key, vvx);
1743 /*-----------------------------------------------------------------*/
1744 /* matchLine - matches one line */
1745 /*-----------------------------------------------------------------*/
1747 matchLine (char *s, char *d, hTab ** vars)
1754 /* skip white space in both */
1755 while (ISCHARSPACE (*s))
1757 while (ISCHARSPACE (*d))
1760 /* if the destination is a var */
1761 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1763 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1764 /* if the variable is already bound
1765 then it MUST match with dest */
1773 /* variable not bound we need to bind it */
1774 bindVar (keyForVar (d + 1), &s, vars);
1776 /* in either case go past the variable */
1778 while (ISCHARDIGIT (*d))
1781 while (ISCHARSPACE (*s))
1783 while (ISCHARSPACE (*d))
1787 /* they should be an exact match other wise */
1796 /* get rid of the trailing spaces
1797 in both source & destination */
1799 while (ISCHARSPACE (*s))
1803 while (ISCHARSPACE (*d))
1806 /* after all this if only one of them
1807 has something left over then no match */
1814 /*-----------------------------------------------------------------*/
1815 /* matchRule - matches a all the rule lines */
1816 /*-----------------------------------------------------------------*/
1818 matchRule (lineNode * pl,
1823 lineNode *spl; /* source pl */
1824 lineNode *rpl; /* rule peep line */
1826 /* setToNull((void *) &pr->vars); */
1827 /* pr->vars = newHashTable(100); */
1829 /* for all the lines defined in the rule */
1835 /* if the source line starts with a ';' then
1836 comment line don't process or the source line
1837 contains == . debugger information skip it */
1839 (*spl->line == ';' || spl->isDebug))
1845 if (!matchLine (spl->line, rpl->line, &pr->vars))
1853 /* if rules ended */
1856 /* if this rule has additional conditions */
1859 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1878 reassociate_ic_down (lineNode *shead, lineNode *stail,
1879 lineNode *rhead, lineNode *rtail)
1881 lineNode *csl; /* current source line */
1882 lineNode *crl; /* current replacement line */
1888 /* skip over any comments */
1889 while (csl!=stail->next && csl->isComment)
1891 while (crl!=rtail->next && crl->isComment)
1894 /* quit if we reach the end */
1895 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1898 if (matchLine(csl->line,crl->line,NULL))
1910 reassociate_ic_up (lineNode *shead, lineNode *stail,
1911 lineNode *rhead, lineNode *rtail)
1913 lineNode *csl; /* current source line */
1914 lineNode *crl; /* current replacement line */
1920 /* skip over any comments */
1921 while (csl!=shead->prev && csl->isComment)
1923 while (crl!=rhead->prev && crl->isComment)
1926 /* quit if we reach the end */
1927 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1930 if (matchLine(csl->line,crl->line,NULL))
1941 /*------------------------------------------------------------------*/
1942 /* reassociate_ic - reassociate replacement lines with origin iCode */
1943 /*------------------------------------------------------------------*/
1945 reassociate_ic (lineNode *shead, lineNode *stail,
1946 lineNode *rhead, lineNode *rtail)
1948 lineNode *csl; /* current source line */
1949 lineNode *crl; /* current replacement line */
1953 /* Check to see if all the source lines (excluding comments) came
1954 ** for the same iCode
1957 for (csl=shead;csl!=stail->next;csl=csl->next)
1958 if (csl->ic && !csl->isComment)
1963 single_iCode = (ic!=NULL);
1964 for (csl=shead;csl!=stail->next;csl=csl->next)
1965 if ((csl->ic != ic) && !csl->isComment)
1967 /* More than one iCode was found. However, if it's just the
1968 ** last line with the different iCode and it was not changed
1969 ** in the replacement, everything else must be the first iCode.
1971 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1973 rtail->ic = stail->ic;
1974 for (crl=rhead;crl!=rtail;crl=crl->next)
1979 single_iCode = FALSE;
1983 /* If all of the source lines came from the same iCode, then so have
1984 ** all of the replacement lines too.
1988 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1993 /* The source lines span iCodes, so we may end up with replacement
1994 ** lines that we don't know which iCode(s) to associate with. Do the
1995 ** best we can by using the following strategies:
1996 ** 1) Start at the top and scan down. As long as the source line
1997 ** matches the replacement line, they have the same iCode.
1998 ** 2) Start at the bottom and scan up. As long as the source line
1999 ** matches the replacement line, they have the same iCode.
2000 ** 3) For any label in the source, look for a matching label in
2001 ** the replacment. If found, they have the same iCode. From
2002 ** these matching labels, scan down for additional matching
2003 ** lines; if found, they also have the same iCode.
2006 /* Strategy #1: Start at the top and scan down for matches
2008 reassociate_ic_down(shead,stail,rhead,rtail);
2010 /* Strategy #2: Start at the bottom and scan up for matches
2012 reassociate_ic_up(shead,stail,rhead,rtail);
2014 /* Strategy #3: Try to match labels
2019 /* skip over any comments */
2020 while (csl!=stail->next && csl->isComment)
2022 if (csl==stail->next)
2027 /* found a source line label; look for it in the replacment lines */
2031 while (crl!=rtail->next && crl->isComment)
2033 if (crl==rtail->next)
2035 if (matchLine(csl->line, crl->line, NULL))
2037 reassociate_ic_down(csl,stail,crl,rtail);
2047 /* Try to assign a meaningful iCode to any comment that is missing
2048 one. Since they are comments, it's ok to make mistakes; we are just
2049 trying to improve continuity to simplify other tests.
2052 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
2054 if (!crl->ic && ic && crl->isComment)
2061 /*-----------------------------------------------------------------*/
2062 /* replaceRule - does replacement of a matching pattern */
2063 /*-----------------------------------------------------------------*/
2065 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
2067 lineNode *cl = NULL;
2068 lineNode *pl = NULL, *lhead = NULL;
2069 /* a long function name and long variable name can evaluate to
2070 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
2071 char lb[MAX_PATTERN_LEN*4];
2073 lineNode *comment = NULL;
2075 /* collect all the comment lines in the source */
2076 for (cl = *shead; cl != stail; cl = cl->next)
2078 if (cl->line && (*cl->line == ';' || cl->isDebug))
2080 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2081 (comment = newLineNode (cl->line)));
2082 pl->isDebug = cl->isDebug;
2083 pl->isComment = cl->isComment || (*cl->line == ';');
2088 /* for all the lines in the replacement pattern do */
2089 for (pl = pr->replace; pl; pl = pl->next)
2099 /* if the line contains a variable */
2100 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2102 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2105 fprintf (stderr, "used unbound variable in replacement\n");
2113 while (ISCHARDIGIT (*l)) {
2123 cl = connectLine (cl, newLineNode (lb));
2125 lhead = cl = newLineNode (lb);
2126 cl->isComment = pl->isComment;
2127 cl->isLabel = pl->isLabel;
2130 /* add the comments if any to the head of list */
2133 lineNode *lc = comment;
2144 /* determine which iCodes the replacment lines relate to */
2145 reassociate_ic(*shead,stail,lhead,cl);
2147 /* now we need to connect / replace the original chain */
2148 /* if there is a prev then change it */
2151 (*shead)->prev->next = lhead;
2152 lhead->prev = (*shead)->prev;
2155 /* now for the tail */
2156 if (stail && stail->next)
2158 stail->next->prev = cl;
2160 cl->next = stail->next;
2165 /* the replacement is empty - delete the source lines */
2167 (*shead)->prev->next = stail->next;
2169 stail->next->prev = (*shead)->prev;
2170 *shead = stail->next;
2174 /* Returns TRUE if this line is a label definition.
2176 * If so, start will point to the start of the label name,
2177 * and len will be it's length.
2180 isLabelDefinition (const char *line, const char **start, int *len,
2183 const char *cp = line;
2185 /* This line is a label if if consists of:
2186 * [optional whitespace] followed by identifier chars
2187 * (alnum | $ | _ ) followed by a colon.
2190 while (*cp && ISCHARSPACE (*cp))
2202 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2203 (isPeepRule && (*cp == '%')))
2208 if ((cp == *start) || (*cp != ':'))
2213 *len = (cp - (*start));
2217 /* Quick & dirty string hash function. */
2219 hashSymbolName (const char *name)
2225 hash = (hash << 6) ^ *name;
2234 return hash % HTAB_SIZE;
2237 /* Build a hash of all labels in the passed set of lines
2238 * and how many times they are referenced.
2241 buildLabelRefCountHash (lineNode * head)
2248 assert (labelHash == NULL);
2249 labelHash = newHashTable (HTAB_SIZE);
2251 /* First pass: locate all the labels. */
2252 for (line = head; line; line = line->next)
2254 if (line->isLabel ||
2257 /* run isLabelDefinition to:
2258 - look for labels in inline assembler
2259 - calculate labelLen
2261 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2262 labelLen <= SDCC_NAME_MAX)
2264 labelHashEntry *entry;
2266 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2268 memcpy (entry->name, label, labelLen);
2269 entry->name[labelLen] = 0;
2270 entry->refCount = -1;
2272 /* Assume function entry points are referenced somewhere, */
2273 /* even if we can't find a reference (might be from outside */
2275 if (line->ic && (line->ic->op == FUNCTION))
2278 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2284 /* Second pass: for each line, note all the referenced labels. */
2285 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2289 for (i = 0; i < HTAB_SIZE; i++)
2291 labelHashEntry *thisEntry;
2293 thisEntry = hTabFirstItemWK (labelHash, i);
2297 if (strstr (line->line, thisEntry->name))
2299 thisEntry->refCount++;
2301 thisEntry = hTabNextItemWK (labelHash);
2308 /* Spew the contents of the table. Debugging fun only. */
2309 for (i = 0; i < HTAB_SIZE; i++)
2311 labelHashEntry *thisEntry;
2313 thisEntry = hTabFirstItemWK (labelHash, i);
2317 fprintf (stderr, "label: %s ref %d\n",
2318 thisEntry->name, thisEntry->refCount);
2319 thisEntry = hTabNextItemWK (labelHash);
2325 /* How does this work?
2331 replace and restart.
2336 Where is stuff allocated?
2340 /*-----------------------------------------------------------------*/
2341 /* peepHole - matches & substitutes rules */
2342 /*-----------------------------------------------------------------*/
2344 peepHole (lineNode ** pls)
2348 lineNode *mtail = NULL;
2349 bool restart, replaced;
2351 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2352 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2353 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2357 assert(labelHash == NULL);
2364 for (pr = rootRules; pr; pr = pr->next)
2366 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2370 /* if inline assembler then no peep hole */
2374 /* don't waste time starting a match on debug symbol
2376 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2381 /* Tidy up any data stored in the hTab */
2384 if (matchRule (spl, &mtail, pr, *pls))
2386 /* restart at the replaced line */
2392 replaceRule (pls, mtail, pr);
2396 replaceRule (&spl, mtail, pr);
2398 /* if restart rule type then
2399 start at the top again */
2408 hTabDeleteAll (pr->vars);
2409 Safe_free (pr->vars);
2413 freeTrace (&_G.values);
2416 } while (restart == TRUE);
2420 hTabDeleteAll (labelHash);
2421 freeTrace (&_G.labels);
2427 /*-----------------------------------------------------------------*/
2428 /* readFileIntoBuffer - reads a file into a string buffer */
2429 /*-----------------------------------------------------------------*/
2431 readFileIntoBuffer (char *fname)
2437 char lb[MAX_PATTERN_LEN];
2439 if (!(f = fopen (fname, "r")))
2441 fprintf (stderr, "cannot open peep rule file\n");
2445 while ((ch = fgetc (f)) != EOF)
2449 /* if we maxed out our local buffer */
2450 if (nch >= (MAX_PATTERN_LEN - 2))
2453 /* copy it into allocated buffer */
2456 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2457 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2461 rs = Safe_strdup (lb);
2467 /* if some characters left over */
2471 /* copy it into allocated buffer */
2474 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2475 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2479 rs = Safe_strdup (lb);
2485 /*-----------------------------------------------------------------*/
2486 /* initPeepHole - initialises the peep hole optimizer stuff */
2487 /*-----------------------------------------------------------------*/
2493 /* read in the default rules */
2494 if (!options.nopeep)
2496 readRules (port->peep.default_rules);
2499 /* if we have any additional file read it too */
2500 if (options.peep_file)
2502 readRules (s = readFileIntoBuffer (options.peep_file));
2503 setToNull ((void *) &s);
2504 /* override nopeep setting, default rules have not been read */
2509 #if !OPT_DISABLE_PIC
2510 /* Convert the peep rules into pcode.
2511 NOTE: this is only support in the PIC port (at the moment)
2514 peepRules2pCode(rootRules);
2517 #if !OPT_DISABLE_PIC16
2518 /* Convert the peep rules into pcode.
2519 NOTE: this is only support in the PIC port (at the moment)
2520 and the PIC16 port (VR 030601)
2522 if (TARGET_IS_PIC16)
2523 pic16_peepRules2pCode(rootRules);