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 while ((c = *cmdTerm) && c != ')')
1275 *cmdTerm = '\0'; /* terminate the arguments */
1279 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1285 cmdTerm = NULL; /* closing parenthesis missing */
1294 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1296 if (strcmp (ftab[i].fname, funcName) == 0)
1298 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1306 "could not find named function \"%s\" in "
1307 "peephole function table\n",
1309 // If the function couldn't be found, let's assume it's
1310 // a bad rule and refuse it.
1315 while (rc && cmdTerm);
1322 /*-----------------------------------------------------------------*/
1323 /* printLine - prints a line chain into a given file */
1324 /*-----------------------------------------------------------------*/
1326 printLine (lineNode * head, struct dbuf_s * oBuf)
1328 iCode *last_ic = NULL;
1329 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1333 if (head->ic!=last_ic)
1336 if (debug_iCode_tracking)
1339 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1340 head->ic->block, head->ic->seq);
1342 dbuf_append_str (oBuf, "; iCode lost\n");
1346 /* don't indent comments & labels */
1348 (head->isComment || head->isLabel)) {
1349 dbuf_printf (oBuf, "%s\n", head->line);
1351 if (head->isInline && *head->line=='#') {
1352 // comment out preprocessor directives in inline asm
1353 dbuf_append_char (oBuf, ';');
1355 dbuf_printf (oBuf, "\t%s\n", head->line);
1361 /*-----------------------------------------------------------------*/
1362 /* newPeepRule - creates a new peeprule and attach it to the root */
1363 /*-----------------------------------------------------------------*/
1365 newPeepRule (lineNode * match,
1372 pr = Safe_alloc ( sizeof (peepRule));
1374 pr->replace = replace;
1375 pr->restart = restart;
1379 pr->cond = Safe_strdup (cond);
1384 pr->vars = newHashTable (100);
1386 /* if root is empty */
1388 rootRules = currRule = pr;
1390 currRule = currRule->next = pr;
1395 /*-----------------------------------------------------------------*/
1396 /* newLineNode - creates a new peep line */
1397 /*-----------------------------------------------------------------*/
1399 newLineNode (const char *line)
1403 pl = Safe_alloc ( sizeof (lineNode));
1404 pl->line = Safe_strdup (line);
1409 /*-----------------------------------------------------------------*/
1410 /* connectLine - connects two lines */
1411 /*-----------------------------------------------------------------*/
1413 connectLine (lineNode * pl1, lineNode * pl2)
1417 fprintf (stderr, "trying to connect null line\n");
1427 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1428 if (!*x) { fprintf(stderr,y); return ; } }
1430 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1431 if (!*x) { fprintf(stderr,z); return ; } }
1432 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1433 if (!*x) { fprintf(stderr,z); return ; } }
1435 /*-----------------------------------------------------------------*/
1436 /* getPeepLine - parses the peep lines */
1437 /*-----------------------------------------------------------------*/
1439 getPeepLine (lineNode ** head, char **bpp)
1441 char lines[MAX_PATTERN_LEN];
1445 lineNode *currL = NULL;
1452 fprintf (stderr, "unexpected end of match pattern\n");
1459 while (ISCHARSPACE (*bp) ||
1470 /* read till end of line */
1472 while ((*bp != '\n' && *bp != '}') && *bp)
1477 while (*lp && ISCHARSPACE(*lp))
1479 isComment = (*lp == ';');
1481 if (!isComment || (isComment && !options.noPeepComments))
1487 *head = currL = newLineNode (lines);
1489 currL = connectLine (currL, newLineNode (lines));
1490 currL->isComment = isComment;
1491 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1500 /*-----------------------------------------------------------------*/
1501 /* readRules - reads the rules from a string buffer */
1502 /*-----------------------------------------------------------------*/
1504 readRules (char *bp)
1507 char lines[MAX_PATTERN_LEN];
1511 lineNode *currL = NULL;
1517 /* look for the token "replace" that is the
1519 while (*bp && strncmp (bp, "replace", 7))
1526 /* then look for either "restart" or '{' */
1527 while (strncmp (bp, "restart", 7) &&
1534 fprintf (stderr, "expected 'restart' or '{'\n");
1542 { /* must be restart */
1544 bp += strlen ("restart");
1546 EXPECT_CHR (bp, '{', "expected '{'\n");
1550 /* skip thru all the blank space */
1551 SKIP_SPACE (bp, "unexpected end of rule\n");
1553 match = replace = currL = NULL;
1554 /* we are the start of a rule */
1555 getPeepLine (&match, &bp);
1557 /* now look for by */
1558 EXPECT_STR (bp, "by", "expected 'by'\n");
1560 /* then look for a '{' */
1561 EXPECT_CHR (bp, '{', "expected '{'\n");
1564 /* save char position (needed for generating error msg) */
1567 SKIP_SPACE (bp, "unexpected end of rule\n");
1568 getPeepLine (&replace, &bp);
1570 /* look for a 'if' */
1571 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1574 if (strncmp (bp, "if", 2) == 0)
1577 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1581 fprintf (stderr, "expected condition name\n");
1585 /* look for the condition */
1587 while (*bp && (*bp != '\n'))
1593 newPeepRule (match, replace, lines, restart);
1597 if (*bp && strncmp (bp, "replace", 7))
1599 /* not the start of a new peeprule, so "if" should be here */
1604 /* go to the start of the line following "{" of the "by" token */
1605 while (*rp && (*rp == '\n'))
1608 /* copy text of rule starting with line after "by {" */
1610 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1613 /* and now the rest of the line */
1614 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1618 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1621 newPeepRule (match, replace, NULL, restart);
1627 /*-----------------------------------------------------------------*/
1628 /* keyForVar - returns the numeric key for a var */
1629 /*-----------------------------------------------------------------*/
1635 while (ISCHARDIGIT (*d))
1644 /*-----------------------------------------------------------------*/
1645 /* bindVar - binds a value to a variable in the given hashtable */
1646 /*-----------------------------------------------------------------*/
1648 bindVar (int key, char **s, hTab ** vtab)
1650 char vval[MAX_PATTERN_LEN];
1654 /* first get the value of the variable */
1656 /* the value is ended by a ',' or space or newline or null or ) */
1659 !ISCHARSPACE (*vvx) &&
1665 /* if we find a '(' then we need to balance it */
1677 // include the trailing ')'
1686 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1688 hTabAddItem (vtab, key, vvx);
1691 /*-----------------------------------------------------------------*/
1692 /* matchLine - matches one line */
1693 /*-----------------------------------------------------------------*/
1695 matchLine (char *s, char *d, hTab ** vars)
1704 /* skip white space in both */
1705 while (ISCHARSPACE (*s))
1707 while (ISCHARSPACE (*d))
1710 /* if the destination is a var */
1711 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1713 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1714 /* if the variable is already bound
1715 then it MUST match with dest */
1723 /* variable not bound we need to bind it */
1724 bindVar (keyForVar (d + 1), &s, vars);
1726 /* in either case go past the variable */
1728 while (ISCHARDIGIT (*d))
1731 while (ISCHARSPACE (*s))
1733 while (ISCHARSPACE (*d))
1737 /* they should be an exact match other wise */
1746 /* get rid of the trailing spaces
1747 in both source & destination */
1749 while (ISCHARSPACE (*s))
1753 while (ISCHARSPACE (*d))
1756 /* after all this if only one of them
1757 has something left over then no match */
1764 /*-----------------------------------------------------------------*/
1765 /* matchRule - matches a all the rule lines */
1766 /*-----------------------------------------------------------------*/
1768 matchRule (lineNode * pl,
1773 lineNode *spl; /* source pl */
1774 lineNode *rpl; /* rule peep line */
1776 /* setToNull((void *) &pr->vars); */
1777 /* pr->vars = newHashTable(100); */
1779 /* for all the lines defined in the rule */
1785 /* if the source line starts with a ';' then
1786 comment line don't process or the source line
1787 contains == . debugger information skip it */
1789 (*spl->line == ';' || spl->isDebug))
1795 if (!matchLine (spl->line, rpl->line, &pr->vars))
1803 /* if rules ended */
1806 /* if this rule has additional conditions */
1809 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1828 reassociate_ic_down (lineNode *shead, lineNode *stail,
1829 lineNode *rhead, lineNode *rtail)
1831 lineNode *csl; /* current source line */
1832 lineNode *crl; /* current replacement line */
1838 /* skip over any comments */
1839 while (csl!=stail->next && csl->isComment)
1841 while (crl!=rtail->next && crl->isComment)
1844 /* quit if we reach the end */
1845 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1848 if (matchLine(csl->line,crl->line,NULL))
1860 reassociate_ic_up (lineNode *shead, lineNode *stail,
1861 lineNode *rhead, lineNode *rtail)
1863 lineNode *csl; /* current source line */
1864 lineNode *crl; /* current replacement line */
1870 /* skip over any comments */
1871 while (csl!=shead->prev && csl->isComment)
1873 while (crl!=rhead->prev && crl->isComment)
1876 /* quit if we reach the end */
1877 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1880 if (matchLine(csl->line,crl->line,NULL))
1891 /*------------------------------------------------------------------*/
1892 /* reassociate_ic - reassociate replacement lines with origin iCode */
1893 /*------------------------------------------------------------------*/
1895 reassociate_ic (lineNode *shead, lineNode *stail,
1896 lineNode *rhead, lineNode *rtail)
1898 lineNode *csl; /* current source line */
1899 lineNode *crl; /* current replacement line */
1903 /* Check to see if all the source lines (excluding comments) came
1904 ** for the same iCode
1907 for (csl=shead;csl!=stail->next;csl=csl->next)
1908 if (csl->ic && !csl->isComment)
1913 single_iCode = (ic!=NULL);
1914 for (csl=shead;csl!=stail->next;csl=csl->next)
1915 if ((csl->ic != ic) && !csl->isComment)
1917 /* More than one iCode was found. However, if it's just the
1918 ** last line with the different iCode and it was not changed
1919 ** in the replacement, everything else must be the first iCode.
1921 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1923 rtail->ic = stail->ic;
1924 for (crl=rhead;crl!=rtail;crl=crl->next)
1929 single_iCode = FALSE;
1933 /* If all of the source lines came from the same iCode, then so have
1934 ** all of the replacement lines too.
1938 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1943 /* The source lines span iCodes, so we may end up with replacement
1944 ** lines that we don't know which iCode(s) to associate with. Do the
1945 ** best we can by using the following strategies:
1946 ** 1) Start at the top and scan down. As long as the source line
1947 ** matches the replacement line, they have the same iCode.
1948 ** 2) Start at the bottom and scan up. As long as the source line
1949 ** matches the replacement line, they have the same iCode.
1950 ** 3) For any label in the source, look for a matching label in
1951 ** the replacment. If found, they have the same iCode. From
1952 ** these matching labels, scan down for additional matching
1953 ** lines; if found, they also have the same iCode.
1956 /* Strategy #1: Start at the top and scan down for matches
1958 reassociate_ic_down(shead,stail,rhead,rtail);
1960 /* Strategy #2: Start at the bottom and scan up for matches
1962 reassociate_ic_up(shead,stail,rhead,rtail);
1964 /* Strategy #3: Try to match labels
1969 /* skip over any comments */
1970 while (csl!=stail->next && csl->isComment)
1972 if (csl==stail->next)
1977 /* found a source line label; look for it in the replacment lines */
1981 while (crl!=rtail->next && crl->isComment)
1983 if (crl==rtail->next)
1985 if (matchLine(csl->line, crl->line, NULL))
1987 reassociate_ic_down(csl,stail,crl,rtail);
1997 /* Try to assign a meaningful iCode to any comment that is missing
1998 one. Since they are comments, it's ok to make mistakes; we are just
1999 trying to improve continuity to simplify other tests.
2002 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
2004 if (!crl->ic && ic && crl->isComment)
2011 /*-----------------------------------------------------------------*/
2012 /* replaceRule - does replacement of a matching pattern */
2013 /*-----------------------------------------------------------------*/
2015 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
2017 lineNode *cl = NULL;
2018 lineNode *pl = NULL, *lhead = NULL;
2019 /* a long function name and long variable name can evaluate to
2020 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
2021 char lb[MAX_PATTERN_LEN*4];
2023 lineNode *comment = NULL;
2025 /* collect all the comment lines in the source */
2026 for (cl = *shead; cl != stail; cl = cl->next)
2028 if (cl->line && (*cl->line == ';' || cl->isDebug))
2030 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2031 (comment = newLineNode (cl->line)));
2032 pl->isDebug = cl->isDebug;
2033 pl->isComment = cl->isComment || (*cl->line == ';');
2038 /* for all the lines in the replacement pattern do */
2039 for (pl = pr->replace; pl; pl = pl->next)
2049 /* if the line contains a variable */
2050 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2052 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2055 fprintf (stderr, "used unbound variable in replacement\n");
2063 while (ISCHARDIGIT (*l)) {
2073 cl = connectLine (cl, newLineNode (lb));
2075 lhead = cl = newLineNode (lb);
2076 cl->isComment = pl->isComment;
2077 cl->isLabel = pl->isLabel;
2080 /* add the comments if any to the head of list */
2083 lineNode *lc = comment;
2094 /* determine which iCodes the replacment lines relate to */
2095 reassociate_ic(*shead,stail,lhead,cl);
2097 /* now we need to connect / replace the original chain */
2098 /* if there is a prev then change it */
2101 (*shead)->prev->next = lhead;
2102 lhead->prev = (*shead)->prev;
2105 /* now for the tail */
2106 if (stail && stail->next)
2108 stail->next->prev = cl;
2110 cl->next = stail->next;
2115 /* the replacement is empty - delete the source lines */
2117 (*shead)->prev->next = stail->next;
2119 stail->next->prev = (*shead)->prev;
2120 *shead = stail->next;
2124 /* Returns TRUE if this line is a label definition.
2126 * If so, start will point to the start of the label name,
2127 * and len will be it's length.
2130 isLabelDefinition (const char *line, const char **start, int *len,
2133 const char *cp = line;
2135 /* This line is a label if if consists of:
2136 * [optional whitespace] followed by identifier chars
2137 * (alnum | $ | _ ) followed by a colon.
2140 while (*cp && ISCHARSPACE (*cp))
2152 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2153 (isPeepRule && (*cp == '%')))
2158 if ((cp == *start) || (*cp != ':'))
2163 *len = (cp - (*start));
2167 /* Quick & dirty string hash function. */
2169 hashSymbolName (const char *name)
2175 hash = (hash << 6) ^ *name;
2184 return hash % HTAB_SIZE;
2187 /* Build a hash of all labels in the passed set of lines
2188 * and how many times they are referenced.
2191 buildLabelRefCountHash (lineNode * head)
2198 assert (labelHash == NULL);
2199 labelHash = newHashTable (HTAB_SIZE);
2201 /* First pass: locate all the labels. */
2202 for (line = head; line; line = line->next)
2204 if (line->isLabel ||
2207 /* run isLabelDefinition to:
2208 - look for labels in inline assembler
2209 - calculate labelLen
2211 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2212 labelLen <= SDCC_NAME_MAX)
2214 labelHashEntry *entry;
2216 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2218 memcpy (entry->name, label, labelLen);
2219 entry->name[labelLen] = 0;
2220 entry->refCount = -1;
2222 /* Assume function entry points are referenced somewhere, */
2223 /* even if we can't find a reference (might be from outside */
2225 if (line->ic && (line->ic->op == FUNCTION))
2228 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2234 /* Second pass: for each line, note all the referenced labels. */
2235 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2239 for (i = 0; i < HTAB_SIZE; i++)
2241 labelHashEntry *thisEntry;
2243 thisEntry = hTabFirstItemWK (labelHash, i);
2247 if (strstr (line->line, thisEntry->name))
2249 thisEntry->refCount++;
2251 thisEntry = hTabNextItemWK (labelHash);
2258 /* Spew the contents of the table. Debugging fun only. */
2259 for (i = 0; i < HTAB_SIZE; i++)
2261 labelHashEntry *thisEntry;
2263 thisEntry = hTabFirstItemWK (labelHash, i);
2267 fprintf (stderr, "label: %s ref %d\n",
2268 thisEntry->name, thisEntry->refCount);
2269 thisEntry = hTabNextItemWK (labelHash);
2275 /* How does this work?
2281 replace and restart.
2286 Where is stuff allocated?
2290 /*-----------------------------------------------------------------*/
2291 /* peepHole - matches & substitutes rules */
2292 /*-----------------------------------------------------------------*/
2294 peepHole (lineNode ** pls)
2298 lineNode *mtail = NULL;
2299 bool restart, replaced;
2301 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2302 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2303 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2307 assert(labelHash == NULL);
2314 for (pr = rootRules; pr; pr = pr->next)
2316 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2320 /* if inline assembler then no peep hole */
2324 /* don't waste time starting a match on debug symbol
2326 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2331 /* Tidy up any data stored in the hTab */
2334 if (matchRule (spl, &mtail, pr, *pls))
2336 /* restart at the replaced line */
2342 replaceRule (pls, mtail, pr);
2346 replaceRule (&spl, mtail, pr);
2348 /* if restart rule type then
2349 start at the top again */
2358 hTabDeleteAll (pr->vars);
2359 Safe_free (pr->vars);
2363 freeTrace (&_G.values);
2366 } while (restart == TRUE);
2370 hTabDeleteAll (labelHash);
2371 freeTrace (&_G.labels);
2377 /*-----------------------------------------------------------------*/
2378 /* readFileIntoBuffer - reads a file into a string buffer */
2379 /*-----------------------------------------------------------------*/
2381 readFileIntoBuffer (char *fname)
2387 char lb[MAX_PATTERN_LEN];
2389 if (!(f = fopen (fname, "r")))
2391 fprintf (stderr, "cannot open peep rule file\n");
2395 while ((ch = fgetc (f)) != EOF)
2399 /* if we maxed out our local buffer */
2400 if (nch >= (MAX_PATTERN_LEN - 2))
2403 /* copy it into allocated buffer */
2406 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2407 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2411 rs = Safe_strdup (lb);
2417 /* if some charaters left over */
2421 /* copy it into allocated buffer */
2424 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2425 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2429 rs = Safe_strdup (lb);
2435 /*-----------------------------------------------------------------*/
2436 /* initPeepHole - initialises the peep hole optimizer stuff */
2437 /*-----------------------------------------------------------------*/
2443 /* read in the default rules */
2444 if (!options.nopeep)
2446 readRules (port->peep.default_rules);
2449 /* if we have any additional file read it too */
2450 if (options.peep_file)
2452 readRules (s = readFileIntoBuffer (options.peep_file));
2453 setToNull ((void *) &s);
2454 /* override nopeep setting, default rules have not been read */
2459 #if !OPT_DISABLE_PIC
2460 /* Convert the peep rules into pcode.
2461 NOTE: this is only support in the PIC port (at the moment)
2464 peepRules2pCode(rootRules);
2467 #if !OPT_DISABLE_PIC16
2468 /* Convert the peep rules into pcode.
2469 NOTE: this is only support in the PIC port (at the moment)
2470 and the PIC16 port (VR 030601)
2472 if (TARGET_IS_PIC16)
2473 pic16_peepRules2pCode(rootRules);