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, const 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)
181 /*-----------------------------------------------------------------*/
182 /* labelIsReturnOnly - Check if label %5 is followed by RET */
183 /*-----------------------------------------------------------------*/
184 FBYNAME (labelIsReturnOnly)
186 /* assumes that %5 pattern variable has the label name */
187 const char *label, *p;
192 label = hTabItemWithKey (vars, 5);
193 if (!label) return FALSE;
196 for(pl = currPl; pl; pl = pl->next) {
197 if (pl->line && !pl->isDebug && !pl->isComment &&
198 pl->line[strlen(pl->line)-1] == ':') {
199 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
200 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
201 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
202 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
203 *(pl->line+5) != '$') {
204 return FALSE; /* non-local label encountered */
208 if (!pl) return FALSE; /* did not find the label */
210 while (pl && (pl->isDebug || pl->isComment))
212 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
214 for (p = pl->line; *p && isspace(*p); p++)
220 if (strcmp(p, retInst) == 0) return TRUE;
225 /*-----------------------------------------------------------------*/
226 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
227 /* usage of it in the code depends on a value from this section */
228 /*-----------------------------------------------------------------*/
229 FBYNAME (okToRemoveSLOC)
232 const char *sloc, *p;
233 int dummy1, dummy2, dummy3;
235 /* assumes that %1 as the SLOC name */
236 sloc = hTabItemWithKey (vars, 1);
237 if (sloc == NULL) return FALSE;
238 p = strstr(sloc, "sloc");
239 if (p == NULL) return FALSE;
241 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
242 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
243 /* the sloc name begins with that. Probably not really necessary */
245 /* Look for any occurance of this SLOC before the peephole match */
246 for (pl = currPl->prev; pl; pl = pl->prev) {
247 if (pl->line && !pl->isDebug && !pl->isComment
248 && *pl->line != ';' && strstr(pl->line, sloc))
251 /* Look for any occurance of this SLOC after the peephole match */
252 for (pl = endPl->next; pl; pl = pl->next) {
253 if (pl->line && !pl->isDebug && !pl->isComment
254 && *pl->line != ';' && strstr(pl->line, sloc))
257 return TRUE; /* safe for a peephole to remove it :) */
261 /*-----------------------------------------------------------------*/
262 /* operandsNotSame - check if %1 & %2 are the same */
263 /*-----------------------------------------------------------------*/
264 FBYNAME (operandsNotSame)
266 char *op1 = hTabItemWithKey (vars, 1);
267 char *op2 = hTabItemWithKey (vars, 2);
269 if (strcmp (op1, op2) == 0)
275 /*-----------------------------------------------------------------*/
276 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
277 /*-----------------------------------------------------------------*/
278 FBYNAME (operandsNotSame3)
280 char *op1 = hTabItemWithKey (vars, 1);
281 char *op2 = hTabItemWithKey (vars, 2);
282 char *op3 = hTabItemWithKey (vars, 3);
284 if ( (strcmp (op1, op2) == 0) ||
285 (strcmp (op1, op3) == 0) ||
286 (strcmp (op2, op3) == 0) )
292 /*-----------------------------------------------------------------*/
293 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
294 /*-----------------------------------------------------------------*/
295 FBYNAME (operandsNotSame4)
297 char *op1 = hTabItemWithKey (vars, 1);
298 char *op2 = hTabItemWithKey (vars, 2);
299 char *op3 = hTabItemWithKey (vars, 3);
300 char *op4 = hTabItemWithKey (vars, 4);
302 if ( (strcmp (op1, op2) == 0) ||
303 (strcmp (op1, op3) == 0) ||
304 (strcmp (op1, op4) == 0) ||
305 (strcmp (op2, op3) == 0) ||
306 (strcmp (op2, op4) == 0) ||
307 (strcmp (op3, op4) == 0) )
313 /*-----------------------------------------------------------------*/
314 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
315 /*-----------------------------------------------------------------*/
316 FBYNAME (operandsNotSame5)
318 char *op1 = hTabItemWithKey (vars, 1);
319 char *op2 = hTabItemWithKey (vars, 2);
320 char *op3 = hTabItemWithKey (vars, 3);
321 char *op4 = hTabItemWithKey (vars, 4);
322 char *op5 = hTabItemWithKey (vars, 5);
324 if ( (strcmp (op1, op2) == 0) ||
325 (strcmp (op1, op3) == 0) ||
326 (strcmp (op1, op4) == 0) ||
327 (strcmp (op1, op5) == 0) ||
328 (strcmp (op2, op3) == 0) ||
329 (strcmp (op2, op4) == 0) ||
330 (strcmp (op2, op5) == 0) ||
331 (strcmp (op3, op4) == 0) ||
332 (strcmp (op3, op5) == 0) ||
333 (strcmp (op4, op5) == 0) )
339 /*-----------------------------------------------------------------*/
340 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
341 /*-----------------------------------------------------------------*/
342 FBYNAME (operandsNotSame6)
344 char *op1 = hTabItemWithKey (vars, 1);
345 char *op2 = hTabItemWithKey (vars, 2);
346 char *op3 = hTabItemWithKey (vars, 3);
347 char *op4 = hTabItemWithKey (vars, 4);
348 char *op5 = hTabItemWithKey (vars, 5);
349 char *op6 = hTabItemWithKey (vars, 6);
351 if ( (strcmp (op1, op2) == 0) ||
352 (strcmp (op1, op3) == 0) ||
353 (strcmp (op1, op4) == 0) ||
354 (strcmp (op1, op5) == 0) ||
355 (strcmp (op1, op6) == 0) ||
356 (strcmp (op2, op3) == 0) ||
357 (strcmp (op2, op4) == 0) ||
358 (strcmp (op2, op5) == 0) ||
359 (strcmp (op2, op6) == 0) ||
360 (strcmp (op3, op4) == 0) ||
361 (strcmp (op3, op5) == 0) ||
362 (strcmp (op3, op6) == 0) ||
363 (strcmp (op4, op5) == 0) ||
364 (strcmp (op4, op6) == 0) ||
365 (strcmp (op5, op6) == 0) )
372 /*-----------------------------------------------------------------*/
373 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
374 /*-----------------------------------------------------------------*/
375 FBYNAME (operandsNotSame7)
377 char *op1 = hTabItemWithKey (vars, 1);
378 char *op2 = hTabItemWithKey (vars, 2);
379 char *op3 = hTabItemWithKey (vars, 3);
380 char *op4 = hTabItemWithKey (vars, 4);
381 char *op5 = hTabItemWithKey (vars, 5);
382 char *op6 = hTabItemWithKey (vars, 6);
383 char *op7 = hTabItemWithKey (vars, 7);
385 if ( (strcmp (op1, op2) == 0) ||
386 (strcmp (op1, op3) == 0) ||
387 (strcmp (op1, op4) == 0) ||
388 (strcmp (op1, op5) == 0) ||
389 (strcmp (op1, op6) == 0) ||
390 (strcmp (op1, op7) == 0) ||
391 (strcmp (op2, op3) == 0) ||
392 (strcmp (op2, op4) == 0) ||
393 (strcmp (op2, op5) == 0) ||
394 (strcmp (op2, op6) == 0) ||
395 (strcmp (op2, op7) == 0) ||
396 (strcmp (op3, op4) == 0) ||
397 (strcmp (op3, op5) == 0) ||
398 (strcmp (op3, op6) == 0) ||
399 (strcmp (op3, op7) == 0) ||
400 (strcmp (op4, op5) == 0) ||
401 (strcmp (op4, op6) == 0) ||
402 (strcmp (op4, op7) == 0) ||
403 (strcmp (op5, op6) == 0) ||
404 (strcmp (op5, op7) == 0) ||
405 (strcmp (op6, op7) == 0) )
411 /*-----------------------------------------------------------------*/
412 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
413 /*-----------------------------------------------------------------*/
414 FBYNAME (operandsNotSame8)
416 char *op1 = hTabItemWithKey (vars, 1);
417 char *op2 = hTabItemWithKey (vars, 2);
418 char *op3 = hTabItemWithKey (vars, 3);
419 char *op4 = hTabItemWithKey (vars, 4);
420 char *op5 = hTabItemWithKey (vars, 5);
421 char *op6 = hTabItemWithKey (vars, 6);
422 char *op7 = hTabItemWithKey (vars, 7);
423 char *op8 = hTabItemWithKey (vars, 8);
425 if ( (strcmp (op1, op2) == 0) ||
426 (strcmp (op1, op3) == 0) ||
427 (strcmp (op1, op4) == 0) ||
428 (strcmp (op1, op5) == 0) ||
429 (strcmp (op1, op6) == 0) ||
430 (strcmp (op1, op7) == 0) ||
431 (strcmp (op1, op8) == 0) ||
432 (strcmp (op2, op3) == 0) ||
433 (strcmp (op2, op4) == 0) ||
434 (strcmp (op2, op5) == 0) ||
435 (strcmp (op2, op6) == 0) ||
436 (strcmp (op2, op7) == 0) ||
437 (strcmp (op2, op8) == 0) ||
438 (strcmp (op3, op4) == 0) ||
439 (strcmp (op3, op5) == 0) ||
440 (strcmp (op3, op6) == 0) ||
441 (strcmp (op3, op7) == 0) ||
442 (strcmp (op3, op8) == 0) ||
443 (strcmp (op4, op5) == 0) ||
444 (strcmp (op4, op6) == 0) ||
445 (strcmp (op4, op7) == 0) ||
446 (strcmp (op4, op8) == 0) ||
447 (strcmp (op5, op6) == 0) ||
448 (strcmp (op5, op7) == 0) ||
449 (strcmp (op5, op8) == 0) ||
450 (strcmp (op6, op7) == 0) ||
451 (strcmp (op6, op8) == 0) ||
452 (strcmp (op7, op8) == 0) )
461 * takes two parameters: a variable (bound to a label name)
462 * and an expected reference count.
464 * Returns TRUE if that label is defined and referenced exactly
465 * the given number of times.
467 FBYNAME (labelRefCount)
469 int varNumber, expectedRefCount;
472 /* If we don't have the label hash table yet, build it. */
475 buildLabelRefCountHash (head);
478 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
480 char *label = hTabItemWithKey (vars, varNumber);
484 labelHashEntry *entry;
486 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
490 if (!strcmp (label, entry->name))
494 entry = hTabNextItemWK (labelHash);
500 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
501 label, entry->refCount, expectedRefCount);
504 rc = (expectedRefCount == entry->refCount);
508 fprintf (stderr, "*** internal error: no label has entry for"
509 " %s in labelRefCount peephole.\n",
515 fprintf (stderr, "*** internal error: var %d not bound"
516 " in peephole labelRefCount rule.\n",
524 "*** internal error: labelRefCount peephole restriction"
525 " malformed: %s\n", cmdLine);
530 /* Within the context of the lines currPl through endPl, determine
531 ** if the variable var contains a symbol that is volatile. Returns
532 ** TRUE only if it is certain that this was not volatile (the symbol
533 ** was found and not volatile, or var was a constant or CPU register).
534 ** Returns FALSE if the symbol was found and volatile, the symbol was
535 ** not found, or var was a indirect/pointer addressing mode.
538 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
540 char symname[SDCC_NAME_MAX + 1];
547 /* Can't tell if indirect accesses are volatile or not, so
548 ** assume they are, just to be safe.
550 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
555 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
557 if (strstr(var,"(bc)"))
559 if (strstr(var,"(de)"))
561 if (strstr(var,"(hl)"))
563 if (strstr(var,"(ix"))
565 if (strstr(var,"(iy"))
569 /* Extract a symbol name from the variable */
570 while (*vp && (*vp!='_'))
572 while (*vp && (isalnum(*vp) || *vp=='_'))
578 /* Nothing resembling a symbol name was found, so it can't
585 for (cl = currPl; cl!=endPl->next; cl = cl->next)
587 if (cl->ic && (cl->ic!=last_ic))
593 op = IC_COND (cl->ic);
594 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
595 return !op->isvolatile;
597 op = IC_JTCOND (cl->ic);
598 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
599 return !op->isvolatile;
601 op = IC_LEFT (cl->ic);
602 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
603 return !op->isvolatile;
604 op = IC_RIGHT (cl->ic);
605 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
606 return !op->isvolatile;
607 op = IC_RESULT (cl->ic);
608 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
609 return !op->isvolatile;
614 /* Couldn't find the symbol for some reason. Assume volatile. */
620 * This rule restriction has two different behaviours depending on
621 * the number of parameters given.
623 * if notVolatile (no parameters given)
624 * The rule is applied only if none of the iCodes originating
625 * the matched pattern reference a volatile operand.
627 * if notVolatile %1 ... (one or more parameters given)
628 * The rule is applied if the parameters are not expressions
629 * containing volatile symbols and are not pointer accesses.
632 FBYNAME (notVolatile)
643 /* If no parameters given, just scan the iCodes for volatile operands */
644 for (cl = currPl; cl!=endPl->next; cl = cl->next)
651 op = IC_COND (cl->ic);
652 if (IS_SYMOP (op) && op->isvolatile)
655 op = IC_JTCOND (cl->ic);
656 if (IS_SYMOP (op) && op->isvolatile)
659 op = IC_LEFT (cl->ic);
660 if (IS_SYMOP (op) && op->isvolatile)
662 op = IC_RIGHT (cl->ic);
663 if (IS_SYMOP (op) && op->isvolatile)
665 op = IC_RESULT (cl->ic);
666 if (IS_SYMOP (op) && op->isvolatile)
674 /* There were parameters; check the volatility of each */
675 while (*cmdLine && isspace(*cmdLine))
682 if (!isdigit(*cmdLine))
684 varNumber = strtol(cmdLine, &digitend, 10);
686 while (*cmdLine && isspace(*cmdLine))
689 var = hTabItemWithKey (vars, varNumber);
693 notvol = notVolatileVariable (var, currPl, endPl);
699 fprintf (stderr, "*** internal error: var %d not bound"
700 " in peephole notVolatile rule.\n",
711 "*** internal error: notVolatile peephole restriction"
712 " malformed: %s\n", cmdLine);
717 /*-----------------------------------------------------------------*/
718 /* callFuncByName - calls a function as defined in the table */
719 /*-----------------------------------------------------------------*/
721 callFuncByName (char *fname,
730 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
735 "labelInRange", labelInRange
739 "operandsNotSame", operandsNotSame
743 "operandsNotSame3", operandsNotSame3
747 "operandsNotSame4", operandsNotSame4
751 "operandsNotSame5", operandsNotSame5
755 "operandsNotSame6", operandsNotSame6
759 "operandsNotSame7", operandsNotSame7
763 "operandsNotSame8", operandsNotSame8
767 "24bitMode", flat24bitMode
771 "xramMovcOption", xramMovcOption
775 "labelRefCount", labelRefCount
779 "portIsDS390", portIsDS390
782 "labelIsReturnOnly", labelIsReturnOnly
785 "okToRemoveSLOC", okToRemoveSLOC
788 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
791 "notVolatile", notVolatile
795 char *cmdCopy, *funcName, *funcArgs;
798 /* Isolate the function name part (we are passed the full condition
799 * string including arguments)
801 cmdCopy = Safe_strdup(fname);
802 funcName = strtok(cmdCopy, " \t");
803 funcArgs = strtok(NULL, "");
805 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
807 if (strcmp (ftab[i].fname, funcName) == 0)
809 rc = (*ftab[i].func) (vars, currPl, endPl, head,
817 "could not find named function \"%s\" in "
818 "peephole function table\n",
820 // If the function couldn't be found, let's assume it's
821 // a bad rule and refuse it.
830 /*-----------------------------------------------------------------*/
831 /* printLine - prints a line chain into a given file */
832 /*-----------------------------------------------------------------*/
834 printLine (lineNode * head, FILE * of)
836 iCode *last_ic = NULL;
837 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
844 if (head->ic!=last_ic)
847 if (debug_iCode_tracking)
850 fprintf (of, "; block = %d, seq = %d\n",
851 head->ic->block, head->ic->seq);
853 fprintf (of, "; iCode lost\n");
857 /* don't indent comments & labels */
859 (*head->line == ';' ||
860 head->line[strlen (head->line) - 1] == ':')) {
861 fprintf (of, "%s\n", head->line);
863 if (head->isInline && *head->line=='#') {
864 // comment out preprocessor directives in inline asm
867 fprintf (of, "\t%s\n", head->line);
873 /*-----------------------------------------------------------------*/
874 /* newPeepRule - creates a new peeprule and attach it to the root */
875 /*-----------------------------------------------------------------*/
877 newPeepRule (lineNode * match,
884 pr = Safe_alloc ( sizeof (peepRule));
886 pr->replace = replace;
887 pr->restart = restart;
891 pr->cond = Safe_strdup (cond);
896 pr->vars = newHashTable (100);
898 /* if root is empty */
900 rootRules = currRule = pr;
902 currRule = currRule->next = pr;
907 /*-----------------------------------------------------------------*/
908 /* newLineNode - creates a new peep line */
909 /*-----------------------------------------------------------------*/
911 newLineNode (char *line)
915 pl = Safe_alloc ( sizeof (lineNode));
916 pl->line = Safe_strdup (line);
921 /*-----------------------------------------------------------------*/
922 /* connectLine - connects two lines */
923 /*-----------------------------------------------------------------*/
925 connectLine (lineNode * pl1, lineNode * pl2)
929 fprintf (stderr, "trying to connect null line\n");
939 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
940 if (!*x) { fprintf(stderr,y); return ; } }
942 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
943 if (!*x) { fprintf(stderr,z); return ; } }
944 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
945 if (!*x) { fprintf(stderr,z); return ; } }
947 /*-----------------------------------------------------------------*/
948 /* getPeepLine - parses the peep lines */
949 /*-----------------------------------------------------------------*/
951 getPeepLine (lineNode ** head, char **bpp)
953 char lines[MAX_PATTERN_LEN];
957 lineNode *currL = NULL;
964 fprintf (stderr, "unexpected end of match pattern\n");
971 while (isspace (*bp) ||
982 /* read till end of line */
984 while ((*bp != '\n' && *bp != '}') && *bp)
989 while (*lp && isspace(*lp))
991 isComment = (*lp == ';');
993 if (!isComment || (isComment && !options.noPeepComments))
996 *head = currL = newLineNode (lines);
998 currL = connectLine (currL, newLineNode (lines));
999 currL->isComment = isComment;
1007 /*-----------------------------------------------------------------*/
1008 /* readRules - reads the rules from a string buffer */
1009 /*-----------------------------------------------------------------*/
1011 readRules (char *bp)
1014 char lines[MAX_PATTERN_LEN];
1018 lineNode *currL = NULL;
1024 /* look for the token "replace" that is the
1026 while (*bp && strncmp (bp, "replace", 7))
1033 /* then look for either "restart" or '{' */
1034 while (strncmp (bp, "restart", 7) &&
1041 fprintf (stderr, "expected 'restart' or '{'\n");
1049 { /* must be restart */
1051 bp += strlen ("restart");
1053 EXPECT_CHR (bp, '{', "expected '{'\n");
1057 /* skip thru all the blank space */
1058 SKIP_SPACE (bp, "unexpected end of rule\n");
1060 match = replace = currL = NULL;
1061 /* we are the start of a rule */
1062 getPeepLine (&match, &bp);
1064 /* now look for by */
1065 EXPECT_STR (bp, "by", "expected 'by'\n");
1067 /* then look for a '{' */
1068 EXPECT_CHR (bp, '{', "expected '{'\n");
1071 SKIP_SPACE (bp, "unexpected end of rule\n");
1072 getPeepLine (&replace, &bp);
1074 /* look for a 'if' */
1075 while ((isspace (*bp) || *bp == '\n') && *bp)
1078 if (strncmp (bp, "if", 2) == 0)
1081 while ((isspace (*bp) || *bp == '\n') && *bp)
1085 fprintf (stderr, "expected condition name\n");
1089 /* look for the condition */
1091 while (*bp && (*bp != '\n'))
1097 newPeepRule (match, replace, lines, restart);
1100 newPeepRule (match, replace, NULL, restart);
1105 /*-----------------------------------------------------------------*/
1106 /* keyForVar - returns the numeric key for a var */
1107 /*-----------------------------------------------------------------*/
1113 while (isdigit (*d))
1122 /*-----------------------------------------------------------------*/
1123 /* bindVar - binds a value to a variable in the given hashtable */
1124 /*-----------------------------------------------------------------*/
1126 bindVar (int key, char **s, hTab ** vtab)
1128 char vval[MAX_PATTERN_LEN];
1132 /* first get the value of the variable */
1134 /* the value is ended by a ',' or space or newline or null or ) */
1143 /* if we find a '(' then we need to balance it */
1155 // include the trailing ')'
1164 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1166 hTabAddItem (vtab, key, vvx);
1169 /*-----------------------------------------------------------------*/
1170 /* matchLine - matches one line */
1171 /*-----------------------------------------------------------------*/
1173 matchLine (char *s, char *d, hTab ** vars)
1182 /* skip white space in both */
1183 while (isspace (*s))
1185 while (isspace (*d))
1188 /* if the destination is a var */
1189 if (*d == '%' && isdigit (*(d + 1)) && vars)
1191 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1192 /* if the variable is already bound
1193 then it MUST match with dest */
1201 /* variable not bound we need to
1203 bindVar (keyForVar (d + 1), &s, vars);
1205 /* in either case go past the variable */
1207 while (isdigit (*d))
1210 while (isspace (*s))
1212 while (isspace (*d))
1216 /* they should be an exact match other wise */
1225 /* get rid of the trailing spaces
1226 in both source & destination */
1228 while (isspace (*s))
1232 while (isspace (*d))
1235 /* after all this if only one of them
1236 has something left over then no match */
1243 /*-----------------------------------------------------------------*/
1244 /* matchRule - matches a all the rule lines */
1245 /*-----------------------------------------------------------------*/
1247 matchRule (lineNode * pl,
1252 lineNode *spl; /* source pl */
1253 lineNode *rpl; /* rule peep line */
1255 /* setToNull((void *) &pr->vars); */
1256 /* pr->vars = newHashTable(100); */
1258 /* for all the lines defined in the rule */
1264 /* if the source line starts with a ';' then
1265 comment line don't process or the source line
1266 contains == . debugger information skip it */
1268 (*spl->line == ';' || spl->isDebug))
1274 if (!matchLine (spl->line, rpl->line, &pr->vars))
1282 /* if rules ended */
1285 /* if this rule has additional conditions */
1288 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1307 reassociate_ic_down (lineNode *shead, lineNode *stail,
1308 lineNode *rhead, lineNode *rtail)
1310 lineNode *csl; /* current source line */
1311 lineNode *crl; /* current replacement line */
1317 /* skip over any comments */
1318 while (csl!=stail->next && csl->isComment)
1320 while (crl!=rtail->next && crl->isComment)
1323 /* quit if we reach the end */
1324 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1327 if (matchLine(csl->line,crl->line,NULL))
1339 reassociate_ic_up (lineNode *shead, lineNode *stail,
1340 lineNode *rhead, lineNode *rtail)
1342 lineNode *csl; /* current source line */
1343 lineNode *crl; /* current replacement line */
1349 /* skip over any comments */
1350 while (csl!=shead->prev && csl->isComment)
1352 while (crl!=rhead->prev && crl->isComment)
1355 /* quit if we reach the end */
1356 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1359 if (matchLine(csl->line,crl->line,NULL))
1370 /*------------------------------------------------------------------*/
1371 /* reassociate_ic - reassociate replacement lines with origin iCode */
1372 /*------------------------------------------------------------------*/
1374 reassociate_ic (lineNode *shead, lineNode *stail,
1375 lineNode *rhead, lineNode *rtail)
1377 lineNode *csl; /* current source line */
1378 lineNode *crl; /* current replacement line */
1382 /* Check to see if all the source lines (excluding comments) came
1383 ** for the same iCode
1386 for (csl=shead;csl!=stail->next;csl=csl->next)
1387 if (csl->ic && !csl->isComment)
1392 single_iCode = (ic!=NULL);
1393 for (csl=shead;csl!=stail->next;csl=csl->next)
1394 if ((csl->ic != ic) && !csl->isComment)
1396 /* More than one iCode was found. However, if it's just the
1397 ** last line with the different iCode and it was not changed
1398 ** in the replacement, everything else must be the first iCode.
1400 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1402 rtail->ic = stail->ic;
1403 for (crl=rhead;crl!=rtail;crl=crl->next)
1408 single_iCode = FALSE;
1412 /* If all of the source lines came from the same iCode, then so have
1413 ** all of the replacement lines too.
1417 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1422 /* The source lines span iCodes, so we may end up with replacement
1423 ** lines that we don't know which iCode(s) to associate with. Do the
1424 ** best we can by using the following strategies:
1425 ** 1) Start at the top and scan down. As long as the source line
1426 ** matches the replacement line, they have the same iCode.
1427 ** 2) Start at the bottom and scan up. As long as the source line
1428 ** matches the replacement line, they have the same iCode.
1429 ** 3) For any label in the source, look for a matching label in
1430 ** the replacment. If found, they have the same iCode. From
1431 ** these matching labels, scan down for additional matching
1432 ** lines; if found, they also have the same iCode.
1435 /* Strategy #1: Start at the top and scan down for matches
1437 reassociate_ic_down(shead,stail,rhead,rtail);
1439 /* Strategy #2: Start at the bottom and scan up for matches
1441 reassociate_ic_up(shead,stail,rhead,rtail);
1443 /* Strategy #3: Try to match labels
1448 const char *labelStart;
1451 /* skip over any comments */
1452 while (csl!=stail->next && csl->isComment)
1454 if (csl==stail->next)
1457 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1459 /* found a source line label; look for it in the replacment lines */
1463 while (crl!=rtail->next && crl->isComment)
1465 if (crl==rtail->next)
1467 if (matchLine(csl->line, crl->line, NULL))
1469 reassociate_ic_down(csl,stail,crl,rtail);
1479 /* Try to assign a meaningful iCode to any comment that is missing
1480 one. Since they are comments, it's ok to make mistakes; we are just
1481 trying to improve continuity to simplify other tests.
1484 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1486 if (!crl->ic && ic && crl->isComment)
1493 /*-----------------------------------------------------------------*/
1494 /* replaceRule - does replacement of a matching pattern */
1495 /*-----------------------------------------------------------------*/
1497 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1499 lineNode *cl = NULL;
1500 lineNode *pl = NULL, *lhead = NULL;
1501 /* a long function name and long variable name can evaluate to
1502 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1503 char lb[MAX_PATTERN_LEN*4];
1505 lineNode *comment = NULL;
1507 /* collect all the comment lines in the source */
1508 for (cl = *shead; cl != stail; cl = cl->next)
1510 if (cl->line && (*cl->line == ';' || cl->isDebug))
1512 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1513 (comment = newLineNode (cl->line)));
1514 pl->isDebug = cl->isDebug;
1515 pl->isComment = cl->isComment || (*cl->line == ';');
1520 /* for all the lines in the replacement pattern do */
1521 for (pl = pr->replace; pl; pl = pl->next)
1531 /* if the line contains a variable */
1532 if (*l == '%' && isdigit (*(l + 1)))
1534 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1537 fprintf (stderr, "used unbound variable in replacement\n");
1545 while (isdigit (*l)) {
1555 cl = connectLine (cl, newLineNode (lb));
1557 lhead = cl = newLineNode (lb);
1558 cl->isComment = pl->isComment;
1561 /* add the comments if any to the head of list */
1564 lineNode *lc = comment;
1575 /* determine which iCodes the replacment lines relate to */
1576 reassociate_ic(*shead,stail,lhead,cl);
1578 /* now we need to connect / replace the original chain */
1579 /* if there is a prev then change it */
1582 (*shead)->prev->next = lhead;
1583 lhead->prev = (*shead)->prev;
1586 /* now for the tail */
1587 if (stail && stail->next)
1589 stail->next->prev = cl;
1591 cl->next = stail->next;
1596 /* the replacement is empty - delete the source lines */
1598 (*shead)->prev->next = stail->next;
1600 stail->next->prev = (*shead)->prev;
1601 *shead = stail->next;
1605 /* Returns TRUE if this line is a label definition.
1607 * If so, start will point to the start of the label name,
1608 * and len will be it's length.
1611 isLabelDefinition (const char *line, const char **start, int *len)
1613 const char *cp = line;
1615 /* This line is a label if if consists of:
1616 * [optional whitespace] followed by identifier chars
1617 * (alnum | $ | _ ) followed by a colon.
1620 while (*cp && isspace (*cp))
1632 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1637 if ((cp == *start) || (*cp != ':'))
1642 *len = (cp - (*start));
1646 /* Quick & dirty string hash function. */
1648 hashSymbolName (const char *name)
1654 hash = (hash << 6) ^ *name;
1663 return hash % HTAB_SIZE;
1666 /* Build a hash of all labels in the passed set of lines
1667 * and how many times they are referenced.
1670 buildLabelRefCountHash (lineNode * head)
1677 assert (labelHash == NULL);
1678 labelHash = newHashTable (HTAB_SIZE);
1680 /* First pass: locate all the labels. */
1685 if (isLabelDefinition (line->line, &label, &labelLen)
1686 && labelLen <= SDCC_NAME_MAX)
1688 labelHashEntry *entry;
1690 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1692 memcpy (entry->name, label, labelLen);
1693 entry->name[labelLen] = 0;
1694 entry->refCount = -1;
1696 /* Assume function entry points are referenced somewhere, */
1697 /* even if we can't find a reference (might be from outside */
1699 if (line->ic && (line->ic->op == FUNCTION))
1702 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1708 /* Second pass: for each line, note all the referenced labels. */
1709 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1713 for (i = 0; i < HTAB_SIZE; i++)
1715 labelHashEntry *thisEntry;
1717 thisEntry = hTabFirstItemWK (labelHash, i);
1721 if (strstr (line->line, thisEntry->name))
1723 thisEntry->refCount++;
1725 thisEntry = hTabNextItemWK (labelHash);
1732 /* Spew the contents of the table. Debugging fun only. */
1733 for (i = 0; i < HTAB_SIZE; i++)
1735 labelHashEntry *thisEntry;
1737 thisEntry = hTabFirstItemWK (labelHash, i);
1741 fprintf (stderr, "label: %s ref %d\n",
1742 thisEntry->name, thisEntry->refCount);
1743 thisEntry = hTabNextItemWK (labelHash);
1749 /* How does this work?
1755 replace and restart.
1760 Where is stuff allocated?
1764 /*-----------------------------------------------------------------*/
1765 /* peepHole - matches & substitutes rules */
1766 /*-----------------------------------------------------------------*/
1768 peepHole (lineNode ** pls)
1772 lineNode *mtail = NULL;
1775 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1776 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1777 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1781 assert(labelHash == NULL);
1788 for (pr = rootRules; pr; pr = pr->next)
1790 for (spl = *pls; spl; spl = spl->next)
1792 /* if inline assembler then no peep hole */
1796 /* don't waste time starting a match on debug symbol
1798 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1803 /* Tidy up any data stored in the hTab */
1806 if (matchRule (spl, &mtail, pr, *pls))
1811 replaceRule (pls, mtail, pr);
1813 replaceRule (&spl, mtail, pr);
1815 /* if restart rule type then
1816 start at the top again */
1825 hTabDeleteAll (pr->vars);
1826 Safe_free (pr->vars);
1830 freeTrace (&_G.values);
1833 } while (restart == TRUE);
1837 hTabDeleteAll (labelHash);
1838 freeTrace (&_G.labels);
1844 /*-----------------------------------------------------------------*/
1845 /* readFileIntoBuffer - reads a file into a string buffer */
1846 /*-----------------------------------------------------------------*/
1848 readFileIntoBuffer (char *fname)
1854 char lb[MAX_PATTERN_LEN];
1856 if (!(f = fopen (fname, "r")))
1858 fprintf (stderr, "cannot open peep rule file\n");
1862 while ((ch = fgetc (f)) != EOF)
1866 /* if we maxed out our local buffer */
1867 if (nch >= (MAX_PATTERN_LEN - 2))
1870 /* copy it into allocated buffer */
1873 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1874 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1878 rs = Safe_strdup (lb);
1884 /* if some charaters left over */
1888 /* copy it into allocated buffer */
1891 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1892 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1896 rs = Safe_strdup (lb);
1902 /*-----------------------------------------------------------------*/
1903 /* initPeepHole - initialises the peep hole optimizer stuff */
1904 /*-----------------------------------------------------------------*/
1910 /* read in the default rules */
1911 readRules (port->peep.default_rules);
1913 /* if we have any additional file read it too */
1914 if (options.peep_file)
1916 readRules (s = readFileIntoBuffer (options.peep_file));
1917 setToNull ((void *) &s);
1921 #if !OPT_DISABLE_PIC
1922 /* Convert the peep rules into pcode.
1923 NOTE: this is only support in the PIC port (at the moment)
1926 peepRules2pCode(rootRules);
1929 #if !OPT_DISABLE_PIC16
1930 /* Convert the peep rules into pcode.
1931 NOTE: this is only support in the PIC port (at the moment)
1932 and the PIC16 port (VR 030601)
1934 if (TARGET_IS_PIC16)
1935 pic16_peepRules2pCode(rootRules);