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 -------------------------------------------------------------------------*/
28 static peepRule *rootRules = NULL;
29 static peepRule *currRule = NULL;
34 char name[SDCC_NAME_MAX + 1];
39 static hTab *labelHash = NULL;
47 static int hashSymbolName (const char *name);
48 static void buildLabelRefCountHash (lineNode * head);
50 static bool matchLine (char *, char *, hTab **);
51 bool isLabelDefinition (const char *line, const char **start, int *len);
53 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
54 lineNode *head, char *cmdLine)
57 void peepRules2pCode(peepRule *);
60 #if !OPT_DISABLE_PIC16
61 void pic16_peepRules2pCode(peepRule *);
64 /*-----------------------------------------------------------------*/
65 /* pcDistance - afinds a label back ward or forward */
66 /*-----------------------------------------------------------------*/
69 pcDistance (lineNode * cpos, char *lbl, bool back)
72 char buff[MAX_PATTERN_LEN];
75 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
81 pl->line[strlen (pl->line) - 1] != ':' &&
83 if (port->peep.getSize) {
84 dist += port->peep.getSize(pl);
90 if (strncmp (pl->line, buff, strlen (buff)) == 0)
102 /*-----------------------------------------------------------------*/
103 /* flat24bitModeAndPortDS390 - */
104 /*-----------------------------------------------------------------*/
105 FBYNAME (flat24bitModeAndPortDS390)
107 return (((strcmp(port->target,"ds390") == 0) ||
108 (strcmp(port->target,"ds400") == 0)) &&
109 (options.model == MODEL_FLAT24));
112 /*-----------------------------------------------------------------*/
113 /* portIsDS390 - return true if port is DS390 */
114 /*-----------------------------------------------------------------*/
115 FBYNAME (portIsDS390)
117 return ((strcmp(port->target,"ds390") == 0) ||
118 (strcmp(port->target,"ds400") == 0));
121 /*-----------------------------------------------------------------*/
122 /* flat24bitMode - will check to see if we are in flat24 mode */
123 /*-----------------------------------------------------------------*/
124 FBYNAME (flat24bitMode)
126 return (options.model == MODEL_FLAT24);
129 /*-----------------------------------------------------------------*/
130 /* xramMovcOption - check if using movc to read xram */
131 /*-----------------------------------------------------------------*/
132 FBYNAME (xramMovcOption)
134 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
142 /*-----------------------------------------------------------------*/
143 /* labelInRange - will check to see if label %5 is within range */
144 /*-----------------------------------------------------------------*/
145 FBYNAME (labelInRange)
147 /* assumes that %5 pattern variable has the label name */
148 char *lbl = hTabItemWithKey (vars, 5);
154 /* Don't optimize jumps in a jump table; a more generic test */
155 if (currPl->ic && currPl->ic->op == JUMPTABLE)
158 /* if the previous two instructions are "ljmp"s then don't
159 do it since it can be part of a jump table */
160 if (currPl->prev && currPl->prev->prev &&
161 strstr (currPl->prev->line, "ljmp") &&
162 strstr (currPl->prev->prev->line, "ljmp"))
165 /* calculate the label distance : the jump for reladdr can be
166 +/- 127 bytes, here Iam assuming that an average 8051
167 instruction is 2 bytes long, so if the label is more than
168 63 intructions away, the label is considered out of range
169 for a relative jump. we could get more precise this will
170 suffice for now since it catches > 90% cases */
171 dist = (pcDistance (currPl, lbl, TRUE) +
172 pcDistance (currPl, lbl, FALSE));
174 /* changed to 127, now that pcDistance return actual number of bytes */
175 if (!dist || dist > 127)
182 /*-----------------------------------------------------------------*/
183 /* labelJTInRange - will check to see if label %5 and up are */
185 /* Specifically meant to optimize long (3-byte) jumps to short */
186 /* (2-byte) jumps in jumptables */
187 /*-----------------------------------------------------------------*/
188 FBYNAME (labelJTInRange)
193 if (!getenv("SDCC_SJMP_JUMPTABLE"))
196 /* Only optimize within a jump table */
197 if (currPl->ic && currPl->ic->op != JUMPTABLE)
200 count = elementsInSet( IC_JTLABELS (currPl->ic) );
202 /* check all labels (this is needed if the case statements are unsorted) */
203 for (i=0; i<count; i++)
205 /* assumes that the %5 pattern variable has the first ljmp label */
206 lbl = hTabItemWithKey (vars, 5+i);
210 dist = pcDistance (currPl, lbl, FALSE);
212 /* three terms used to calculate allowable distance */
213 // 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);
215 dist > 127+ /* range of sjmp */
216 (7+3*i)+ /* offset between this jump and currPl,
217 should use pcDistance instead? */
218 (count-i-1) /* if peephole applies distance is shortened */
226 /*-----------------------------------------------------------------*/
227 /* labelIsReturnOnly - Check if label %5 is followed by RET */
228 /*-----------------------------------------------------------------*/
229 FBYNAME (labelIsReturnOnly)
231 /* assumes that %5 pattern variable has the label name */
232 const char *label, *p;
237 label = hTabItemWithKey (vars, 5);
238 if (!label) return FALSE;
241 for(pl = currPl; pl; pl = pl->next) {
242 if (pl->line && !pl->isDebug && !pl->isComment &&
243 pl->line[strlen(pl->line)-1] == ':') {
244 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
245 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
246 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
247 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
248 *(pl->line+5) != '$') {
249 return FALSE; /* non-local label encountered */
253 if (!pl) return FALSE; /* did not find the label */
255 while (pl && (pl->isDebug || pl->isComment))
257 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
259 for (p = pl->line; *p && isspace(*p); p++)
265 if (strcmp(p, retInst) == 0) return TRUE;
270 /*-----------------------------------------------------------------*/
271 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
272 /* usage of it in the code depends on a value from this section */
273 /*-----------------------------------------------------------------*/
274 FBYNAME (okToRemoveSLOC)
277 const char *sloc, *p;
278 int dummy1, dummy2, dummy3;
280 /* assumes that %1 as the SLOC name */
281 sloc = hTabItemWithKey (vars, 1);
282 if (sloc == NULL) return FALSE;
283 p = strstr(sloc, "sloc");
284 if (p == NULL) return FALSE;
286 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
287 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
288 /* the sloc name begins with that. Probably not really necessary */
290 /* Look for any occurance of this SLOC before the peephole match */
291 for (pl = currPl->prev; pl; pl = pl->prev) {
292 if (pl->line && !pl->isDebug && !pl->isComment
293 && *pl->line != ';' && strstr(pl->line, sloc))
296 /* Look for any occurance of this SLOC after the peephole match */
297 for (pl = endPl->next; pl; pl = pl->next) {
298 if (pl->line && !pl->isDebug && !pl->isComment
299 && *pl->line != ';' && strstr(pl->line, sloc))
302 return TRUE; /* safe for a peephole to remove it :) */
306 /*-----------------------------------------------------------------*/
307 /* operandsNotSame - check if %1 & %2 are the same */
308 /*-----------------------------------------------------------------*/
309 FBYNAME (operandsNotSame)
311 char *op1 = hTabItemWithKey (vars, 1);
312 char *op2 = hTabItemWithKey (vars, 2);
314 if (strcmp (op1, op2) == 0)
320 /*-----------------------------------------------------------------*/
321 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
322 /*-----------------------------------------------------------------*/
323 FBYNAME (operandsNotSame3)
325 char *op1 = hTabItemWithKey (vars, 1);
326 char *op2 = hTabItemWithKey (vars, 2);
327 char *op3 = hTabItemWithKey (vars, 3);
329 if ( (strcmp (op1, op2) == 0) ||
330 (strcmp (op1, op3) == 0) ||
331 (strcmp (op2, op3) == 0) )
337 /*-----------------------------------------------------------------*/
338 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
339 /*-----------------------------------------------------------------*/
340 FBYNAME (operandsNotSame4)
342 char *op1 = hTabItemWithKey (vars, 1);
343 char *op2 = hTabItemWithKey (vars, 2);
344 char *op3 = hTabItemWithKey (vars, 3);
345 char *op4 = hTabItemWithKey (vars, 4);
347 if ( (strcmp (op1, op2) == 0) ||
348 (strcmp (op1, op3) == 0) ||
349 (strcmp (op1, op4) == 0) ||
350 (strcmp (op2, op3) == 0) ||
351 (strcmp (op2, op4) == 0) ||
352 (strcmp (op3, op4) == 0) )
358 /*-----------------------------------------------------------------*/
359 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
360 /*-----------------------------------------------------------------*/
361 FBYNAME (operandsNotSame5)
363 char *op1 = hTabItemWithKey (vars, 1);
364 char *op2 = hTabItemWithKey (vars, 2);
365 char *op3 = hTabItemWithKey (vars, 3);
366 char *op4 = hTabItemWithKey (vars, 4);
367 char *op5 = hTabItemWithKey (vars, 5);
369 if ( (strcmp (op1, op2) == 0) ||
370 (strcmp (op1, op3) == 0) ||
371 (strcmp (op1, op4) == 0) ||
372 (strcmp (op1, op5) == 0) ||
373 (strcmp (op2, op3) == 0) ||
374 (strcmp (op2, op4) == 0) ||
375 (strcmp (op2, op5) == 0) ||
376 (strcmp (op3, op4) == 0) ||
377 (strcmp (op3, op5) == 0) ||
378 (strcmp (op4, op5) == 0) )
384 /*-----------------------------------------------------------------*/
385 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
386 /*-----------------------------------------------------------------*/
387 FBYNAME (operandsNotSame6)
389 char *op1 = hTabItemWithKey (vars, 1);
390 char *op2 = hTabItemWithKey (vars, 2);
391 char *op3 = hTabItemWithKey (vars, 3);
392 char *op4 = hTabItemWithKey (vars, 4);
393 char *op5 = hTabItemWithKey (vars, 5);
394 char *op6 = hTabItemWithKey (vars, 6);
396 if ( (strcmp (op1, op2) == 0) ||
397 (strcmp (op1, op3) == 0) ||
398 (strcmp (op1, op4) == 0) ||
399 (strcmp (op1, op5) == 0) ||
400 (strcmp (op1, op6) == 0) ||
401 (strcmp (op2, op3) == 0) ||
402 (strcmp (op2, op4) == 0) ||
403 (strcmp (op2, op5) == 0) ||
404 (strcmp (op2, op6) == 0) ||
405 (strcmp (op3, op4) == 0) ||
406 (strcmp (op3, op5) == 0) ||
407 (strcmp (op3, op6) == 0) ||
408 (strcmp (op4, op5) == 0) ||
409 (strcmp (op4, op6) == 0) ||
410 (strcmp (op5, op6) == 0) )
417 /*-----------------------------------------------------------------*/
418 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
419 /*-----------------------------------------------------------------*/
420 FBYNAME (operandsNotSame7)
422 char *op1 = hTabItemWithKey (vars, 1);
423 char *op2 = hTabItemWithKey (vars, 2);
424 char *op3 = hTabItemWithKey (vars, 3);
425 char *op4 = hTabItemWithKey (vars, 4);
426 char *op5 = hTabItemWithKey (vars, 5);
427 char *op6 = hTabItemWithKey (vars, 6);
428 char *op7 = hTabItemWithKey (vars, 7);
430 if ( (strcmp (op1, op2) == 0) ||
431 (strcmp (op1, op3) == 0) ||
432 (strcmp (op1, op4) == 0) ||
433 (strcmp (op1, op5) == 0) ||
434 (strcmp (op1, op6) == 0) ||
435 (strcmp (op1, op7) == 0) ||
436 (strcmp (op2, op3) == 0) ||
437 (strcmp (op2, op4) == 0) ||
438 (strcmp (op2, op5) == 0) ||
439 (strcmp (op2, op6) == 0) ||
440 (strcmp (op2, op7) == 0) ||
441 (strcmp (op3, op4) == 0) ||
442 (strcmp (op3, op5) == 0) ||
443 (strcmp (op3, op6) == 0) ||
444 (strcmp (op3, op7) == 0) ||
445 (strcmp (op4, op5) == 0) ||
446 (strcmp (op4, op6) == 0) ||
447 (strcmp (op4, op7) == 0) ||
448 (strcmp (op5, op6) == 0) ||
449 (strcmp (op5, op7) == 0) ||
450 (strcmp (op6, op7) == 0) )
456 /*-----------------------------------------------------------------*/
457 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
458 /*-----------------------------------------------------------------*/
459 FBYNAME (operandsNotSame8)
461 char *op1 = hTabItemWithKey (vars, 1);
462 char *op2 = hTabItemWithKey (vars, 2);
463 char *op3 = hTabItemWithKey (vars, 3);
464 char *op4 = hTabItemWithKey (vars, 4);
465 char *op5 = hTabItemWithKey (vars, 5);
466 char *op6 = hTabItemWithKey (vars, 6);
467 char *op7 = hTabItemWithKey (vars, 7);
468 char *op8 = hTabItemWithKey (vars, 8);
470 if ( (strcmp (op1, op2) == 0) ||
471 (strcmp (op1, op3) == 0) ||
472 (strcmp (op1, op4) == 0) ||
473 (strcmp (op1, op5) == 0) ||
474 (strcmp (op1, op6) == 0) ||
475 (strcmp (op1, op7) == 0) ||
476 (strcmp (op1, op8) == 0) ||
477 (strcmp (op2, op3) == 0) ||
478 (strcmp (op2, op4) == 0) ||
479 (strcmp (op2, op5) == 0) ||
480 (strcmp (op2, op6) == 0) ||
481 (strcmp (op2, op7) == 0) ||
482 (strcmp (op2, op8) == 0) ||
483 (strcmp (op3, op4) == 0) ||
484 (strcmp (op3, op5) == 0) ||
485 (strcmp (op3, op6) == 0) ||
486 (strcmp (op3, op7) == 0) ||
487 (strcmp (op3, op8) == 0) ||
488 (strcmp (op4, op5) == 0) ||
489 (strcmp (op4, op6) == 0) ||
490 (strcmp (op4, op7) == 0) ||
491 (strcmp (op4, op8) == 0) ||
492 (strcmp (op5, op6) == 0) ||
493 (strcmp (op5, op7) == 0) ||
494 (strcmp (op5, op8) == 0) ||
495 (strcmp (op6, op7) == 0) ||
496 (strcmp (op6, op8) == 0) ||
497 (strcmp (op7, op8) == 0) )
506 * takes two parameters: a variable (bound to a label name)
507 * and an expected reference count.
509 * Returns TRUE if that label is defined and referenced exactly
510 * the given number of times.
512 FBYNAME (labelRefCount)
514 int varNumber, expectedRefCount;
517 /* If we don't have the label hash table yet, build it. */
520 buildLabelRefCountHash (head);
523 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
525 char *label = hTabItemWithKey (vars, varNumber);
529 labelHashEntry *entry;
531 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
535 if (!strcmp (label, entry->name))
539 entry = hTabNextItemWK (labelHash);
545 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
546 label, entry->refCount, expectedRefCount);
549 rc = (expectedRefCount == entry->refCount);
553 fprintf (stderr, "*** internal error: no label has entry for"
554 " %s in labelRefCount peephole.\n",
560 fprintf (stderr, "*** internal error: var %d not bound"
561 " in peephole labelRefCount rule.\n",
569 "*** internal error: labelRefCount peephole restriction"
570 " malformed: %s\n", cmdLine);
576 /* labelRefCountChange:
577 * takes two parameters: a variable (bound to a label name)
578 * and a signed int for changing the reference count.
580 * Please note, this function is not a conditional. It unconditionally
581 * changes the label. It should be passed as the 'last' function
582 * so it only is applied if all other conditions have been met.
584 * should always return TRUE
586 FBYNAME (labelRefCountChange)
588 int varNumber, RefCountDelta;
591 /* If we don't have the label hash table yet, build it. */
594 buildLabelRefCountHash (head);
597 if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 2)
599 char *label = hTabItemWithKey (vars, varNumber);
603 labelHashEntry *entry;
605 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
609 if (!strcmp (label, entry->name))
613 entry = hTabNextItemWK (labelHash);
617 if (0 <= entry->refCount + RefCountDelta)
619 entry->refCount += RefCountDelta;
624 fprintf (stderr, "*** internal error: label %s may not get"
625 " negative refCount in %s peephole.\n",
626 label, __FUNCTION__);
631 fprintf (stderr, "*** internal error: no label has entry for"
632 " %s in %s peephole.\n",
633 label, __FUNCTION__);
638 fprintf (stderr, "*** internal error: var %d not bound"
639 " in peephole %s rule.\n",
640 varNumber, __FUNCTION__);
646 "*** internal error: labelRefCount peephole restriction"
647 " malformed: %s\n", cmdLine);
653 /* Within the context of the lines currPl through endPl, determine
654 ** if the variable var contains a symbol that is volatile. Returns
655 ** TRUE only if it is certain that this was not volatile (the symbol
656 ** was found and not volatile, or var was a constant or CPU register).
657 ** Returns FALSE if the symbol was found and volatile, the symbol was
658 ** not found, or var was a indirect/pointer addressing mode.
661 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
663 char symname[SDCC_NAME_MAX + 1];
670 /* Can't tell if indirect accesses are volatile or not, so
671 ** assume they are, just to be safe.
673 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
678 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
680 if (strstr(var,"(bc)"))
682 if (strstr(var,"(de)"))
684 if (strstr(var,"(hl)"))
686 if (strstr(var,"(ix"))
688 if (strstr(var,"(iy"))
692 /* Extract a symbol name from the variable */
693 while (*vp && (*vp!='_'))
695 while (*vp && (isalnum(*vp) || *vp=='_'))
701 /* Nothing resembling a symbol name was found, so it can't
708 for (cl = currPl; cl!=endPl->next; cl = cl->next)
710 if (cl->ic && (cl->ic!=last_ic))
716 op = IC_COND (cl->ic);
717 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
718 return !op->isvolatile;
720 op = IC_JTCOND (cl->ic);
721 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
722 return !op->isvolatile;
724 op = IC_LEFT (cl->ic);
725 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
726 return !op->isvolatile;
727 op = IC_RIGHT (cl->ic);
728 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
729 return !op->isvolatile;
730 op = IC_RESULT (cl->ic);
731 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
732 return !op->isvolatile;
737 /* Couldn't find the symbol for some reason. Assume volatile. */
743 * This rule restriction has two different behaviours depending on
744 * the number of parameters given.
746 * if notVolatile (no parameters given)
747 * The rule is applied only if none of the iCodes originating
748 * the matched pattern reference a volatile operand.
750 * if notVolatile %1 ... (one or more parameters given)
751 * The rule is applied if the parameters are not expressions
752 * containing volatile symbols and are not pointer accesses.
755 FBYNAME (notVolatile)
766 /* If no parameters given, just scan the iCodes for volatile operands */
767 for (cl = currPl; cl!=endPl->next; cl = cl->next)
774 op = IC_COND (cl->ic);
775 if (IS_SYMOP (op) && op->isvolatile)
778 op = IC_JTCOND (cl->ic);
779 if (IS_SYMOP (op) && op->isvolatile)
782 op = IC_LEFT (cl->ic);
783 if (IS_SYMOP (op) && op->isvolatile)
785 op = IC_RIGHT (cl->ic);
786 if (IS_SYMOP (op) && op->isvolatile)
788 op = IC_RESULT (cl->ic);
789 if (IS_SYMOP (op) && op->isvolatile)
797 /* There were parameters; check the volatility of each */
798 while (*cmdLine && isspace(*cmdLine))
805 if (!isdigit(*cmdLine))
807 varNumber = strtol(cmdLine, &digitend, 10);
809 while (*cmdLine && isspace(*cmdLine))
812 var = hTabItemWithKey (vars, varNumber);
816 notvol = notVolatileVariable (var, currPl, endPl);
822 fprintf (stderr, "*** internal error: var %d not bound"
823 " in peephole notVolatile rule.\n",
834 "*** internal error: notVolatile peephole restriction"
835 " malformed: %s\n", cmdLine);
840 /*------------------------------------------------------------------*/
841 /* setFromConditionArgs - parse a peephole condition's arguments */
842 /* to produce a set of strings, one per argument. Variables %x will */
843 /* be replaced with their values. String literals (in single quotes)*/
844 /* are accepted and return in unquoted form. */
845 /*------------------------------------------------------------------*/
847 setFromConditionArgs (char *cmdLine, hTab * vars)
852 set *operands = NULL;
857 while (*cmdLine && isspace(*cmdLine))
865 if (!isdigit(*cmdLine))
867 varNumber = strtol(cmdLine, &digitend, 10);
870 var = hTabItemWithKey (vars, varNumber);
874 addSetHead (&operands, var);
879 else if (*cmdLine == '\'' )
881 char quote = *cmdLine;
884 while (*cmdLine && *cmdLine != quote)
886 if (*cmdLine == quote)
890 addSetHead (&operands, var);
895 while (*cmdLine && isspace(*cmdLine))
902 deleteSet (&operands);
907 operandBaseName (const char *op)
909 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
911 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
913 if (!strncmp (op, "ar", 2) && isdigit(*(op+2)) && !*(op+3))
921 /*-------------------------------------------------------------------*/
922 /* operandsNotRelated - returns true of the condition's operands are */
923 /* not related (taking into account register name aliases). N-way */
924 /* comparison performed between all operands. */
925 /*-------------------------------------------------------------------*/
926 FBYNAME (operandsNotRelated)
929 const char *op1, *op2;
931 operands = setFromConditionArgs (cmdLine, vars);
936 "*** internal error: operandsNotRelated peephole restriction"
937 " malformed: %s\n", cmdLine);
941 while ((op1 = setFirstItem (operands)))
943 deleteSetItem (&operands, (void*)op1);
944 op1 = operandBaseName (op1);
946 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
948 op2 = operandBaseName (op2);
949 if (strcmp (op1, op2) == 0)
951 deleteSet (&operands);
957 deleteSet (&operands);
962 /*-----------------------------------------------------------------*/
963 /* callFuncByName - calls a function as defined in the table */
964 /*-----------------------------------------------------------------*/
966 callFuncByName (char *fname,
975 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
980 "labelInRange", labelInRange
984 "labelJTInRange", labelJTInRange
988 "operandsNotSame", operandsNotSame
992 "operandsNotSame3", operandsNotSame3
996 "operandsNotSame4", operandsNotSame4
1000 "operandsNotSame5", operandsNotSame5
1004 "operandsNotSame6", operandsNotSame6
1008 "operandsNotSame7", operandsNotSame7
1012 "operandsNotSame8", operandsNotSame8
1016 "24bitMode", flat24bitMode
1020 "xramMovcOption", xramMovcOption
1024 "labelRefCount", labelRefCount
1028 "portIsDS390", portIsDS390
1031 "labelIsReturnOnly", labelIsReturnOnly
1034 "okToRemoveSLOC", okToRemoveSLOC
1037 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
1040 "notVolatile", notVolatile
1043 "operandsNotRelated", operandsNotRelated
1046 "labelRefCountChange", labelRefCountChange
1050 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
1054 /* Isolate the function name part (we are passed the full condition
1055 * string including arguments)
1057 cmdTerm = cmdCopy = Safe_strdup(fname);
1061 funcArgs = funcName = cmdTerm;
1062 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
1064 *funcArgs = '\0'; /* terminate the function name */
1068 /* Find the start of the arguments */
1069 if (c == ' ' || c == '\t')
1070 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
1073 /* If the arguments started with an opening parenthesis, */
1074 /* use the closing parenthesis for the end of the */
1075 /* arguments and look for the start of another condition */
1076 /* that can optionally follow. If there was no opening */
1077 /* parethesis, then everything that follows are arguments */
1078 /* and there can be no additional conditions. */
1082 while ((c = *cmdTerm) && c != ')')
1084 *cmdTerm = '\0'; /* terminate the arguments */
1088 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1094 cmdTerm = NULL; /* closing parenthesis missing */
1103 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1105 if (strcmp (ftab[i].fname, funcName) == 0)
1107 rc = (*ftab[i].func) (vars, currPl, endPl, head,
1116 "could not find named function \"%s\" in "
1117 "peephole function table\n",
1119 // If the function couldn't be found, let's assume it's
1120 // a bad rule and refuse it.
1125 while (rc && cmdTerm);
1132 /*-----------------------------------------------------------------*/
1133 /* printLine - prints a line chain into a given file */
1134 /*-----------------------------------------------------------------*/
1136 printLine (lineNode * head, FILE * of)
1138 iCode *last_ic = NULL;
1139 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1146 if (head->ic!=last_ic)
1149 if (debug_iCode_tracking)
1152 fprintf (of, "; block = %d, seq = %d\n",
1153 head->ic->block, head->ic->seq);
1155 fprintf (of, "; iCode lost\n");
1159 /* don't indent comments & labels */
1161 (*head->line == ';' ||
1162 head->line[strlen (head->line) - 1] == ':')) {
1163 fprintf (of, "%s\n", head->line);
1165 if (head->isInline && *head->line=='#') {
1166 // comment out preprocessor directives in inline asm
1169 fprintf (of, "\t%s\n", head->line);
1175 /*-----------------------------------------------------------------*/
1176 /* newPeepRule - creates a new peeprule and attach it to the root */
1177 /*-----------------------------------------------------------------*/
1179 newPeepRule (lineNode * match,
1186 pr = Safe_alloc ( sizeof (peepRule));
1188 pr->replace = replace;
1189 pr->restart = restart;
1193 pr->cond = Safe_strdup (cond);
1198 pr->vars = newHashTable (100);
1200 /* if root is empty */
1202 rootRules = currRule = pr;
1204 currRule = currRule->next = pr;
1209 /*-----------------------------------------------------------------*/
1210 /* newLineNode - creates a new peep line */
1211 /*-----------------------------------------------------------------*/
1213 newLineNode (char *line)
1217 pl = Safe_alloc ( sizeof (lineNode));
1218 pl->line = Safe_strdup (line);
1223 /*-----------------------------------------------------------------*/
1224 /* connectLine - connects two lines */
1225 /*-----------------------------------------------------------------*/
1227 connectLine (lineNode * pl1, lineNode * pl2)
1231 fprintf (stderr, "trying to connect null line\n");
1241 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1242 if (!*x) { fprintf(stderr,y); return ; } }
1244 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1245 if (!*x) { fprintf(stderr,z); return ; } }
1246 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1247 if (!*x) { fprintf(stderr,z); return ; } }
1249 /*-----------------------------------------------------------------*/
1250 /* getPeepLine - parses the peep lines */
1251 /*-----------------------------------------------------------------*/
1253 getPeepLine (lineNode ** head, char **bpp)
1255 char lines[MAX_PATTERN_LEN];
1259 lineNode *currL = NULL;
1266 fprintf (stderr, "unexpected end of match pattern\n");
1273 while (isspace (*bp) ||
1284 /* read till end of line */
1286 while ((*bp != '\n' && *bp != '}') && *bp)
1291 while (*lp && isspace(*lp))
1293 isComment = (*lp == ';');
1295 if (!isComment || (isComment && !options.noPeepComments))
1298 *head = currL = newLineNode (lines);
1300 currL = connectLine (currL, newLineNode (lines));
1301 currL->isComment = isComment;
1309 /*-----------------------------------------------------------------*/
1310 /* readRules - reads the rules from a string buffer */
1311 /*-----------------------------------------------------------------*/
1313 readRules (char *bp)
1316 char lines[MAX_PATTERN_LEN];
1320 lineNode *currL = NULL;
1326 /* look for the token "replace" that is the
1328 while (*bp && strncmp (bp, "replace", 7))
1335 /* then look for either "restart" or '{' */
1336 while (strncmp (bp, "restart", 7) &&
1343 fprintf (stderr, "expected 'restart' or '{'\n");
1351 { /* must be restart */
1353 bp += strlen ("restart");
1355 EXPECT_CHR (bp, '{', "expected '{'\n");
1359 /* skip thru all the blank space */
1360 SKIP_SPACE (bp, "unexpected end of rule\n");
1362 match = replace = currL = NULL;
1363 /* we are the start of a rule */
1364 getPeepLine (&match, &bp);
1366 /* now look for by */
1367 EXPECT_STR (bp, "by", "expected 'by'\n");
1369 /* then look for a '{' */
1370 EXPECT_CHR (bp, '{', "expected '{'\n");
1373 SKIP_SPACE (bp, "unexpected end of rule\n");
1374 getPeepLine (&replace, &bp);
1376 /* look for a 'if' */
1377 while ((isspace (*bp) || *bp == '\n') && *bp)
1380 if (strncmp (bp, "if", 2) == 0)
1383 while ((isspace (*bp) || *bp == '\n') && *bp)
1387 fprintf (stderr, "expected condition name\n");
1391 /* look for the condition */
1393 while (*bp && (*bp != '\n'))
1399 newPeepRule (match, replace, lines, restart);
1402 newPeepRule (match, replace, NULL, restart);
1407 /*-----------------------------------------------------------------*/
1408 /* keyForVar - returns the numeric key for a var */
1409 /*-----------------------------------------------------------------*/
1415 while (isdigit (*d))
1424 /*-----------------------------------------------------------------*/
1425 /* bindVar - binds a value to a variable in the given hashtable */
1426 /*-----------------------------------------------------------------*/
1428 bindVar (int key, char **s, hTab ** vtab)
1430 char vval[MAX_PATTERN_LEN];
1434 /* first get the value of the variable */
1436 /* the value is ended by a ',' or space or newline or null or ) */
1445 /* if we find a '(' then we need to balance it */
1457 // include the trailing ')'
1466 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1468 hTabAddItem (vtab, key, vvx);
1471 /*-----------------------------------------------------------------*/
1472 /* matchLine - matches one line */
1473 /*-----------------------------------------------------------------*/
1475 matchLine (char *s, char *d, hTab ** vars)
1484 /* skip white space in both */
1485 while (isspace (*s))
1487 while (isspace (*d))
1490 /* if the destination is a var */
1491 if (*d == '%' && isdigit (*(d + 1)) && vars)
1493 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1494 /* if the variable is already bound
1495 then it MUST match with dest */
1503 /* variable not bound we need to
1505 bindVar (keyForVar (d + 1), &s, vars);
1507 /* in either case go past the variable */
1509 while (isdigit (*d))
1512 while (isspace (*s))
1514 while (isspace (*d))
1518 /* they should be an exact match other wise */
1527 /* get rid of the trailing spaces
1528 in both source & destination */
1530 while (isspace (*s))
1534 while (isspace (*d))
1537 /* after all this if only one of them
1538 has something left over then no match */
1545 /*-----------------------------------------------------------------*/
1546 /* matchRule - matches a all the rule lines */
1547 /*-----------------------------------------------------------------*/
1549 matchRule (lineNode * pl,
1554 lineNode *spl; /* source pl */
1555 lineNode *rpl; /* rule peep line */
1557 /* setToNull((void *) &pr->vars); */
1558 /* pr->vars = newHashTable(100); */
1560 /* for all the lines defined in the rule */
1566 /* if the source line starts with a ';' then
1567 comment line don't process or the source line
1568 contains == . debugger information skip it */
1570 (*spl->line == ';' || spl->isDebug))
1576 if (!matchLine (spl->line, rpl->line, &pr->vars))
1584 /* if rules ended */
1587 /* if this rule has additional conditions */
1590 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1609 reassociate_ic_down (lineNode *shead, lineNode *stail,
1610 lineNode *rhead, lineNode *rtail)
1612 lineNode *csl; /* current source line */
1613 lineNode *crl; /* current replacement line */
1619 /* skip over any comments */
1620 while (csl!=stail->next && csl->isComment)
1622 while (crl!=rtail->next && crl->isComment)
1625 /* quit if we reach the end */
1626 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1629 if (matchLine(csl->line,crl->line,NULL))
1641 reassociate_ic_up (lineNode *shead, lineNode *stail,
1642 lineNode *rhead, lineNode *rtail)
1644 lineNode *csl; /* current source line */
1645 lineNode *crl; /* current replacement line */
1651 /* skip over any comments */
1652 while (csl!=shead->prev && csl->isComment)
1654 while (crl!=rhead->prev && crl->isComment)
1657 /* quit if we reach the end */
1658 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1661 if (matchLine(csl->line,crl->line,NULL))
1672 /*------------------------------------------------------------------*/
1673 /* reassociate_ic - reassociate replacement lines with origin iCode */
1674 /*------------------------------------------------------------------*/
1676 reassociate_ic (lineNode *shead, lineNode *stail,
1677 lineNode *rhead, lineNode *rtail)
1679 lineNode *csl; /* current source line */
1680 lineNode *crl; /* current replacement line */
1684 /* Check to see if all the source lines (excluding comments) came
1685 ** for the same iCode
1688 for (csl=shead;csl!=stail->next;csl=csl->next)
1689 if (csl->ic && !csl->isComment)
1694 single_iCode = (ic!=NULL);
1695 for (csl=shead;csl!=stail->next;csl=csl->next)
1696 if ((csl->ic != ic) && !csl->isComment)
1698 /* More than one iCode was found. However, if it's just the
1699 ** last line with the different iCode and it was not changed
1700 ** in the replacement, everything else must be the first iCode.
1702 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1704 rtail->ic = stail->ic;
1705 for (crl=rhead;crl!=rtail;crl=crl->next)
1710 single_iCode = FALSE;
1714 /* If all of the source lines came from the same iCode, then so have
1715 ** all of the replacement lines too.
1719 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1724 /* The source lines span iCodes, so we may end up with replacement
1725 ** lines that we don't know which iCode(s) to associate with. Do the
1726 ** best we can by using the following strategies:
1727 ** 1) Start at the top and scan down. As long as the source line
1728 ** matches the replacement line, they have the same iCode.
1729 ** 2) Start at the bottom and scan up. As long as the source line
1730 ** matches the replacement line, they have the same iCode.
1731 ** 3) For any label in the source, look for a matching label in
1732 ** the replacment. If found, they have the same iCode. From
1733 ** these matching labels, scan down for additional matching
1734 ** lines; if found, they also have the same iCode.
1737 /* Strategy #1: Start at the top and scan down for matches
1739 reassociate_ic_down(shead,stail,rhead,rtail);
1741 /* Strategy #2: Start at the bottom and scan up for matches
1743 reassociate_ic_up(shead,stail,rhead,rtail);
1745 /* Strategy #3: Try to match labels
1750 const char *labelStart;
1753 /* skip over any comments */
1754 while (csl!=stail->next && csl->isComment)
1756 if (csl==stail->next)
1759 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1761 /* found a source line label; look for it in the replacment lines */
1765 while (crl!=rtail->next && crl->isComment)
1767 if (crl==rtail->next)
1769 if (matchLine(csl->line, crl->line, NULL))
1771 reassociate_ic_down(csl,stail,crl,rtail);
1781 /* Try to assign a meaningful iCode to any comment that is missing
1782 one. Since they are comments, it's ok to make mistakes; we are just
1783 trying to improve continuity to simplify other tests.
1786 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1788 if (!crl->ic && ic && crl->isComment)
1795 /*-----------------------------------------------------------------*/
1796 /* replaceRule - does replacement of a matching pattern */
1797 /*-----------------------------------------------------------------*/
1799 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1801 lineNode *cl = NULL;
1802 lineNode *pl = NULL, *lhead = NULL;
1803 /* a long function name and long variable name can evaluate to
1804 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1805 char lb[MAX_PATTERN_LEN*4];
1807 lineNode *comment = NULL;
1809 /* collect all the comment lines in the source */
1810 for (cl = *shead; cl != stail; cl = cl->next)
1812 if (cl->line && (*cl->line == ';' || cl->isDebug))
1814 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1815 (comment = newLineNode (cl->line)));
1816 pl->isDebug = cl->isDebug;
1817 pl->isComment = cl->isComment || (*cl->line == ';');
1822 /* for all the lines in the replacement pattern do */
1823 for (pl = pr->replace; pl; pl = pl->next)
1833 /* if the line contains a variable */
1834 if (*l == '%' && isdigit (*(l + 1)))
1836 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1839 fprintf (stderr, "used unbound variable in replacement\n");
1847 while (isdigit (*l)) {
1857 cl = connectLine (cl, newLineNode (lb));
1859 lhead = cl = newLineNode (lb);
1860 cl->isComment = pl->isComment;
1863 /* add the comments if any to the head of list */
1866 lineNode *lc = comment;
1877 /* determine which iCodes the replacment lines relate to */
1878 reassociate_ic(*shead,stail,lhead,cl);
1880 /* now we need to connect / replace the original chain */
1881 /* if there is a prev then change it */
1884 (*shead)->prev->next = lhead;
1885 lhead->prev = (*shead)->prev;
1888 /* now for the tail */
1889 if (stail && stail->next)
1891 stail->next->prev = cl;
1893 cl->next = stail->next;
1898 /* the replacement is empty - delete the source lines */
1900 (*shead)->prev->next = stail->next;
1902 stail->next->prev = (*shead)->prev;
1903 *shead = stail->next;
1907 /* Returns TRUE if this line is a label definition.
1909 * If so, start will point to the start of the label name,
1910 * and len will be it's length.
1913 isLabelDefinition (const char *line, const char **start, int *len)
1915 const char *cp = line;
1917 /* This line is a label if if consists of:
1918 * [optional whitespace] followed by identifier chars
1919 * (alnum | $ | _ ) followed by a colon.
1922 while (*cp && isspace (*cp))
1934 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1939 if ((cp == *start) || (*cp != ':'))
1944 *len = (cp - (*start));
1948 /* Quick & dirty string hash function. */
1950 hashSymbolName (const char *name)
1956 hash = (hash << 6) ^ *name;
1965 return hash % HTAB_SIZE;
1968 /* Build a hash of all labels in the passed set of lines
1969 * and how many times they are referenced.
1972 buildLabelRefCountHash (lineNode * head)
1979 assert (labelHash == NULL);
1980 labelHash = newHashTable (HTAB_SIZE);
1982 /* First pass: locate all the labels. */
1987 if (isLabelDefinition (line->line, &label, &labelLen)
1988 && labelLen <= SDCC_NAME_MAX)
1990 labelHashEntry *entry;
1992 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1994 memcpy (entry->name, label, labelLen);
1995 entry->name[labelLen] = 0;
1996 entry->refCount = -1;
1998 /* Assume function entry points are referenced somewhere, */
1999 /* even if we can't find a reference (might be from outside */
2001 if (line->ic && (line->ic->op == FUNCTION))
2004 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
2010 /* Second pass: for each line, note all the referenced labels. */
2011 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
2015 for (i = 0; i < HTAB_SIZE; i++)
2017 labelHashEntry *thisEntry;
2019 thisEntry = hTabFirstItemWK (labelHash, i);
2023 if (strstr (line->line, thisEntry->name))
2025 thisEntry->refCount++;
2027 thisEntry = hTabNextItemWK (labelHash);
2034 /* Spew the contents of the table. Debugging fun only. */
2035 for (i = 0; i < HTAB_SIZE; i++)
2037 labelHashEntry *thisEntry;
2039 thisEntry = hTabFirstItemWK (labelHash, i);
2043 fprintf (stderr, "label: %s ref %d\n",
2044 thisEntry->name, thisEntry->refCount);
2045 thisEntry = hTabNextItemWK (labelHash);
2051 /* How does this work?
2057 replace and restart.
2062 Where is stuff allocated?
2066 /*-----------------------------------------------------------------*/
2067 /* peepHole - matches & substitutes rules */
2068 /*-----------------------------------------------------------------*/
2070 peepHole (lineNode ** pls)
2074 lineNode *mtail = NULL;
2077 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
2078 /* The PIC port uses a different peep hole optimizer based on "pCode" */
2079 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2083 assert(labelHash == NULL);
2090 for (pr = rootRules; pr; pr = pr->next)
2092 for (spl = *pls; spl; spl = spl->next)
2094 /* if inline assembler then no peep hole */
2098 /* don't waste time starting a match on debug symbol
2100 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2105 /* Tidy up any data stored in the hTab */
2108 if (matchRule (spl, &mtail, pr, *pls))
2113 replaceRule (pls, mtail, pr);
2115 replaceRule (&spl, mtail, pr);
2117 /* if restart rule type then
2118 start at the top again */
2127 hTabDeleteAll (pr->vars);
2128 Safe_free (pr->vars);
2132 freeTrace (&_G.values);
2135 } while (restart == TRUE);
2139 hTabDeleteAll (labelHash);
2140 freeTrace (&_G.labels);
2146 /*-----------------------------------------------------------------*/
2147 /* readFileIntoBuffer - reads a file into a string buffer */
2148 /*-----------------------------------------------------------------*/
2150 readFileIntoBuffer (char *fname)
2156 char lb[MAX_PATTERN_LEN];
2158 if (!(f = fopen (fname, "r")))
2160 fprintf (stderr, "cannot open peep rule file\n");
2164 while ((ch = fgetc (f)) != EOF)
2168 /* if we maxed out our local buffer */
2169 if (nch >= (MAX_PATTERN_LEN - 2))
2172 /* copy it into allocated buffer */
2175 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2176 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2180 rs = Safe_strdup (lb);
2186 /* if some charaters left over */
2190 /* copy it into allocated buffer */
2193 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2194 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2198 rs = Safe_strdup (lb);
2204 /*-----------------------------------------------------------------*/
2205 /* initPeepHole - initialises the peep hole optimizer stuff */
2206 /*-----------------------------------------------------------------*/
2212 /* read in the default rules */
2213 readRules (port->peep.default_rules);
2215 /* if we have any additional file read it too */
2216 if (options.peep_file)
2218 readRules (s = readFileIntoBuffer (options.peep_file));
2219 setToNull ((void *) &s);
2223 #if !OPT_DISABLE_PIC
2224 /* Convert the peep rules into pcode.
2225 NOTE: this is only support in the PIC port (at the moment)
2228 peepRules2pCode(rootRules);
2231 #if !OPT_DISABLE_PIC16
2232 /* Convert the peep rules into pcode.
2233 NOTE: this is only support in the PIC port (at the moment)
2234 and the PIC16 port (VR 030601)
2236 if (TARGET_IS_PIC16)
2237 pic16_peepRules2pCode(rootRules);