1 /*-------------------------------------------------------------------------
2 SDCCpeeph.c - The peep hole optimizer: for interpreting the
5 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
27 #include "dbuf_string.h"
29 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
30 #define ISCHARSPACE(c) isspace((unsigned char)c)
31 #define ISCHARALNUM(c) isalnum((unsigned char)c)
33 static peepRule *rootRules = NULL;
34 static peepRule *currRule = NULL;
38 hTab *labelHash = NULL;
46 static int hashSymbolName (const char *name);
47 static void buildLabelRefCountHash (lineNode * head);
48 static void bindVar (int key, char **s, hTab ** vtab);
50 static bool matchLine (char *, char *, hTab **);
52 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
53 lineNode *head, char *cmdLine)
56 void peepRules2pCode(peepRule *);
59 #if !OPT_DISABLE_PIC16
60 void pic16_peepRules2pCode(peepRule *);
63 /*-----------------------------------------------------------------*/
64 /* pcDistance - afinds a label back ward or forward */
65 /*-----------------------------------------------------------------*/
68 pcDistance (lineNode * cpos, char *lbl, bool back)
71 char buff[MAX_PATTERN_LEN];
74 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
82 if (port->peep.getSize) {
83 dist += port->peep.getSize(pl);
89 if (strncmp (pl->line, buff, strlen (buff)) == 0)
101 /*-----------------------------------------------------------------*/
102 /* flat24bitModeAndPortDS390 - */
103 /*-----------------------------------------------------------------*/
104 FBYNAME (flat24bitModeAndPortDS390)
106 return (((strcmp(port->target,"ds390") == 0) ||
107 (strcmp(port->target,"ds400") == 0)) &&
108 (options.model == MODEL_FLAT24));
111 /*-----------------------------------------------------------------*/
112 /* portIsDS390 - return true if port is DS390 */
113 /*-----------------------------------------------------------------*/
114 FBYNAME (portIsDS390)
116 return ((strcmp(port->target,"ds390") == 0) ||
117 (strcmp(port->target,"ds400") == 0));
120 /*-----------------------------------------------------------------*/
121 /* flat24bitMode - will check to see if we are in flat24 mode */
122 /*-----------------------------------------------------------------*/
123 FBYNAME (flat24bitMode)
125 return (options.model == MODEL_FLAT24);
128 /*-----------------------------------------------------------------*/
129 /* xramMovcOption - check if using movc to read xram */
130 /*-----------------------------------------------------------------*/
131 FBYNAME (xramMovcOption)
133 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
136 /*-----------------------------------------------------------------*/
137 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
138 /*-----------------------------------------------------------------*/
139 FBYNAME (useAcallAjmp)
141 return (options.acall_ajmp && (strcmp(port->target,"mcs51") == 0));
146 /*-----------------------------------------------------------------*/
147 /* labelInRange - will check to see if label %5 is within range */
148 /*-----------------------------------------------------------------*/
149 FBYNAME (labelInRange)
151 /* assumes that %5 pattern variable has the label name */
152 char *lbl = hTabItemWithKey (vars, 5);
158 /* Don't optimize jumps in a jump table; a more generic test */
159 if (currPl->ic && currPl->ic->op == JUMPTABLE)
162 /* if the previous two instructions are "ljmp"s then don't
163 do it since it can be part of a jump table */
164 if (currPl->prev && currPl->prev->prev &&
165 strstr (currPl->prev->line, "ljmp") &&
166 strstr (currPl->prev->prev->line, "ljmp"))
169 /* calculate the label distance : the jump for reladdr can be
170 +/- 127 bytes, here Iam assuming that an average 8051
171 instruction is 2 bytes long, so if the label is more than
172 63 intructions away, the label is considered out of range
173 for a relative jump. we could get more precise this will
174 suffice for now since it catches > 90% cases */
175 dist = (pcDistance (currPl, lbl, TRUE) +
176 pcDistance (currPl, lbl, FALSE));
178 /* changed to 127, now that pcDistance return actual number of bytes */
179 if (!dist || dist > 127)
186 /*-----------------------------------------------------------------*/
187 /* labelJTInRange - will check to see if label %5 and up are */
189 /* Specifically meant to optimize long (3-byte) jumps to short */
190 /* (2-byte) jumps in jumptables */
191 /*-----------------------------------------------------------------*/
192 FBYNAME (labelJTInRange)
197 if (!getenv("SDCC_SJMP_JUMPTABLE"))
200 /* Only optimize within a jump table */
201 if (currPl->ic && currPl->ic->op != JUMPTABLE)
204 count = elementsInSet( IC_JTLABELS (currPl->ic) );
206 /* check all labels (this is needed if the case statements are unsorted) */
207 for (i=0; i<count; i++)
209 /* assumes that the %5 pattern variable has the first ljmp label */
210 lbl = hTabItemWithKey (vars, 5+i);
214 dist = pcDistance (currPl, lbl, FALSE);
216 /* three terms used to calculate allowable distance */
217 // 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);
219 dist > 127+ /* range of sjmp */
220 (7+3*i)+ /* offset between this jump and currPl,
221 should use pcDistance instead? */
222 (count-i-1) /* if peephole applies distance is shortened */
230 /*-----------------------------------------------------------------*/
231 /* labelIsReturnOnly - Check if label %5 is followed by RET */
232 /*-----------------------------------------------------------------*/
233 FBYNAME (labelIsReturnOnly)
235 /* assumes that %5 pattern variable has the label name */
236 const char *label, *p;
241 /* Don't optimize jumps in a jump table; a more generic test */
242 if (currPl->ic && currPl->ic->op == JUMPTABLE)
245 label = hTabItemWithKey (vars, 5);
250 for(pl = currPl; pl; pl = pl->next)
252 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
254 if (strncmp(pl->line, label, len) == 0)
255 break; /* Found Label */
256 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
257 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
258 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
259 *(pl->line+5) != '$')
261 return FALSE; /* non-local label encountered */
266 return FALSE; /* did not find the label */
268 while (pl && (pl->isDebug || pl->isComment))
270 if (!pl || !pl->line || pl->isDebug)
271 return FALSE; /* next line not valid */
273 for (p = pl->line; *p && ISCHARSPACE(*p); p++)
279 if (strcmp(p, retInst) == 0)
285 /*-----------------------------------------------------------------*/
286 /* labelIsUncondJump - Check if label %5 is followed by an */
287 /* unconditional jump and put the destination of that jump in %6 */
288 /*-----------------------------------------------------------------*/
289 FBYNAME (labelIsUncondJump)
291 /* assumes that %5 pattern variable has the label name */
296 char * jpInst = NULL;
298 /* Don't optimize jumps in a jump table; a more generic test */
299 if (currPl->ic && currPl->ic->op == JUMPTABLE)
302 label = hTabItemWithKey (vars, 5);
307 for (pl = currPl; pl; pl = pl->next)
309 if (pl->line && !pl->isDebug && !pl->isComment && pl->isLabel)
311 if (strncmp(pl->line, label, len) == 0)
312 break; /* Found Label */
313 if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
314 !ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
315 !ISCHARDIGIT(*(pl->line+3)) || !ISCHARDIGIT(*(pl->line+4)) ||
316 *(pl->line+5) != '$')
318 return FALSE; /* non-local label encountered */
323 return FALSE; /* did not find the label */
325 while (pl && (pl->isDebug || pl->isComment))
327 if (!pl || !pl->line)
328 return FALSE; /* next line not valid */
330 while (*p && ISCHARSPACE(*p))
333 if (TARGET_MCS51_LIKE)
339 len = strlen(jpInst);
340 if (strncmp(p, jpInst, len) != 0)
341 return FALSE; /* next line is no jump */
343 while (*p && ISCHARSPACE(*p))
347 while (*q && *q!=';')
349 while (q>p && ISCHARSPACE(*q))
353 return FALSE; /* no destination? */
356 while (q>p && *q!=',')
359 return FALSE; /* conditional jump */
361 if (strcmp(p, q) == 0)
362 return FALSE; /* labels are equal */
363 /* now put the destination in %6 */
364 bindVar (6, &p, &vars);
369 /*-----------------------------------------------------------------*/
370 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
371 /* usage of it in the code depends on a value from this section */
372 /*-----------------------------------------------------------------*/
373 FBYNAME (okToRemoveSLOC)
376 const char *sloc, *p;
377 int dummy1, dummy2, dummy3;
379 /* assumes that %1 as the SLOC name */
380 sloc = hTabItemWithKey (vars, 1);
381 if (sloc == NULL) return FALSE;
382 p = strstr(sloc, "sloc");
383 if (p == NULL) return FALSE;
385 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
386 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
387 /* the sloc name begins with that. Probably not really necessary */
389 /* Look for any occurance of this SLOC before the peephole match */
390 for (pl = currPl->prev; pl; pl = pl->prev) {
391 if (pl->line && !pl->isDebug && !pl->isComment
392 && *pl->line != ';' && strstr(pl->line, sloc))
395 /* Look for any occurance of this SLOC after the peephole match */
396 for (pl = endPl->next; pl; pl = pl->next) {
397 if (pl->line && !pl->isDebug && !pl->isComment
398 && *pl->line != ';' && strstr(pl->line, sloc))
401 return TRUE; /* safe for a peephole to remove it :) */
404 /*-----------------------------------------------------------------*/
405 /* deadMove - Check, if a pop/push pair can be removed */
406 /*-----------------------------------------------------------------*/
409 const char *reg = hTabItemWithKey (vars, 1);
411 if (port->peep.deadMove)
412 return port->peep.deadMove (reg, currPl, head);
414 fprintf (stderr, "Function deadMove not initialized in port structure\n");
418 /*-----------------------------------------------------------------*/
419 /* operandsNotSame - check if %1 & %2 are the same */
420 /*-----------------------------------------------------------------*/
421 FBYNAME (operandsNotSame)
423 char *op1 = hTabItemWithKey (vars, 1);
424 char *op2 = hTabItemWithKey (vars, 2);
426 if (strcmp (op1, op2) == 0)
432 /*-----------------------------------------------------------------*/
433 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
434 /*-----------------------------------------------------------------*/
435 FBYNAME (operandsNotSame3)
437 char *op1 = hTabItemWithKey (vars, 1);
438 char *op2 = hTabItemWithKey (vars, 2);
439 char *op3 = hTabItemWithKey (vars, 3);
441 if ( (strcmp (op1, op2) == 0) ||
442 (strcmp (op1, op3) == 0) ||
443 (strcmp (op2, op3) == 0) )
449 /*-----------------------------------------------------------------*/
450 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
451 /*-----------------------------------------------------------------*/
452 FBYNAME (operandsNotSame4)
454 char *op1 = hTabItemWithKey (vars, 1);
455 char *op2 = hTabItemWithKey (vars, 2);
456 char *op3 = hTabItemWithKey (vars, 3);
457 char *op4 = hTabItemWithKey (vars, 4);
459 if ( (strcmp (op1, op2) == 0) ||
460 (strcmp (op1, op3) == 0) ||
461 (strcmp (op1, op4) == 0) ||
462 (strcmp (op2, op3) == 0) ||
463 (strcmp (op2, op4) == 0) ||
464 (strcmp (op3, op4) == 0) )
470 /*-----------------------------------------------------------------*/
471 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
472 /*-----------------------------------------------------------------*/
473 FBYNAME (operandsNotSame5)
475 char *op1 = hTabItemWithKey (vars, 1);
476 char *op2 = hTabItemWithKey (vars, 2);
477 char *op3 = hTabItemWithKey (vars, 3);
478 char *op4 = hTabItemWithKey (vars, 4);
479 char *op5 = hTabItemWithKey (vars, 5);
481 if ( (strcmp (op1, op2) == 0) ||
482 (strcmp (op1, op3) == 0) ||
483 (strcmp (op1, op4) == 0) ||
484 (strcmp (op1, op5) == 0) ||
485 (strcmp (op2, op3) == 0) ||
486 (strcmp (op2, op4) == 0) ||
487 (strcmp (op2, op5) == 0) ||
488 (strcmp (op3, op4) == 0) ||
489 (strcmp (op3, op5) == 0) ||
490 (strcmp (op4, op5) == 0) )
496 /*-----------------------------------------------------------------*/
497 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
498 /*-----------------------------------------------------------------*/
499 FBYNAME (operandsNotSame6)
501 char *op1 = hTabItemWithKey (vars, 1);
502 char *op2 = hTabItemWithKey (vars, 2);
503 char *op3 = hTabItemWithKey (vars, 3);
504 char *op4 = hTabItemWithKey (vars, 4);
505 char *op5 = hTabItemWithKey (vars, 5);
506 char *op6 = hTabItemWithKey (vars, 6);
508 if ( (strcmp (op1, op2) == 0) ||
509 (strcmp (op1, op3) == 0) ||
510 (strcmp (op1, op4) == 0) ||
511 (strcmp (op1, op5) == 0) ||
512 (strcmp (op1, op6) == 0) ||
513 (strcmp (op2, op3) == 0) ||
514 (strcmp (op2, op4) == 0) ||
515 (strcmp (op2, op5) == 0) ||
516 (strcmp (op2, op6) == 0) ||
517 (strcmp (op3, op4) == 0) ||
518 (strcmp (op3, op5) == 0) ||
519 (strcmp (op3, op6) == 0) ||
520 (strcmp (op4, op5) == 0) ||
521 (strcmp (op4, op6) == 0) ||
522 (strcmp (op5, op6) == 0) )
529 /*-----------------------------------------------------------------*/
530 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
531 /*-----------------------------------------------------------------*/
532 FBYNAME (operandsNotSame7)
534 char *op1 = hTabItemWithKey (vars, 1);
535 char *op2 = hTabItemWithKey (vars, 2);
536 char *op3 = hTabItemWithKey (vars, 3);
537 char *op4 = hTabItemWithKey (vars, 4);
538 char *op5 = hTabItemWithKey (vars, 5);
539 char *op6 = hTabItemWithKey (vars, 6);
540 char *op7 = hTabItemWithKey (vars, 7);
542 if ( (strcmp (op1, op2) == 0) ||
543 (strcmp (op1, op3) == 0) ||
544 (strcmp (op1, op4) == 0) ||
545 (strcmp (op1, op5) == 0) ||
546 (strcmp (op1, op6) == 0) ||
547 (strcmp (op1, op7) == 0) ||
548 (strcmp (op2, op3) == 0) ||
549 (strcmp (op2, op4) == 0) ||
550 (strcmp (op2, op5) == 0) ||
551 (strcmp (op2, op6) == 0) ||
552 (strcmp (op2, op7) == 0) ||
553 (strcmp (op3, op4) == 0) ||
554 (strcmp (op3, op5) == 0) ||
555 (strcmp (op3, op6) == 0) ||
556 (strcmp (op3, op7) == 0) ||
557 (strcmp (op4, op5) == 0) ||
558 (strcmp (op4, op6) == 0) ||
559 (strcmp (op4, op7) == 0) ||
560 (strcmp (op5, op6) == 0) ||
561 (strcmp (op5, op7) == 0) ||
562 (strcmp (op6, op7) == 0) )
568 /*-----------------------------------------------------------------*/
569 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
570 /*-----------------------------------------------------------------*/
571 FBYNAME (operandsNotSame8)
573 char *op1 = hTabItemWithKey (vars, 1);
574 char *op2 = hTabItemWithKey (vars, 2);
575 char *op3 = hTabItemWithKey (vars, 3);
576 char *op4 = hTabItemWithKey (vars, 4);
577 char *op5 = hTabItemWithKey (vars, 5);
578 char *op6 = hTabItemWithKey (vars, 6);
579 char *op7 = hTabItemWithKey (vars, 7);
580 char *op8 = hTabItemWithKey (vars, 8);
582 if ( (strcmp (op1, op2) == 0) ||
583 (strcmp (op1, op3) == 0) ||
584 (strcmp (op1, op4) == 0) ||
585 (strcmp (op1, op5) == 0) ||
586 (strcmp (op1, op6) == 0) ||
587 (strcmp (op1, op7) == 0) ||
588 (strcmp (op1, op8) == 0) ||
589 (strcmp (op2, op3) == 0) ||
590 (strcmp (op2, op4) == 0) ||
591 (strcmp (op2, op5) == 0) ||
592 (strcmp (op2, op6) == 0) ||
593 (strcmp (op2, op7) == 0) ||
594 (strcmp (op2, op8) == 0) ||
595 (strcmp (op3, op4) == 0) ||
596 (strcmp (op3, op5) == 0) ||
597 (strcmp (op3, op6) == 0) ||
598 (strcmp (op3, op7) == 0) ||
599 (strcmp (op3, op8) == 0) ||
600 (strcmp (op4, op5) == 0) ||
601 (strcmp (op4, op6) == 0) ||
602 (strcmp (op4, op7) == 0) ||
603 (strcmp (op4, op8) == 0) ||
604 (strcmp (op5, op6) == 0) ||
605 (strcmp (op5, op7) == 0) ||
606 (strcmp (op5, op8) == 0) ||
607 (strcmp (op6, op7) == 0) ||
608 (strcmp (op6, op8) == 0) ||
609 (strcmp (op7, op8) == 0) )
615 /*-----------------------------------------------------------------*/
616 /* labelHashEntry- searches for a label in the list labelHash */
617 /* Builds labelHash, if it does not yet exist. */
618 /* Returns the labelHashEntry or NULL */
619 /*-----------------------------------------------------------------*/
621 getLabelRef (const char *label, lineNode *head)
623 labelHashEntry *entry;
625 /* If we don't have the label hash table yet, build it. */
628 buildLabelRefCountHash (head);
631 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
635 if (!strcmp (label, entry->name))
639 entry = hTabNextItemWK (labelHash);
646 * takes two parameters: a variable (bound to a label name)
647 * and an expected reference count.
649 * Returns TRUE if that label is defined and referenced exactly
650 * the given number of times.
652 FBYNAME (labelRefCount)
654 int varNumber, expectedRefCount;
657 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
659 char *label = hTabItemWithKey (vars, varNumber);
663 labelHashEntry *entry = getLabelRef (label, head);
669 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
670 label, entry->refCount, expectedRefCount);
673 rc = (expectedRefCount == entry->refCount);
677 fprintf (stderr, "*** internal error: no label has entry for"
678 " %s in labelRefCount peephole.\n",
684 fprintf (stderr, "*** internal error: var %d not bound"
685 " in peephole labelRefCount rule.\n",
693 "*** internal error: labelRefCount peephole restriction"
694 " malformed: %s\n", cmdLine);
700 /* labelRefCountChange:
701 * takes two parameters: a variable (bound to a label name)
702 * and a signed int for changing the reference count.
704 * Please note, this function is not a conditional. It unconditionally
705 * changes the label. It should be passed as the 'last' function
706 * so it only is applied if all other conditions have been met.
708 * should always return TRUE
710 FBYNAME (labelRefCountChange)
712 int varNumber, RefCountDelta;
715 /* If we don't have the label hash table yet, build it. */
718 buildLabelRefCountHash (head);
721 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
723 char *label = hTabItemWithKey (vars, varNumber);
727 labelHashEntry *entry;
729 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
733 if (!strcmp (label, entry->name))
737 entry = hTabNextItemWK (labelHash);
741 if (0 <= entry->refCount + RefCountDelta)
743 entry->refCount += RefCountDelta;
748 fprintf (stderr, "*** internal error: label %s may not get"
749 " negative refCount in %s peephole.\n",
750 label, __FUNCTION__);
755 fprintf (stderr, "*** internal error: no label has entry for"
756 " %s in %s peephole.\n",
757 label, __FUNCTION__);
762 fprintf (stderr, "*** internal error: var %d not bound"
763 " in peephole %s rule.\n",
764 varNumber, __FUNCTION__);
770 "*** internal error: labelRefCount peephole restriction"
771 " malformed: %s\n", cmdLine);
777 /* Within the context of the lines currPl through endPl, determine
778 ** if the variable var contains a symbol that is volatile. Returns
779 ** TRUE only if it is certain that this was not volatile (the symbol
780 ** was found and not volatile, or var was a constant or CPU register).
781 ** Returns FALSE if the symbol was found and volatile, the symbol was
782 ** not found, or var was a indirect/pointer addressing mode.
785 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
787 char symname[SDCC_NAME_MAX + 1];
794 /* Can't tell if indirect accesses are volatile or not, so
795 ** assume they are, just to be safe.
797 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
802 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
804 if (strstr(var,"(bc)"))
806 if (strstr(var,"(de)"))
808 if (strstr(var,"(hl)"))
810 if (strstr(var,"(ix"))
812 if (strstr(var,"(iy"))
816 /* Extract a symbol name from the variable */
817 while (*vp && (*vp!='_'))
819 while (*vp && (ISCHARALNUM(*vp) || *vp=='_'))
825 /* Nothing resembling a symbol name was found, so it can't
832 for (cl = currPl; cl!=endPl->next; cl = cl->next)
834 if (cl->ic && (cl->ic!=last_ic))
840 op = IC_COND (cl->ic);
841 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
842 return !op->isvolatile;
844 op = IC_JTCOND (cl->ic);
845 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
846 return !op->isvolatile;
848 op = IC_LEFT (cl->ic);
849 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
850 return !op->isvolatile;
851 op = IC_RIGHT (cl->ic);
852 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
853 return !op->isvolatile;
854 op = IC_RESULT (cl->ic);
855 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
856 return !op->isvolatile;
861 /* Couldn't find the symbol for some reason. Assume volatile. */
867 * This rule restriction has two different behaviours depending on
868 * the number of parameters given.
870 * if notVolatile (no parameters given)
871 * The rule is applied only if none of the iCodes originating
872 * the matched pattern reference a volatile operand.
874 * if notVolatile %1 ... (one or more parameters given)
875 * The rule is applied if the parameters are not expressions
876 * containing volatile symbols and are not pointer accesses.
879 FBYNAME (notVolatile)
890 /* If no parameters given, just scan the iCodes for volatile operands */
891 for (cl = currPl; cl!=endPl->next; cl = cl->next)
898 op = IC_COND (cl->ic);
899 if (IS_SYMOP (op) && op->isvolatile)
902 op = IC_JTCOND (cl->ic);
903 if (IS_SYMOP (op) && op->isvolatile)
906 op = IC_LEFT (cl->ic);
907 if (IS_SYMOP (op) && op->isvolatile)
909 op = IC_RIGHT (cl->ic);
910 if (IS_SYMOP (op) && op->isvolatile)
912 op = IC_RESULT (cl->ic);
913 if (IS_SYMOP (op) && op->isvolatile)
921 /* There were parameters; check the volatility of each */
922 while (*cmdLine && ISCHARSPACE(*cmdLine))
929 if (!ISCHARDIGIT(*cmdLine))
931 varNumber = strtol(cmdLine, &digitend, 10);
933 while (*cmdLine && ISCHARSPACE(*cmdLine))
936 var = hTabItemWithKey (vars, varNumber);
940 notvol = notVolatileVariable (var, currPl, endPl);
946 fprintf (stderr, "*** internal error: var %d not bound"
947 " in peephole notVolatile rule.\n",
958 "*** internal error: notVolatile peephole restriction"
959 " malformed: %s\n", cmdLine);
964 /*------------------------------------------------------------------*/
965 /* setFromConditionArgs - parse a peephole condition's arguments */
966 /* to produce a set of strings, one per argument. Variables %x will */
967 /* be replaced with their values. String literals (in single quotes)*/
968 /* are accepted and return in unquoted form. */
969 /*------------------------------------------------------------------*/
971 setFromConditionArgs (char *cmdLine, hTab * vars)
976 set *operands = NULL;
981 while (*cmdLine && ISCHARSPACE(*cmdLine))
989 if (!ISCHARDIGIT(*cmdLine))
991 varNumber = strtol(cmdLine, &digitend, 10);
994 var = hTabItemWithKey (vars, varNumber);
998 addSetHead (&operands, var);
1003 else if (*cmdLine == '\'' )
1005 char quote = *cmdLine;
1008 while (*cmdLine && *cmdLine != quote)
1010 if (*cmdLine == quote)
1014 addSetHead (&operands, var);
1019 while (*cmdLine && ISCHARSPACE(*cmdLine))
1026 deleteSet (&operands);
1031 operandBaseName (const char *op)
1033 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
1035 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
1037 if (!strncmp (op, "ar", 2) && ISCHARDIGIT(*(op+2)) && !*(op+3))
1045 /*-------------------------------------------------------------------*/
1046 /* operandsNotRelated - returns true if the condition's operands are */
1047 /* not related (taking into account register name aliases). N-way */
1048 /* comparison performed between all operands. */
1049 /*-------------------------------------------------------------------*/
1050 FBYNAME (operandsNotRelated)
1053 const char *op1, *op2;
1055 operands = setFromConditionArgs (cmdLine, vars);
1060 "*** internal error: operandsNotRelated peephole restriction"
1061 " malformed: %s\n", cmdLine);
1065 while ((op1 = setFirstItem (operands)))
1067 deleteSetItem (&operands, (void*)op1);
1068 op1 = operandBaseName (op1);
1070 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
1072 op2 = operandBaseName (op2);
1073 if (strcmp (op1, op2) == 0)
1075 deleteSet (&operands);
1081 deleteSet (&operands);
1086 /*-------------------------------------------------------------------*/
1087 /* operandsLiteral - returns true of the condition's operands are */
1089 /*-------------------------------------------------------------------*/
1090 FBYNAME (operandsLiteral)
1095 operands = setFromConditionArgs (cmdLine, vars);
1100 "*** internal error: operandsLiteral peephole restriction"
1101 " malformed: %s\n", cmdLine);
1105 for (op = setFirstItem (operands); op; op = setNextItem (operands))
1109 deleteSet (&operands);
1114 deleteSet (&operands);
1119 /*-----------------------------------------------------------------*/
1120 /* callFuncByName - calls a function as defined in the table */
1121 /*-----------------------------------------------------------------*/
1123 callFuncByName (char *fname,
1132 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
1137 "labelInRange", labelInRange
1141 "labelJTInRange", labelJTInRange
1145 "operandsNotSame", operandsNotSame
1149 "operandsNotSame3", operandsNotSame3
1153 "operandsNotSame4", operandsNotSame4
1157 "operandsNotSame5", operandsNotSame5
1161 "operandsNotSame6", operandsNotSame6
1165 "operandsNotSame7", operandsNotSame7
1169 "operandsNotSame8", operandsNotSame8
1173 "24bitMode", flat24bitMode
1177 "xramMovcOption", xramMovcOption
1181 "labelRefCount", labelRefCount
1185 "portIsDS390", portIsDS390
1188 "labelIsReturnOnly", labelIsReturnOnly
1191 "labelIsUncondJump", labelIsUncondJump
1194 "okToRemoveSLOC", okToRemoveSLOC
1197 "deadMove", deadMove
1200 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1203 "notVolatile", notVolatile
1206 "operandsNotRelated", operandsNotRelated
1209 "operandsLiteral", operandsLiteral
1212 "labelRefCountChange", labelRefCountChange
1215 "useAcallAjmp", useAcallAjmp
1219 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1223 /* Isolate the function name part (we are passed the full condition
1224 * string including arguments)
1226 cmdTerm = cmdCopy = Safe_strdup(fname);
1230 funcArgs = funcName = cmdTerm;
1231 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1233 *funcArgs = '\0'; /* terminate the function name */
1237 /* Find the start of the arguments */
1238 if (c == ' ' || c == '\t')
1239 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1242 /* If the arguments started with an opening parenthesis, */
1243 /* use the closing parenthesis for the end of the */
1244 /* arguments and look for the start of another condition */
1245 /* that can optionally follow. If there was no opening */
1246 /* parethesis, then everything that follows are arguments */
1247 /* and there can be no additional conditions. */
1251 while ((c = *cmdTerm) && c != ')')
1253 *cmdTerm = '\0'; /* terminate the arguments */
1257 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1263 cmdTerm = NULL; /* closing parenthesis missing */
1272 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1274 if (strcmp (ftab[i].fname, funcName) == 0)
1276 rc = (*ftab[i].func) (vars, currPl, endPl, head, funcArgs);
1284 "could not find named function \"%s\" in "
1285 "peephole function table\n",
1287 // If the function couldn't be found, let's assume it's
1288 // a bad rule and refuse it.
1293 while (rc && cmdTerm);
1300 /*-----------------------------------------------------------------*/
1301 /* printLine - prints a line chain into a given file */
1302 /*-----------------------------------------------------------------*/
1304 printLine (lineNode * head, struct dbuf_s * oBuf)
1306 iCode *last_ic = NULL;
1307 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1311 if (head->ic!=last_ic)
1314 if (debug_iCode_tracking)
1317 dbuf_printf (oBuf, "; block = %d, seq = %d\n",
1318 head->ic->block, head->ic->seq);
1320 dbuf_append_str (oBuf, "; iCode lost\n");
1324 /* don't indent comments & labels */
1326 (head->isComment || head->isLabel)) {
1327 dbuf_printf (oBuf, "%s\n", head->line);
1329 if (head->isInline && *head->line=='#') {
1330 // comment out preprocessor directives in inline asm
1331 dbuf_append_char (oBuf, ';');
1333 dbuf_printf (oBuf, "\t%s\n", head->line);
1339 /*-----------------------------------------------------------------*/
1340 /* newPeepRule - creates a new peeprule and attach it to the root */
1341 /*-----------------------------------------------------------------*/
1343 newPeepRule (lineNode * match,
1350 pr = Safe_alloc ( sizeof (peepRule));
1352 pr->replace = replace;
1353 pr->restart = restart;
1357 pr->cond = Safe_strdup (cond);
1362 pr->vars = newHashTable (100);
1364 /* if root is empty */
1366 rootRules = currRule = pr;
1368 currRule = currRule->next = pr;
1373 /*-----------------------------------------------------------------*/
1374 /* newLineNode - creates a new peep line */
1375 /*-----------------------------------------------------------------*/
1377 newLineNode (const char *line)
1381 pl = Safe_alloc ( sizeof (lineNode));
1382 pl->line = Safe_strdup (line);
1387 /*-----------------------------------------------------------------*/
1388 /* connectLine - connects two lines */
1389 /*-----------------------------------------------------------------*/
1391 connectLine (lineNode * pl1, lineNode * pl2)
1395 fprintf (stderr, "trying to connect null line\n");
1405 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
1406 if (!*x) { fprintf(stderr,y); return ; } }
1408 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1409 if (!*x) { fprintf(stderr,z); return ; } }
1410 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1411 if (!*x) { fprintf(stderr,z); return ; } }
1413 /*-----------------------------------------------------------------*/
1414 /* getPeepLine - parses the peep lines */
1415 /*-----------------------------------------------------------------*/
1417 getPeepLine (lineNode ** head, char **bpp)
1419 char lines[MAX_PATTERN_LEN];
1423 lineNode *currL = NULL;
1430 fprintf (stderr, "unexpected end of match pattern\n");
1437 while (ISCHARSPACE (*bp) ||
1448 /* read till end of line */
1450 while ((*bp != '\n' && *bp != '}') && *bp)
1455 while (*lp && ISCHARSPACE(*lp))
1457 isComment = (*lp == ';');
1459 if (!isComment || (isComment && !options.noPeepComments))
1465 *head = currL = newLineNode (lines);
1467 currL = connectLine (currL, newLineNode (lines));
1468 currL->isComment = isComment;
1469 currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
1478 /*-----------------------------------------------------------------*/
1479 /* readRules - reads the rules from a string buffer */
1480 /*-----------------------------------------------------------------*/
1482 readRules (char *bp)
1485 char lines[MAX_PATTERN_LEN];
1489 lineNode *currL = NULL;
1495 /* look for the token "replace" that is the
1497 while (*bp && strncmp (bp, "replace", 7))
1504 /* then look for either "restart" or '{' */
1505 while (strncmp (bp, "restart", 7) &&
1512 fprintf (stderr, "expected 'restart' or '{'\n");
1520 { /* must be restart */
1522 bp += strlen ("restart");
1524 EXPECT_CHR (bp, '{', "expected '{'\n");
1528 /* skip thru all the blank space */
1529 SKIP_SPACE (bp, "unexpected end of rule\n");
1531 match = replace = currL = NULL;
1532 /* we are the start of a rule */
1533 getPeepLine (&match, &bp);
1535 /* now look for by */
1536 EXPECT_STR (bp, "by", "expected 'by'\n");
1538 /* then look for a '{' */
1539 EXPECT_CHR (bp, '{', "expected '{'\n");
1542 /* save char position (needed for generating error msg) */
1545 SKIP_SPACE (bp, "unexpected end of rule\n");
1546 getPeepLine (&replace, &bp);
1548 /* look for a 'if' */
1549 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1552 if (strncmp (bp, "if", 2) == 0)
1555 while ((ISCHARSPACE (*bp) || *bp == '\n') && *bp)
1559 fprintf (stderr, "expected condition name\n");
1563 /* look for the condition */
1565 while (*bp && (*bp != '\n'))
1571 newPeepRule (match, replace, lines, restart);
1575 if (*bp && strncmp (bp, "replace", 7))
1577 /* not the start of a new peeprule, so "if" should be here */
1582 /* go to the start of the line following "{" of the "by" token */
1583 while (*rp && (*rp == '\n'))
1586 /* copy text of rule starting with line after "by {" */
1588 while (*rp && (rp < bp) && ((cp - strbuff) < sizeof(strbuff)))
1591 /* and now the rest of the line */
1592 while (*rp && (*rp != '\n') && ((cp - strbuff) < sizeof(strbuff)))
1596 fprintf (stderr, "%s\nexpected '} if ...'\n", strbuff);
1599 newPeepRule (match, replace, NULL, restart);
1605 /*-----------------------------------------------------------------*/
1606 /* keyForVar - returns the numeric key for a var */
1607 /*-----------------------------------------------------------------*/
1613 while (ISCHARDIGIT (*d))
1622 /*-----------------------------------------------------------------*/
1623 /* bindVar - binds a value to a variable in the given hashtable */
1624 /*-----------------------------------------------------------------*/
1626 bindVar (int key, char **s, hTab ** vtab)
1628 char vval[MAX_PATTERN_LEN];
1632 /* first get the value of the variable */
1634 /* the value is ended by a ',' or space or newline or null or ) */
1637 !ISCHARSPACE (*vvx) &&
1643 /* if we find a '(' then we need to balance it */
1655 // include the trailing ')'
1664 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1666 hTabAddItem (vtab, key, vvx);
1669 /*-----------------------------------------------------------------*/
1670 /* matchLine - matches one line */
1671 /*-----------------------------------------------------------------*/
1673 matchLine (char *s, char *d, hTab ** vars)
1682 /* skip white space in both */
1683 while (ISCHARSPACE (*s))
1685 while (ISCHARSPACE (*d))
1688 /* if the destination is a var */
1689 if (*d == '%' && ISCHARDIGIT (*(d + 1)) && vars)
1691 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1692 /* if the variable is already bound
1693 then it MUST match with dest */
1701 /* variable not bound we need to bind it */
1702 bindVar (keyForVar (d + 1), &s, vars);
1704 /* in either case go past the variable */
1706 while (ISCHARDIGIT (*d))
1709 while (ISCHARSPACE (*s))
1711 while (ISCHARSPACE (*d))
1715 /* they should be an exact match other wise */
1724 /* get rid of the trailing spaces
1725 in both source & destination */
1727 while (ISCHARSPACE (*s))
1731 while (ISCHARSPACE (*d))
1734 /* after all this if only one of them
1735 has something left over then no match */
1742 /*-----------------------------------------------------------------*/
1743 /* matchRule - matches a all the rule lines */
1744 /*-----------------------------------------------------------------*/
1746 matchRule (lineNode * pl,
1751 lineNode *spl; /* source pl */
1752 lineNode *rpl; /* rule peep line */
1754 /* setToNull((void *) &pr->vars); */
1755 /* pr->vars = newHashTable(100); */
1757 /* for all the lines defined in the rule */
1763 /* if the source line starts with a ';' then
1764 comment line don't process or the source line
1765 contains == . debugger information skip it */
1767 (*spl->line == ';' || spl->isDebug))
1773 if (!matchLine (spl->line, rpl->line, &pr->vars))
1781 /* if rules ended */
1784 /* if this rule has additional conditions */
1787 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1806 reassociate_ic_down (lineNode *shead, lineNode *stail,
1807 lineNode *rhead, lineNode *rtail)
1809 lineNode *csl; /* current source line */
1810 lineNode *crl; /* current replacement line */
1816 /* skip over any comments */
1817 while (csl!=stail->next && csl->isComment)
1819 while (crl!=rtail->next && crl->isComment)
1822 /* quit if we reach the end */
1823 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1826 if (matchLine(csl->line,crl->line,NULL))
1838 reassociate_ic_up (lineNode *shead, lineNode *stail,
1839 lineNode *rhead, lineNode *rtail)
1841 lineNode *csl; /* current source line */
1842 lineNode *crl; /* current replacement line */
1848 /* skip over any comments */
1849 while (csl!=shead->prev && csl->isComment)
1851 while (crl!=rhead->prev && crl->isComment)
1854 /* quit if we reach the end */
1855 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1858 if (matchLine(csl->line,crl->line,NULL))
1869 /*------------------------------------------------------------------*/
1870 /* reassociate_ic - reassociate replacement lines with origin iCode */
1871 /*------------------------------------------------------------------*/
1873 reassociate_ic (lineNode *shead, lineNode *stail,
1874 lineNode *rhead, lineNode *rtail)
1876 lineNode *csl; /* current source line */
1877 lineNode *crl; /* current replacement line */
1881 /* Check to see if all the source lines (excluding comments) came
1882 ** for the same iCode
1885 for (csl=shead;csl!=stail->next;csl=csl->next)
1886 if (csl->ic && !csl->isComment)
1891 single_iCode = (ic!=NULL);
1892 for (csl=shead;csl!=stail->next;csl=csl->next)
1893 if ((csl->ic != ic) && !csl->isComment)
1895 /* More than one iCode was found. However, if it's just the
1896 ** last line with the different iCode and it was not changed
1897 ** in the replacement, everything else must be the first iCode.
1899 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1901 rtail->ic = stail->ic;
1902 for (crl=rhead;crl!=rtail;crl=crl->next)
1907 single_iCode = FALSE;
1911 /* If all of the source lines came from the same iCode, then so have
1912 ** all of the replacement lines too.
1916 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1921 /* The source lines span iCodes, so we may end up with replacement
1922 ** lines that we don't know which iCode(s) to associate with. Do the
1923 ** best we can by using the following strategies:
1924 ** 1) Start at the top and scan down. As long as the source line
1925 ** matches the replacement line, they have the same iCode.
1926 ** 2) Start at the bottom and scan up. As long as the source line
1927 ** matches the replacement line, they have the same iCode.
1928 ** 3) For any label in the source, look for a matching label in
1929 ** the replacment. If found, they have the same iCode. From
1930 ** these matching labels, scan down for additional matching
1931 ** lines; if found, they also have the same iCode.
1934 /* Strategy #1: Start at the top and scan down for matches
1936 reassociate_ic_down(shead,stail,rhead,rtail);
1938 /* Strategy #2: Start at the bottom and scan up for matches
1940 reassociate_ic_up(shead,stail,rhead,rtail);
1942 /* Strategy #3: Try to match labels
1947 /* skip over any comments */
1948 while (csl!=stail->next && csl->isComment)
1950 if (csl==stail->next)
1955 /* found a source line label; look for it in the replacment lines */
1959 while (crl!=rtail->next && crl->isComment)
1961 if (crl==rtail->next)
1963 if (matchLine(csl->line, crl->line, NULL))
1965 reassociate_ic_down(csl,stail,crl,rtail);
1975 /* Try to assign a meaningful iCode to any comment that is missing
1976 one. Since they are comments, it's ok to make mistakes; we are just
1977 trying to improve continuity to simplify other tests.
1980 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1982 if (!crl->ic && ic && crl->isComment)
1989 /*-----------------------------------------------------------------*/
1990 /* replaceRule - does replacement of a matching pattern */
1991 /*-----------------------------------------------------------------*/
1993 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1995 lineNode *cl = NULL;
1996 lineNode *pl = NULL, *lhead = NULL;
1997 /* a long function name and long variable name can evaluate to
1998 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1999 char lb[MAX_PATTERN_LEN*4];
2001 lineNode *comment = NULL;
2003 /* collect all the comment lines in the source */
2004 for (cl = *shead; cl != stail; cl = cl->next)
2006 if (cl->line && (*cl->line == ';' || cl->isDebug))
2008 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
2009 (comment = newLineNode (cl->line)));
2010 pl->isDebug = cl->isDebug;
2011 pl->isComment = cl->isComment || (*cl->line == ';');
2016 /* for all the lines in the replacement pattern do */
2017 for (pl = pr->replace; pl; pl = pl->next)
2027 /* if the line contains a variable */
2028 if (*l == '%' && ISCHARDIGIT (*(l + 1)))
2030 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
2033 fprintf (stderr, "used unbound variable in replacement\n");
2041 while (ISCHARDIGIT (*l)) {
2051 cl = connectLine (cl, newLineNode (lb));
2053 lhead = cl = newLineNode (lb);
2054 cl->isComment = pl->isComment;
2055 cl->isLabel = pl->isLabel;
2058 /* add the comments if any to the head of list */
2061 lineNode *lc = comment;
2072 /* determine which iCodes the replacment lines relate to */
2073 reassociate_ic(*shead,stail,lhead,cl);
2075 /* now we need to connect / replace the original chain */
2076 /* if there is a prev then change it */
2079 (*shead)->prev->next = lhead;
2080 lhead->prev = (*shead)->prev;
2083 /* now for the tail */
2084 if (stail && stail->next)
2086 stail->next->prev = cl;
2088 cl->next = stail->next;
2093 /* the replacement is empty - delete the source lines */
2095 (*shead)->prev->next = stail->next;
2097 stail->next->prev = (*shead)->prev;
2098 *shead = stail->next;
2102 /* Returns TRUE if this line is a label definition.
2104 * If so, start will point to the start of the label name,
2105 * and len will be it's length.
2108 isLabelDefinition (const char *line, const char **start, int *len,
2111 const char *cp = line;
2113 /* This line is a label if if consists of:
2114 * [optional whitespace] followed by identifier chars
2115 * (alnum | $ | _ ) followed by a colon.
2118 while (*cp && ISCHARSPACE (*cp))
2130 while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
2131 (isPeepRule && (*cp == '%')))
2136 if ((cp == *start) || (*cp != ':'))
2141 *len = (cp - (*start));
2145 /* Quick & dirty string hash function. */
2147 hashSymbolName (const char *name)
2153 hash = (hash << 6) ^ *name;
2162 return hash % HTAB_SIZE;
2165 /* Build a hash of all labels in the passed set of lines
2166 * and how many times they are referenced.
2169 buildLabelRefCountHash (lineNode * head)
2176 assert (labelHash == NULL);
2177 labelHash = newHashTable (HTAB_SIZE);
2179 /* First pass: locate all the labels. */
2180 for (line = head; line; line = line->next)
2182 if (line->isLabel ||
2185 /* run isLabelDefinition to:
2186 - look for labels in inline assembler
2187 - calculate labelLen
2189 if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
2190 labelLen <= SDCC_NAME_MAX)
2192 labelHashEntry *entry;
2194 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
2196 memcpy (entry->name, label, labelLen);
2197 entry->name[labelLen] = 0;
2198 entry->refCount = -1;
2200 /* Assume function entry points are referenced somewhere, */
2201 /* even if we can't find a reference (might be from outside */
2203 if (line->ic && (line->ic->op == FUNCTION))
2206 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2212 /* Second pass: for each line, note all the referenced labels. */
2213 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2217 for (i = 0; i < HTAB_SIZE; i++)
2219 labelHashEntry *thisEntry;
2221 thisEntry = hTabFirstItemWK (labelHash, i);
2225 if (strstr (line->line, thisEntry->name))
2227 thisEntry->refCount++;
2229 thisEntry = hTabNextItemWK (labelHash);
2236 /* Spew the contents of the table. Debugging fun only. */
2237 for (i = 0; i < HTAB_SIZE; i++)
2239 labelHashEntry *thisEntry;
2241 thisEntry = hTabFirstItemWK (labelHash, i);
2245 fprintf (stderr, "label: %s ref %d\n",
2246 thisEntry->name, thisEntry->refCount);
2247 thisEntry = hTabNextItemWK (labelHash);
2253 /* How does this work?
2259 replace and restart.
2264 Where is stuff allocated?
2268 /*-----------------------------------------------------------------*/
2269 /* peepHole - matches & substitutes rules */
2270 /*-----------------------------------------------------------------*/
2272 peepHole (lineNode ** pls)
2276 lineNode *mtail = NULL;
2277 bool restart, replaced;
2279 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2280 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2281 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2285 assert(labelHash == NULL);
2292 for (pr = rootRules; pr; pr = pr->next)
2294 for (spl = *pls; spl; spl = replaced ? spl : spl->next)
2298 /* if inline assembler then no peep hole */
2302 /* don't waste time starting a match on debug symbol
2304 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2309 /* Tidy up any data stored in the hTab */
2312 if (matchRule (spl, &mtail, pr, *pls))
2314 /* restart at the replaced line */
2320 replaceRule (pls, mtail, pr);
2324 replaceRule (&spl, mtail, pr);
2326 /* if restart rule type then
2327 start at the top again */
2336 hTabDeleteAll (pr->vars);
2337 Safe_free (pr->vars);
2341 freeTrace (&_G.values);
2344 } while (restart == TRUE);
2348 hTabDeleteAll (labelHash);
2349 freeTrace (&_G.labels);
2355 /*-----------------------------------------------------------------*/
2356 /* readFileIntoBuffer - reads a file into a string buffer */
2357 /*-----------------------------------------------------------------*/
2359 readFileIntoBuffer (char *fname)
2365 char lb[MAX_PATTERN_LEN];
2367 if (!(f = fopen (fname, "r")))
2369 fprintf (stderr, "cannot open peep rule file\n");
2373 while ((ch = fgetc (f)) != EOF)
2377 /* if we maxed out our local buffer */
2378 if (nch >= (MAX_PATTERN_LEN - 2))
2381 /* copy it into allocated buffer */
2384 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2385 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2389 rs = Safe_strdup (lb);
2395 /* if some charaters left over */
2399 /* copy it into allocated buffer */
2402 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2403 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2407 rs = Safe_strdup (lb);
2413 /*-----------------------------------------------------------------*/
2414 /* initPeepHole - initialises the peep hole optimizer stuff */
2415 /*-----------------------------------------------------------------*/
2421 /* read in the default rules */
2422 if (!options.nopeep)
2424 readRules (port->peep.default_rules);
2427 /* if we have any additional file read it too */
2428 if (options.peep_file)
2430 readRules (s = readFileIntoBuffer (options.peep_file));
2431 setToNull ((void *) &s);
2432 /* override nopeep setting, default rules have not been read */
2437 #if !OPT_DISABLE_PIC
2438 /* Convert the peep rules into pcode.
2439 NOTE: this is only support in the PIC port (at the moment)
2442 peepRules2pCode(rootRules);
2445 #if !OPT_DISABLE_PIC16
2446 /* Convert the peep rules into pcode.
2447 NOTE: this is only support in the PIC port (at the moment)
2448 and the PIC16 port (VR 030601)
2450 if (TARGET_IS_PIC16)
2451 pic16_peepRules2pCode(rootRules);