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);
575 /* Within the context of the lines currPl through endPl, determine
576 ** if the variable var contains a symbol that is volatile. Returns
577 ** TRUE only if it is certain that this was not volatile (the symbol
578 ** was found and not volatile, or var was a constant or CPU register).
579 ** Returns FALSE if the symbol was found and volatile, the symbol was
580 ** not found, or var was a indirect/pointer addressing mode.
583 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
585 char symname[SDCC_NAME_MAX + 1];
592 /* Can't tell if indirect accesses are volatile or not, so
593 ** assume they are, just to be safe.
595 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
600 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
602 if (strstr(var,"(bc)"))
604 if (strstr(var,"(de)"))
606 if (strstr(var,"(hl)"))
608 if (strstr(var,"(ix"))
610 if (strstr(var,"(iy"))
614 /* Extract a symbol name from the variable */
615 while (*vp && (*vp!='_'))
617 while (*vp && (isalnum(*vp) || *vp=='_'))
623 /* Nothing resembling a symbol name was found, so it can't
630 for (cl = currPl; cl!=endPl->next; cl = cl->next)
632 if (cl->ic && (cl->ic!=last_ic))
638 op = IC_COND (cl->ic);
639 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
640 return !op->isvolatile;
642 op = IC_JTCOND (cl->ic);
643 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
644 return !op->isvolatile;
646 op = IC_LEFT (cl->ic);
647 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
648 return !op->isvolatile;
649 op = IC_RIGHT (cl->ic);
650 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
651 return !op->isvolatile;
652 op = IC_RESULT (cl->ic);
653 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
654 return !op->isvolatile;
659 /* Couldn't find the symbol for some reason. Assume volatile. */
665 * This rule restriction has two different behaviours depending on
666 * the number of parameters given.
668 * if notVolatile (no parameters given)
669 * The rule is applied only if none of the iCodes originating
670 * the matched pattern reference a volatile operand.
672 * if notVolatile %1 ... (one or more parameters given)
673 * The rule is applied if the parameters are not expressions
674 * containing volatile symbols and are not pointer accesses.
677 FBYNAME (notVolatile)
688 /* If no parameters given, just scan the iCodes for volatile operands */
689 for (cl = currPl; cl!=endPl->next; cl = cl->next)
696 op = IC_COND (cl->ic);
697 if (IS_SYMOP (op) && op->isvolatile)
700 op = IC_JTCOND (cl->ic);
701 if (IS_SYMOP (op) && op->isvolatile)
704 op = IC_LEFT (cl->ic);
705 if (IS_SYMOP (op) && op->isvolatile)
707 op = IC_RIGHT (cl->ic);
708 if (IS_SYMOP (op) && op->isvolatile)
710 op = IC_RESULT (cl->ic);
711 if (IS_SYMOP (op) && op->isvolatile)
719 /* There were parameters; check the volatility of each */
720 while (*cmdLine && isspace(*cmdLine))
727 if (!isdigit(*cmdLine))
729 varNumber = strtol(cmdLine, &digitend, 10);
731 while (*cmdLine && isspace(*cmdLine))
734 var = hTabItemWithKey (vars, varNumber);
738 notvol = notVolatileVariable (var, currPl, endPl);
744 fprintf (stderr, "*** internal error: var %d not bound"
745 " in peephole notVolatile rule.\n",
756 "*** internal error: notVolatile peephole restriction"
757 " malformed: %s\n", cmdLine);
762 /*------------------------------------------------------------------*/
763 /* setFromConditionArgs - parse a peephole condition's arguments */
764 /* to produce a set of strings, one per argument. Variables %x will */
765 /* be replaced with their values. String literals (in single quotes)*/
766 /* are accepted and return in unquoted form. */
767 /*------------------------------------------------------------------*/
769 setFromConditionArgs (char *cmdLine, hTab * vars)
774 set *operands = NULL;
779 while (*cmdLine && isspace(*cmdLine))
787 if (!isdigit(*cmdLine))
789 varNumber = strtol(cmdLine, &digitend, 10);
792 var = hTabItemWithKey (vars, varNumber);
796 addSetHead (&operands, var);
801 else if (*cmdLine == '\'' )
803 char quote = *cmdLine;
806 while (*cmdLine && *cmdLine != quote)
808 if (*cmdLine == quote)
812 addSetHead (&operands, var);
817 while (*cmdLine && isspace(*cmdLine))
824 deleteSet (&operands);
829 operandBaseName (const char *op)
831 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
833 if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4))
835 if (!strncmp (op, "ar", 2) && isdigit(*(op+2)) && !*(op+3))
843 /*-------------------------------------------------------------------*/
844 /* operandsNotRelated - returns true of the condition's operands are */
845 /* not related (taking into account register name aliases). N-way */
846 /* comparison performed between all operands. */
847 /*-------------------------------------------------------------------*/
848 FBYNAME (operandsNotRelated)
851 const char *op1, *op2;
853 operands = setFromConditionArgs (cmdLine, vars);
858 "*** internal error: operandsNotRelated peephole restriction"
859 " malformed: %s\n", cmdLine);
863 while ((op1 = setFirstItem (operands)))
865 deleteSetItem (&operands, (void*)op1);
866 op1 = operandBaseName (op1);
868 for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands))
870 op2 = operandBaseName (op2);
871 if (strcmp (op1, op2) == 0)
873 deleteSet (&operands);
879 deleteSet (&operands);
884 /*-----------------------------------------------------------------*/
885 /* callFuncByName - calls a function as defined in the table */
886 /*-----------------------------------------------------------------*/
888 callFuncByName (char *fname,
897 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *);
902 "labelInRange", labelInRange
906 "labelJTInRange", labelJTInRange
910 "operandsNotSame", operandsNotSame
914 "operandsNotSame3", operandsNotSame3
918 "operandsNotSame4", operandsNotSame4
922 "operandsNotSame5", operandsNotSame5
926 "operandsNotSame6", operandsNotSame6
930 "operandsNotSame7", operandsNotSame7
934 "operandsNotSame8", operandsNotSame8
938 "24bitMode", flat24bitMode
942 "xramMovcOption", xramMovcOption
946 "labelRefCount", labelRefCount
950 "portIsDS390", portIsDS390
953 "labelIsReturnOnly", labelIsReturnOnly
956 "okToRemoveSLOC", okToRemoveSLOC
959 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
962 "notVolatile", notVolatile
965 "operandsNotRelated", operandsNotRelated
969 char *cmdCopy, *funcName, *funcArgs, *cmdTerm;
973 /* Isolate the function name part (we are passed the full condition
974 * string including arguments)
976 cmdTerm = cmdCopy = Safe_strdup(fname);
980 funcArgs = funcName = cmdTerm;
981 while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(')
983 *funcArgs = '\0'; /* terminate the function name */
987 /* Find the start of the arguments */
988 if (c == ' ' || c == '\t')
989 while ((c = *funcArgs) && (c == ' ' || c == '\t'))
992 /* If the arguments started with an opening parenthesis, */
993 /* use the closing parenthesis for the end of the */
994 /* arguments and look for the start of another condition */
995 /* that can optionally follow. If there was no opening */
996 /* parethesis, then everything that follows are arguments */
997 /* and there can be no additional conditions. */
1001 while ((c = *cmdTerm) && c != ')')
1003 *cmdTerm = '\0'; /* terminate the arguments */
1007 while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ','))
1013 cmdTerm = NULL; /* closing parenthesis missing */
1022 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
1024 if (strcmp (ftab[i].fname, funcName) == 0)
1026 rc = (*ftab[i].func) (vars, currPl, endPl, head,
1035 "could not find named function \"%s\" in "
1036 "peephole function table\n",
1038 // If the function couldn't be found, let's assume it's
1039 // a bad rule and refuse it.
1044 while (rc && cmdTerm);
1051 /*-----------------------------------------------------------------*/
1052 /* printLine - prints a line chain into a given file */
1053 /*-----------------------------------------------------------------*/
1055 printLine (lineNode * head, FILE * of)
1057 iCode *last_ic = NULL;
1058 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
1065 if (head->ic!=last_ic)
1068 if (debug_iCode_tracking)
1071 fprintf (of, "; block = %d, seq = %d\n",
1072 head->ic->block, head->ic->seq);
1074 fprintf (of, "; iCode lost\n");
1078 /* don't indent comments & labels */
1080 (*head->line == ';' ||
1081 head->line[strlen (head->line) - 1] == ':')) {
1082 fprintf (of, "%s\n", head->line);
1084 if (head->isInline && *head->line=='#') {
1085 // comment out preprocessor directives in inline asm
1088 fprintf (of, "\t%s\n", head->line);
1094 /*-----------------------------------------------------------------*/
1095 /* newPeepRule - creates a new peeprule and attach it to the root */
1096 /*-----------------------------------------------------------------*/
1098 newPeepRule (lineNode * match,
1105 pr = Safe_alloc ( sizeof (peepRule));
1107 pr->replace = replace;
1108 pr->restart = restart;
1112 pr->cond = Safe_strdup (cond);
1117 pr->vars = newHashTable (100);
1119 /* if root is empty */
1121 rootRules = currRule = pr;
1123 currRule = currRule->next = pr;
1128 /*-----------------------------------------------------------------*/
1129 /* newLineNode - creates a new peep line */
1130 /*-----------------------------------------------------------------*/
1132 newLineNode (char *line)
1136 pl = Safe_alloc ( sizeof (lineNode));
1137 pl->line = Safe_strdup (line);
1142 /*-----------------------------------------------------------------*/
1143 /* connectLine - connects two lines */
1144 /*-----------------------------------------------------------------*/
1146 connectLine (lineNode * pl1, lineNode * pl2)
1150 fprintf (stderr, "trying to connect null line\n");
1160 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1161 if (!*x) { fprintf(stderr,y); return ; } }
1163 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1164 if (!*x) { fprintf(stderr,z); return ; } }
1165 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1166 if (!*x) { fprintf(stderr,z); return ; } }
1168 /*-----------------------------------------------------------------*/
1169 /* getPeepLine - parses the peep lines */
1170 /*-----------------------------------------------------------------*/
1172 getPeepLine (lineNode ** head, char **bpp)
1174 char lines[MAX_PATTERN_LEN];
1178 lineNode *currL = NULL;
1185 fprintf (stderr, "unexpected end of match pattern\n");
1192 while (isspace (*bp) ||
1203 /* read till end of line */
1205 while ((*bp != '\n' && *bp != '}') && *bp)
1210 while (*lp && isspace(*lp))
1212 isComment = (*lp == ';');
1214 if (!isComment || (isComment && !options.noPeepComments))
1217 *head = currL = newLineNode (lines);
1219 currL = connectLine (currL, newLineNode (lines));
1220 currL->isComment = isComment;
1228 /*-----------------------------------------------------------------*/
1229 /* readRules - reads the rules from a string buffer */
1230 /*-----------------------------------------------------------------*/
1232 readRules (char *bp)
1235 char lines[MAX_PATTERN_LEN];
1239 lineNode *currL = NULL;
1245 /* look for the token "replace" that is the
1247 while (*bp && strncmp (bp, "replace", 7))
1254 /* then look for either "restart" or '{' */
1255 while (strncmp (bp, "restart", 7) &&
1262 fprintf (stderr, "expected 'restart' or '{'\n");
1270 { /* must be restart */
1272 bp += strlen ("restart");
1274 EXPECT_CHR (bp, '{', "expected '{'\n");
1278 /* skip thru all the blank space */
1279 SKIP_SPACE (bp, "unexpected end of rule\n");
1281 match = replace = currL = NULL;
1282 /* we are the start of a rule */
1283 getPeepLine (&match, &bp);
1285 /* now look for by */
1286 EXPECT_STR (bp, "by", "expected 'by'\n");
1288 /* then look for a '{' */
1289 EXPECT_CHR (bp, '{', "expected '{'\n");
1292 SKIP_SPACE (bp, "unexpected end of rule\n");
1293 getPeepLine (&replace, &bp);
1295 /* look for a 'if' */
1296 while ((isspace (*bp) || *bp == '\n') && *bp)
1299 if (strncmp (bp, "if", 2) == 0)
1302 while ((isspace (*bp) || *bp == '\n') && *bp)
1306 fprintf (stderr, "expected condition name\n");
1310 /* look for the condition */
1312 while (*bp && (*bp != '\n'))
1318 newPeepRule (match, replace, lines, restart);
1321 newPeepRule (match, replace, NULL, restart);
1326 /*-----------------------------------------------------------------*/
1327 /* keyForVar - returns the numeric key for a var */
1328 /*-----------------------------------------------------------------*/
1334 while (isdigit (*d))
1343 /*-----------------------------------------------------------------*/
1344 /* bindVar - binds a value to a variable in the given hashtable */
1345 /*-----------------------------------------------------------------*/
1347 bindVar (int key, char **s, hTab ** vtab)
1349 char vval[MAX_PATTERN_LEN];
1353 /* first get the value of the variable */
1355 /* the value is ended by a ',' or space or newline or null or ) */
1364 /* if we find a '(' then we need to balance it */
1376 // include the trailing ')'
1385 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1387 hTabAddItem (vtab, key, vvx);
1390 /*-----------------------------------------------------------------*/
1391 /* matchLine - matches one line */
1392 /*-----------------------------------------------------------------*/
1394 matchLine (char *s, char *d, hTab ** vars)
1403 /* skip white space in both */
1404 while (isspace (*s))
1406 while (isspace (*d))
1409 /* if the destination is a var */
1410 if (*d == '%' && isdigit (*(d + 1)) && vars)
1412 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1413 /* if the variable is already bound
1414 then it MUST match with dest */
1422 /* variable not bound we need to
1424 bindVar (keyForVar (d + 1), &s, vars);
1426 /* in either case go past the variable */
1428 while (isdigit (*d))
1431 while (isspace (*s))
1433 while (isspace (*d))
1437 /* they should be an exact match other wise */
1446 /* get rid of the trailing spaces
1447 in both source & destination */
1449 while (isspace (*s))
1453 while (isspace (*d))
1456 /* after all this if only one of them
1457 has something left over then no match */
1464 /*-----------------------------------------------------------------*/
1465 /* matchRule - matches a all the rule lines */
1466 /*-----------------------------------------------------------------*/
1468 matchRule (lineNode * pl,
1473 lineNode *spl; /* source pl */
1474 lineNode *rpl; /* rule peep line */
1476 /* setToNull((void *) &pr->vars); */
1477 /* pr->vars = newHashTable(100); */
1479 /* for all the lines defined in the rule */
1485 /* if the source line starts with a ';' then
1486 comment line don't process or the source line
1487 contains == . debugger information skip it */
1489 (*spl->line == ';' || spl->isDebug))
1495 if (!matchLine (spl->line, rpl->line, &pr->vars))
1503 /* if rules ended */
1506 /* if this rule has additional conditions */
1509 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1528 reassociate_ic_down (lineNode *shead, lineNode *stail,
1529 lineNode *rhead, lineNode *rtail)
1531 lineNode *csl; /* current source line */
1532 lineNode *crl; /* current replacement line */
1538 /* skip over any comments */
1539 while (csl!=stail->next && csl->isComment)
1541 while (crl!=rtail->next && crl->isComment)
1544 /* quit if we reach the end */
1545 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1548 if (matchLine(csl->line,crl->line,NULL))
1560 reassociate_ic_up (lineNode *shead, lineNode *stail,
1561 lineNode *rhead, lineNode *rtail)
1563 lineNode *csl; /* current source line */
1564 lineNode *crl; /* current replacement line */
1570 /* skip over any comments */
1571 while (csl!=shead->prev && csl->isComment)
1573 while (crl!=rhead->prev && crl->isComment)
1576 /* quit if we reach the end */
1577 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1580 if (matchLine(csl->line,crl->line,NULL))
1591 /*------------------------------------------------------------------*/
1592 /* reassociate_ic - reassociate replacement lines with origin iCode */
1593 /*------------------------------------------------------------------*/
1595 reassociate_ic (lineNode *shead, lineNode *stail,
1596 lineNode *rhead, lineNode *rtail)
1598 lineNode *csl; /* current source line */
1599 lineNode *crl; /* current replacement line */
1603 /* Check to see if all the source lines (excluding comments) came
1604 ** for the same iCode
1607 for (csl=shead;csl!=stail->next;csl=csl->next)
1608 if (csl->ic && !csl->isComment)
1613 single_iCode = (ic!=NULL);
1614 for (csl=shead;csl!=stail->next;csl=csl->next)
1615 if ((csl->ic != ic) && !csl->isComment)
1617 /* More than one iCode was found. However, if it's just the
1618 ** last line with the different iCode and it was not changed
1619 ** in the replacement, everything else must be the first iCode.
1621 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1623 rtail->ic = stail->ic;
1624 for (crl=rhead;crl!=rtail;crl=crl->next)
1629 single_iCode = FALSE;
1633 /* If all of the source lines came from the same iCode, then so have
1634 ** all of the replacement lines too.
1638 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1643 /* The source lines span iCodes, so we may end up with replacement
1644 ** lines that we don't know which iCode(s) to associate with. Do the
1645 ** best we can by using the following strategies:
1646 ** 1) Start at the top and scan down. As long as the source line
1647 ** matches the replacement line, they have the same iCode.
1648 ** 2) Start at the bottom and scan up. As long as the source line
1649 ** matches the replacement line, they have the same iCode.
1650 ** 3) For any label in the source, look for a matching label in
1651 ** the replacment. If found, they have the same iCode. From
1652 ** these matching labels, scan down for additional matching
1653 ** lines; if found, they also have the same iCode.
1656 /* Strategy #1: Start at the top and scan down for matches
1658 reassociate_ic_down(shead,stail,rhead,rtail);
1660 /* Strategy #2: Start at the bottom and scan up for matches
1662 reassociate_ic_up(shead,stail,rhead,rtail);
1664 /* Strategy #3: Try to match labels
1669 const char *labelStart;
1672 /* skip over any comments */
1673 while (csl!=stail->next && csl->isComment)
1675 if (csl==stail->next)
1678 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1680 /* found a source line label; look for it in the replacment lines */
1684 while (crl!=rtail->next && crl->isComment)
1686 if (crl==rtail->next)
1688 if (matchLine(csl->line, crl->line, NULL))
1690 reassociate_ic_down(csl,stail,crl,rtail);
1700 /* Try to assign a meaningful iCode to any comment that is missing
1701 one. Since they are comments, it's ok to make mistakes; we are just
1702 trying to improve continuity to simplify other tests.
1705 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1707 if (!crl->ic && ic && crl->isComment)
1714 /*-----------------------------------------------------------------*/
1715 /* replaceRule - does replacement of a matching pattern */
1716 /*-----------------------------------------------------------------*/
1718 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1720 lineNode *cl = NULL;
1721 lineNode *pl = NULL, *lhead = NULL;
1722 /* a long function name and long variable name can evaluate to
1723 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1724 char lb[MAX_PATTERN_LEN*4];
1726 lineNode *comment = NULL;
1728 /* collect all the comment lines in the source */
1729 for (cl = *shead; cl != stail; cl = cl->next)
1731 if (cl->line && (*cl->line == ';' || cl->isDebug))
1733 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1734 (comment = newLineNode (cl->line)));
1735 pl->isDebug = cl->isDebug;
1736 pl->isComment = cl->isComment || (*cl->line == ';');
1741 /* for all the lines in the replacement pattern do */
1742 for (pl = pr->replace; pl; pl = pl->next)
1752 /* if the line contains a variable */
1753 if (*l == '%' && isdigit (*(l + 1)))
1755 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1758 fprintf (stderr, "used unbound variable in replacement\n");
1766 while (isdigit (*l)) {
1776 cl = connectLine (cl, newLineNode (lb));
1778 lhead = cl = newLineNode (lb);
1779 cl->isComment = pl->isComment;
1782 /* add the comments if any to the head of list */
1785 lineNode *lc = comment;
1796 /* determine which iCodes the replacment lines relate to */
1797 reassociate_ic(*shead,stail,lhead,cl);
1799 /* now we need to connect / replace the original chain */
1800 /* if there is a prev then change it */
1803 (*shead)->prev->next = lhead;
1804 lhead->prev = (*shead)->prev;
1807 /* now for the tail */
1808 if (stail && stail->next)
1810 stail->next->prev = cl;
1812 cl->next = stail->next;
1817 /* the replacement is empty - delete the source lines */
1819 (*shead)->prev->next = stail->next;
1821 stail->next->prev = (*shead)->prev;
1822 *shead = stail->next;
1826 /* Returns TRUE if this line is a label definition.
1828 * If so, start will point to the start of the label name,
1829 * and len will be it's length.
1832 isLabelDefinition (const char *line, const char **start, int *len)
1834 const char *cp = line;
1836 /* This line is a label if if consists of:
1837 * [optional whitespace] followed by identifier chars
1838 * (alnum | $ | _ ) followed by a colon.
1841 while (*cp && isspace (*cp))
1853 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1858 if ((cp == *start) || (*cp != ':'))
1863 *len = (cp - (*start));
1867 /* Quick & dirty string hash function. */
1869 hashSymbolName (const char *name)
1875 hash = (hash << 6) ^ *name;
1884 return hash % HTAB_SIZE;
1887 /* Build a hash of all labels in the passed set of lines
1888 * and how many times they are referenced.
1891 buildLabelRefCountHash (lineNode * head)
1898 assert (labelHash == NULL);
1899 labelHash = newHashTable (HTAB_SIZE);
1901 /* First pass: locate all the labels. */
1906 if (isLabelDefinition (line->line, &label, &labelLen)
1907 && labelLen <= SDCC_NAME_MAX)
1909 labelHashEntry *entry;
1911 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1913 memcpy (entry->name, label, labelLen);
1914 entry->name[labelLen] = 0;
1915 entry->refCount = -1;
1917 /* Assume function entry points are referenced somewhere, */
1918 /* even if we can't find a reference (might be from outside */
1920 if (line->ic && (line->ic->op == FUNCTION))
1923 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1929 /* Second pass: for each line, note all the referenced labels. */
1930 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1934 for (i = 0; i < HTAB_SIZE; i++)
1936 labelHashEntry *thisEntry;
1938 thisEntry = hTabFirstItemWK (labelHash, i);
1942 if (strstr (line->line, thisEntry->name))
1944 thisEntry->refCount++;
1946 thisEntry = hTabNextItemWK (labelHash);
1953 /* Spew the contents of the table. Debugging fun only. */
1954 for (i = 0; i < HTAB_SIZE; i++)
1956 labelHashEntry *thisEntry;
1958 thisEntry = hTabFirstItemWK (labelHash, i);
1962 fprintf (stderr, "label: %s ref %d\n",
1963 thisEntry->name, thisEntry->refCount);
1964 thisEntry = hTabNextItemWK (labelHash);
1970 /* How does this work?
1976 replace and restart.
1981 Where is stuff allocated?
1985 /*-----------------------------------------------------------------*/
1986 /* peepHole - matches & substitutes rules */
1987 /*-----------------------------------------------------------------*/
1989 peepHole (lineNode ** pls)
1993 lineNode *mtail = NULL;
1996 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1997 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1998 if (TARGET_IS_PIC || TARGET_IS_PIC16)
2002 assert(labelHash == NULL);
2009 for (pr = rootRules; pr; pr = pr->next)
2011 for (spl = *pls; spl; spl = spl->next)
2013 /* if inline assembler then no peep hole */
2017 /* don't waste time starting a match on debug symbol
2019 if (spl->isDebug || spl->isComment || *(spl->line)==';')
2024 /* Tidy up any data stored in the hTab */
2027 if (matchRule (spl, &mtail, pr, *pls))
2032 replaceRule (pls, mtail, pr);
2034 replaceRule (&spl, mtail, pr);
2036 /* if restart rule type then
2037 start at the top again */
2046 hTabDeleteAll (pr->vars);
2047 Safe_free (pr->vars);
2051 freeTrace (&_G.values);
2054 } while (restart == TRUE);
2058 hTabDeleteAll (labelHash);
2059 freeTrace (&_G.labels);
2065 /*-----------------------------------------------------------------*/
2066 /* readFileIntoBuffer - reads a file into a string buffer */
2067 /*-----------------------------------------------------------------*/
2069 readFileIntoBuffer (char *fname)
2075 char lb[MAX_PATTERN_LEN];
2077 if (!(f = fopen (fname, "r")))
2079 fprintf (stderr, "cannot open peep rule file\n");
2083 while ((ch = fgetc (f)) != EOF)
2087 /* if we maxed out our local buffer */
2088 if (nch >= (MAX_PATTERN_LEN - 2))
2091 /* copy it into allocated buffer */
2094 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2095 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2099 rs = Safe_strdup (lb);
2105 /* if some charaters left over */
2109 /* copy it into allocated buffer */
2112 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
2113 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
2117 rs = Safe_strdup (lb);
2123 /*-----------------------------------------------------------------*/
2124 /* initPeepHole - initialises the peep hole optimizer stuff */
2125 /*-----------------------------------------------------------------*/
2131 /* read in the default rules */
2132 readRules (port->peep.default_rules);
2134 /* if we have any additional file read it too */
2135 if (options.peep_file)
2137 readRules (s = readFileIntoBuffer (options.peep_file));
2138 setToNull ((void *) &s);
2142 #if !OPT_DISABLE_PIC
2143 /* Convert the peep rules into pcode.
2144 NOTE: this is only support in the PIC port (at the moment)
2147 peepRules2pCode(rootRules);
2150 #if !OPT_DISABLE_PIC16
2151 /* Convert the peep rules into pcode.
2152 NOTE: this is only support in the PIC port (at the moment)
2153 and the PIC16 port (VR 030601)
2155 if (TARGET_IS_PIC16)
2156 pic16_peepRules2pCode(rootRules);