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;
191 label = hTabItemWithKey (vars, 5);
192 if (!label) return FALSE;
195 for(pl = currPl; pl; pl = pl->next) {
196 if (pl->line && !pl->isDebug && !pl->isComment &&
197 pl->line[strlen(pl->line)-1] == ':') {
198 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
199 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
200 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
201 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
202 *(pl->line+5) != '$') {
203 return FALSE; /* non-local label encountered */
207 if (!pl) return FALSE; /* did not find the label */
209 while (pl && (pl->isDebug || pl->isComment))
211 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
213 for (p = pl->line; *p && isspace(*p); p++)
215 if (strcmp(p, "ret") == 0) return TRUE;
220 /*-----------------------------------------------------------------*/
221 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
222 /* usage of it in the code depends on a value from this section */
223 /*-----------------------------------------------------------------*/
224 FBYNAME (okToRemoveSLOC)
227 const char *sloc, *p;
228 int dummy1, dummy2, dummy3;
230 /* assumes that %1 as the SLOC name */
231 sloc = hTabItemWithKey (vars, 1);
232 if (sloc == NULL) return FALSE;
233 p = strstr(sloc, "sloc");
234 if (p == NULL) return FALSE;
236 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
237 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
238 /* the sloc name begins with that. Probably not really necessary */
240 /* Look for any occurance of this SLOC before the peephole match */
241 for (pl = currPl->prev; pl; pl = pl->prev) {
242 if (pl->line && !pl->isDebug && !pl->isComment
243 && *pl->line != ';' && strstr(pl->line, sloc))
246 /* Look for any occurance of this SLOC after the peephole match */
247 for (pl = endPl->next; pl; pl = pl->next) {
248 if (pl->line && !pl->isDebug && !pl->isComment
249 && *pl->line != ';' && strstr(pl->line, sloc))
252 return TRUE; /* safe for a peephole to remove it :) */
256 /*-----------------------------------------------------------------*/
257 /* operandsNotSame - check if %1 & %2 are the same */
258 /*-----------------------------------------------------------------*/
259 FBYNAME (operandsNotSame)
261 char *op1 = hTabItemWithKey (vars, 1);
262 char *op2 = hTabItemWithKey (vars, 2);
264 if (strcmp (op1, op2) == 0)
270 /*-----------------------------------------------------------------*/
271 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
272 /*-----------------------------------------------------------------*/
273 FBYNAME (operandsNotSame3)
275 char *op1 = hTabItemWithKey (vars, 1);
276 char *op2 = hTabItemWithKey (vars, 2);
277 char *op3 = hTabItemWithKey (vars, 3);
279 if ( (strcmp (op1, op2) == 0) ||
280 (strcmp (op1, op3) == 0) ||
281 (strcmp (op2, op3) == 0) )
287 /*-----------------------------------------------------------------*/
288 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
289 /*-----------------------------------------------------------------*/
290 FBYNAME (operandsNotSame4)
292 char *op1 = hTabItemWithKey (vars, 1);
293 char *op2 = hTabItemWithKey (vars, 2);
294 char *op3 = hTabItemWithKey (vars, 3);
295 char *op4 = hTabItemWithKey (vars, 4);
297 if ( (strcmp (op1, op2) == 0) ||
298 (strcmp (op1, op3) == 0) ||
299 (strcmp (op1, op4) == 0) ||
300 (strcmp (op2, op3) == 0) ||
301 (strcmp (op2, op4) == 0) ||
302 (strcmp (op3, op4) == 0) )
308 /*-----------------------------------------------------------------*/
309 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
310 /*-----------------------------------------------------------------*/
311 FBYNAME (operandsNotSame5)
313 char *op1 = hTabItemWithKey (vars, 1);
314 char *op2 = hTabItemWithKey (vars, 2);
315 char *op3 = hTabItemWithKey (vars, 3);
316 char *op4 = hTabItemWithKey (vars, 4);
317 char *op5 = hTabItemWithKey (vars, 5);
319 if ( (strcmp (op1, op2) == 0) ||
320 (strcmp (op1, op3) == 0) ||
321 (strcmp (op1, op4) == 0) ||
322 (strcmp (op1, op5) == 0) ||
323 (strcmp (op2, op3) == 0) ||
324 (strcmp (op2, op4) == 0) ||
325 (strcmp (op2, op5) == 0) ||
326 (strcmp (op3, op4) == 0) ||
327 (strcmp (op3, op5) == 0) ||
328 (strcmp (op4, op5) == 0) )
334 /*-----------------------------------------------------------------*/
335 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
336 /*-----------------------------------------------------------------*/
337 FBYNAME (operandsNotSame6)
339 char *op1 = hTabItemWithKey (vars, 1);
340 char *op2 = hTabItemWithKey (vars, 2);
341 char *op3 = hTabItemWithKey (vars, 3);
342 char *op4 = hTabItemWithKey (vars, 4);
343 char *op5 = hTabItemWithKey (vars, 5);
344 char *op6 = hTabItemWithKey (vars, 6);
346 if ( (strcmp (op1, op2) == 0) ||
347 (strcmp (op1, op3) == 0) ||
348 (strcmp (op1, op4) == 0) ||
349 (strcmp (op1, op5) == 0) ||
350 (strcmp (op1, op6) == 0) ||
351 (strcmp (op2, op3) == 0) ||
352 (strcmp (op2, op4) == 0) ||
353 (strcmp (op2, op5) == 0) ||
354 (strcmp (op2, op6) == 0) ||
355 (strcmp (op3, op4) == 0) ||
356 (strcmp (op3, op5) == 0) ||
357 (strcmp (op3, op6) == 0) ||
358 (strcmp (op4, op5) == 0) ||
359 (strcmp (op4, op6) == 0) ||
360 (strcmp (op5, op6) == 0) )
367 /*-----------------------------------------------------------------*/
368 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
369 /*-----------------------------------------------------------------*/
370 FBYNAME (operandsNotSame7)
372 char *op1 = hTabItemWithKey (vars, 1);
373 char *op2 = hTabItemWithKey (vars, 2);
374 char *op3 = hTabItemWithKey (vars, 3);
375 char *op4 = hTabItemWithKey (vars, 4);
376 char *op5 = hTabItemWithKey (vars, 5);
377 char *op6 = hTabItemWithKey (vars, 6);
378 char *op7 = hTabItemWithKey (vars, 7);
380 if ( (strcmp (op1, op2) == 0) ||
381 (strcmp (op1, op3) == 0) ||
382 (strcmp (op1, op4) == 0) ||
383 (strcmp (op1, op5) == 0) ||
384 (strcmp (op1, op6) == 0) ||
385 (strcmp (op1, op7) == 0) ||
386 (strcmp (op2, op3) == 0) ||
387 (strcmp (op2, op4) == 0) ||
388 (strcmp (op2, op5) == 0) ||
389 (strcmp (op2, op6) == 0) ||
390 (strcmp (op2, op7) == 0) ||
391 (strcmp (op3, op4) == 0) ||
392 (strcmp (op3, op5) == 0) ||
393 (strcmp (op3, op6) == 0) ||
394 (strcmp (op3, op7) == 0) ||
395 (strcmp (op4, op5) == 0) ||
396 (strcmp (op4, op6) == 0) ||
397 (strcmp (op4, op7) == 0) ||
398 (strcmp (op5, op6) == 0) ||
399 (strcmp (op5, op7) == 0) ||
400 (strcmp (op6, op7) == 0) )
406 /*-----------------------------------------------------------------*/
407 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
408 /*-----------------------------------------------------------------*/
409 FBYNAME (operandsNotSame8)
411 char *op1 = hTabItemWithKey (vars, 1);
412 char *op2 = hTabItemWithKey (vars, 2);
413 char *op3 = hTabItemWithKey (vars, 3);
414 char *op4 = hTabItemWithKey (vars, 4);
415 char *op5 = hTabItemWithKey (vars, 5);
416 char *op6 = hTabItemWithKey (vars, 6);
417 char *op7 = hTabItemWithKey (vars, 7);
418 char *op8 = hTabItemWithKey (vars, 8);
420 if ( (strcmp (op1, op2) == 0) ||
421 (strcmp (op1, op3) == 0) ||
422 (strcmp (op1, op4) == 0) ||
423 (strcmp (op1, op5) == 0) ||
424 (strcmp (op1, op6) == 0) ||
425 (strcmp (op1, op7) == 0) ||
426 (strcmp (op1, op8) == 0) ||
427 (strcmp (op2, op3) == 0) ||
428 (strcmp (op2, op4) == 0) ||
429 (strcmp (op2, op5) == 0) ||
430 (strcmp (op2, op6) == 0) ||
431 (strcmp (op2, op7) == 0) ||
432 (strcmp (op2, op8) == 0) ||
433 (strcmp (op3, op4) == 0) ||
434 (strcmp (op3, op5) == 0) ||
435 (strcmp (op3, op6) == 0) ||
436 (strcmp (op3, op7) == 0) ||
437 (strcmp (op3, op8) == 0) ||
438 (strcmp (op4, op5) == 0) ||
439 (strcmp (op4, op6) == 0) ||
440 (strcmp (op4, op7) == 0) ||
441 (strcmp (op4, op8) == 0) ||
442 (strcmp (op5, op6) == 0) ||
443 (strcmp (op5, op7) == 0) ||
444 (strcmp (op5, op8) == 0) ||
445 (strcmp (op6, op7) == 0) ||
446 (strcmp (op6, op8) == 0) ||
447 (strcmp (op7, op8) == 0) )
456 * takes two parameters: a variable (bound to a label name)
457 * and an expected reference count.
459 * Returns TRUE if that label is defined and referenced exactly
460 * the given number of times.
462 FBYNAME (labelRefCount)
464 int varNumber, expectedRefCount;
467 /* If we don't have the label hash table yet, build it. */
470 buildLabelRefCountHash (head);
473 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
475 char *label = hTabItemWithKey (vars, varNumber);
479 labelHashEntry *entry;
481 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
485 if (!strcmp (label, entry->name))
489 entry = hTabNextItemWK (labelHash);
495 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
496 label, entry->refCount, expectedRefCount);
499 rc = (expectedRefCount == entry->refCount);
503 fprintf (stderr, "*** internal error: no label has entry for"
504 " %s in labelRefCount peephole.\n",
510 fprintf (stderr, "*** internal error: var %d not bound"
511 " in peephole labelRefCount rule.\n",
519 "*** internal error: labelRefCount peephole restriction"
520 " malformed: %s\n", cmdLine);
525 /* Within the context of the lines currPl through endPl, determine
526 ** if the variable var contains a symbol that is volatile. Returns
527 ** TRUE only if it is certain that this was not volatile (the symbol
528 ** was found and not volatile, or var was a constant or CPU register).
529 ** Returns FALSE if the symbol was found and volatile, the symbol was
530 ** not found, or var was a indirect/pointer addressing mode.
533 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
535 char symname[SDCC_NAME_MAX + 1];
542 /* Can't tell if indirect accesses are volatile or not, so
543 ** assume they are, just to be safe.
545 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
550 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
552 if (strstr(var,"(bc)"))
554 if (strstr(var,"(de)"))
556 if (strstr(var,"(hl)"))
558 if (strstr(var,"(ix"))
560 if (strstr(var,"(iy"))
564 /* Extract a symbol name from the variable */
565 while (*vp && (*vp!='_'))
567 while (*vp && (isalnum(*vp) || *vp=='_'))
573 /* Nothing resembling a symbol name was found, so it can't
580 for (cl = currPl; cl!=endPl->next; cl = cl->next)
582 if (cl->ic && (cl->ic!=last_ic))
588 op = IC_COND (cl->ic);
589 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
590 return !op->isvolatile;
592 op = IC_JTCOND (cl->ic);
593 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
594 return !op->isvolatile;
596 op = IC_LEFT (cl->ic);
597 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
598 return !op->isvolatile;
599 op = IC_RIGHT (cl->ic);
600 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
601 return !op->isvolatile;
602 op = IC_RESULT (cl->ic);
603 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
604 return !op->isvolatile;
609 /* Couldn't find the symbol for some reason. Assume volatile. */
615 * This rule restriction has two different behaviours depending on
616 * the number of parameters given.
618 * if notVolatile (no parameters given)
619 * The rule is applied only if none of the iCodes originating
620 * the matched pattern reference a volatile operand.
622 * if notVolatile %1 ... (one or more parameters given)
623 * The rule is applied if the parameters are not expressions
624 * containing volatile symbols and are not pointer accesses.
627 FBYNAME (notVolatile)
638 /* If no parameters given, just scan the iCodes for volatile operands */
639 for (cl = currPl; cl!=endPl->next; cl = cl->next)
646 op = IC_COND (cl->ic);
647 if (IS_SYMOP (op) && op->isvolatile)
650 op = IC_JTCOND (cl->ic);
651 if (IS_SYMOP (op) && op->isvolatile)
654 op = IC_LEFT (cl->ic);
655 if (IS_SYMOP (op) && op->isvolatile)
657 op = IC_RIGHT (cl->ic);
658 if (IS_SYMOP (op) && op->isvolatile)
660 op = IC_RESULT (cl->ic);
661 if (IS_SYMOP (op) && op->isvolatile)
669 /* There were parameters; check the volatility of each */
670 while (*cmdLine && isspace(*cmdLine))
677 if (!isdigit(*cmdLine))
679 varNumber = strtol(cmdLine, &digitend, 10);
681 while (*cmdLine && isspace(*cmdLine))
684 var = hTabItemWithKey (vars, varNumber);
688 notvol = notVolatileVariable (var, currPl, endPl);
694 fprintf (stderr, "*** internal error: var %d not bound"
695 " in peephole notVolatile rule.\n",
706 "*** internal error: notVolatile peephole restriction"
707 " malformed: %s\n", cmdLine);
712 /*-----------------------------------------------------------------*/
713 /* callFuncByName - calls a function as defined in the table */
714 /*-----------------------------------------------------------------*/
716 callFuncByName (char *fname,
725 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
730 "labelInRange", labelInRange
734 "operandsNotSame", operandsNotSame
738 "operandsNotSame3", operandsNotSame3
742 "operandsNotSame4", operandsNotSame4
746 "operandsNotSame5", operandsNotSame5
750 "operandsNotSame6", operandsNotSame6
754 "operandsNotSame7", operandsNotSame7
758 "operandsNotSame8", operandsNotSame8
762 "24bitMode", flat24bitMode
766 "xramMovcOption", xramMovcOption
770 "labelRefCount", labelRefCount
774 "portIsDS390", portIsDS390
777 "labelIsReturnOnly", labelIsReturnOnly
780 "okToRemoveSLOC", okToRemoveSLOC
783 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
786 "notVolatile", notVolatile
790 char *cmdCopy, *funcName, *funcArgs;
793 /* Isolate the function name part (we are passed the full condition
794 * string including arguments)
796 cmdCopy = Safe_strdup(fname);
797 funcName = strtok(cmdCopy, " \t");
798 funcArgs = strtok(NULL, "");
800 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
802 if (strcmp (ftab[i].fname, funcName) == 0)
804 rc = (*ftab[i].func) (vars, currPl, endPl, head,
812 "could not find named function \"%s\" in "
813 "peephole function table\n",
815 // If the function couldn't be found, let's assume it's
816 // a bad rule and refuse it.
825 /*-----------------------------------------------------------------*/
826 /* printLine - prints a line chain into a given file */
827 /*-----------------------------------------------------------------*/
829 printLine (lineNode * head, FILE * of)
831 iCode *last_ic = NULL;
832 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
839 if (head->ic!=last_ic)
842 if (debug_iCode_tracking)
845 fprintf (of, "; block = %d, seq = %d\n",
846 head->ic->block, head->ic->seq);
848 fprintf (of, "; iCode lost\n");
852 /* don't indent comments & labels */
854 (*head->line == ';' ||
855 head->line[strlen (head->line) - 1] == ':')) {
856 fprintf (of, "%s\n", head->line);
858 if (head->isInline && *head->line=='#') {
859 // comment out preprocessor directives in inline asm
862 fprintf (of, "\t%s\n", head->line);
868 /*-----------------------------------------------------------------*/
869 /* newPeepRule - creates a new peeprule and attach it to the root */
870 /*-----------------------------------------------------------------*/
872 newPeepRule (lineNode * match,
879 pr = Safe_alloc ( sizeof (peepRule));
881 pr->replace = replace;
882 pr->restart = restart;
886 pr->cond = Safe_strdup (cond);
891 pr->vars = newHashTable (100);
893 /* if root is empty */
895 rootRules = currRule = pr;
897 currRule = currRule->next = pr;
902 /*-----------------------------------------------------------------*/
903 /* newLineNode - creates a new peep line */
904 /*-----------------------------------------------------------------*/
906 newLineNode (char *line)
910 pl = Safe_alloc ( sizeof (lineNode));
911 pl->line = Safe_strdup (line);
916 /*-----------------------------------------------------------------*/
917 /* connectLine - connects two lines */
918 /*-----------------------------------------------------------------*/
920 connectLine (lineNode * pl1, lineNode * pl2)
924 fprintf (stderr, "trying to connect null line\n");
934 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
935 if (!*x) { fprintf(stderr,y); return ; } }
937 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
938 if (!*x) { fprintf(stderr,z); return ; } }
939 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
940 if (!*x) { fprintf(stderr,z); return ; } }
942 /*-----------------------------------------------------------------*/
943 /* getPeepLine - parses the peep lines */
944 /*-----------------------------------------------------------------*/
946 getPeepLine (lineNode ** head, char **bpp)
948 char lines[MAX_PATTERN_LEN];
952 lineNode *currL = NULL;
959 fprintf (stderr, "unexpected end of match pattern\n");
966 while (isspace (*bp) ||
977 /* read till end of line */
979 while ((*bp != '\n' && *bp != '}') && *bp)
984 while (*lp && isspace(*lp))
986 isComment = (*lp == ';');
988 if (!isComment || (isComment && !options.noPeepComments))
991 *head = currL = newLineNode (lines);
993 currL = connectLine (currL, newLineNode (lines));
994 currL->isComment = isComment;
1002 /*-----------------------------------------------------------------*/
1003 /* readRules - reads the rules from a string buffer */
1004 /*-----------------------------------------------------------------*/
1006 readRules (char *bp)
1009 char lines[MAX_PATTERN_LEN];
1013 lineNode *currL = NULL;
1019 /* look for the token "replace" that is the
1021 while (*bp && strncmp (bp, "replace", 7))
1028 /* then look for either "restart" or '{' */
1029 while (strncmp (bp, "restart", 7) &&
1036 fprintf (stderr, "expected 'restart' or '{'\n");
1044 { /* must be restart */
1046 bp += strlen ("restart");
1048 EXPECT_CHR (bp, '{', "expected '{'\n");
1052 /* skip thru all the blank space */
1053 SKIP_SPACE (bp, "unexpected end of rule\n");
1055 match = replace = currL = NULL;
1056 /* we are the start of a rule */
1057 getPeepLine (&match, &bp);
1059 /* now look for by */
1060 EXPECT_STR (bp, "by", "expected 'by'\n");
1062 /* then look for a '{' */
1063 EXPECT_CHR (bp, '{', "expected '{'\n");
1066 SKIP_SPACE (bp, "unexpected end of rule\n");
1067 getPeepLine (&replace, &bp);
1069 /* look for a 'if' */
1070 while ((isspace (*bp) || *bp == '\n') && *bp)
1073 if (strncmp (bp, "if", 2) == 0)
1076 while ((isspace (*bp) || *bp == '\n') && *bp)
1080 fprintf (stderr, "expected condition name\n");
1084 /* look for the condition */
1086 while (*bp && (*bp != '\n'))
1092 newPeepRule (match, replace, lines, restart);
1095 newPeepRule (match, replace, NULL, restart);
1100 /*-----------------------------------------------------------------*/
1101 /* keyForVar - returns the numeric key for a var */
1102 /*-----------------------------------------------------------------*/
1108 while (isdigit (*d))
1117 /*-----------------------------------------------------------------*/
1118 /* bindVar - binds a value to a variable in the given hashtable */
1119 /*-----------------------------------------------------------------*/
1121 bindVar (int key, char **s, hTab ** vtab)
1123 char vval[MAX_PATTERN_LEN];
1127 /* first get the value of the variable */
1129 /* the value is ended by a ',' or space or newline or null or ) */
1138 /* if we find a '(' then we need to balance it */
1150 // include the trailing ')'
1159 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1161 hTabAddItem (vtab, key, vvx);
1164 /*-----------------------------------------------------------------*/
1165 /* matchLine - matches one line */
1166 /*-----------------------------------------------------------------*/
1168 matchLine (char *s, char *d, hTab ** vars)
1177 /* skip white space in both */
1178 while (isspace (*s))
1180 while (isspace (*d))
1183 /* if the destination is a var */
1184 if (*d == '%' && isdigit (*(d + 1)) && vars)
1186 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1187 /* if the variable is already bound
1188 then it MUST match with dest */
1196 /* variable not bound we need to
1198 bindVar (keyForVar (d + 1), &s, vars);
1200 /* in either case go past the variable */
1202 while (isdigit (*d))
1205 while (isspace (*s))
1207 while (isspace (*d))
1211 /* they should be an exact match other wise */
1220 /* get rid of the trailing spaces
1221 in both source & destination */
1223 while (isspace (*s))
1227 while (isspace (*d))
1230 /* after all this if only one of them
1231 has something left over then no match */
1238 /*-----------------------------------------------------------------*/
1239 /* matchRule - matches a all the rule lines */
1240 /*-----------------------------------------------------------------*/
1242 matchRule (lineNode * pl,
1247 lineNode *spl; /* source pl */
1248 lineNode *rpl; /* rule peep line */
1250 /* setToNull((void *) &pr->vars); */
1251 /* pr->vars = newHashTable(100); */
1253 /* for all the lines defined in the rule */
1259 /* if the source line starts with a ';' then
1260 comment line don't process or the source line
1261 contains == . debugger information skip it */
1263 (*spl->line == ';' || spl->isDebug))
1269 if (!matchLine (spl->line, rpl->line, &pr->vars))
1277 /* if rules ended */
1280 /* if this rule has additional conditions */
1283 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1302 reassociate_ic_down (lineNode *shead, lineNode *stail,
1303 lineNode *rhead, lineNode *rtail)
1305 lineNode *csl; /* current source line */
1306 lineNode *crl; /* current replacement line */
1312 /* skip over any comments */
1313 while (csl!=stail->next && csl->isComment)
1315 while (crl!=rtail->next && crl->isComment)
1318 /* quit if we reach the end */
1319 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1322 if (matchLine(csl->line,crl->line,NULL))
1334 reassociate_ic_up (lineNode *shead, lineNode *stail,
1335 lineNode *rhead, lineNode *rtail)
1337 lineNode *csl; /* current source line */
1338 lineNode *crl; /* current replacement line */
1344 /* skip over any comments */
1345 while (csl!=shead->prev && csl->isComment)
1347 while (crl!=rhead->prev && crl->isComment)
1350 /* quit if we reach the end */
1351 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1354 if (matchLine(csl->line,crl->line,NULL))
1365 /*------------------------------------------------------------------*/
1366 /* reassociate_ic - reassociate replacement lines with origin iCode */
1367 /*------------------------------------------------------------------*/
1369 reassociate_ic (lineNode *shead, lineNode *stail,
1370 lineNode *rhead, lineNode *rtail)
1372 lineNode *csl; /* current source line */
1373 lineNode *crl; /* current replacement line */
1377 /* Check to see if all the source lines (excluding comments) came
1378 ** for the same iCode
1381 for (csl=shead;csl!=stail->next;csl=csl->next)
1382 if (csl->ic && !csl->isComment)
1387 single_iCode = (ic!=NULL);
1388 for (csl=shead;csl!=stail->next;csl=csl->next)
1389 if ((csl->ic != ic) && !csl->isComment)
1391 /* More than one iCode was found. However, if it's just the
1392 ** last line with the different iCode and it was not changed
1393 ** in the replacement, everything else must be the first iCode.
1395 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1397 rtail->ic = stail->ic;
1398 for (crl=rhead;crl!=rtail;crl=crl->next)
1403 single_iCode = FALSE;
1407 /* If all of the source lines came from the same iCode, then so have
1408 ** all of the replacement lines too.
1412 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1417 /* The source lines span iCodes, so we may end up with replacement
1418 ** lines that we don't know which iCode(s) to associate with. Do the
1419 ** best we can by using the following strategies:
1420 ** 1) Start at the top and scan down. As long as the source line
1421 ** matches the replacement line, they have the same iCode.
1422 ** 2) Start at the bottom and scan up. As long as the source line
1423 ** matches the replacement line, they have the same iCode.
1424 ** 3) For any label in the source, look for a matching label in
1425 ** the replacment. If found, they have the same iCode. From
1426 ** these matching labels, scan down for additional matching
1427 ** lines; if found, they also have the same iCode.
1430 /* Strategy #1: Start at the top and scan down for matches
1432 reassociate_ic_down(shead,stail,rhead,rtail);
1434 /* Strategy #2: Start at the bottom and scan up for matches
1436 reassociate_ic_up(shead,stail,rhead,rtail);
1438 /* Strategy #3: Try to match labels
1443 const char *labelStart;
1446 /* skip over any comments */
1447 while (csl!=stail->next && csl->isComment)
1449 if (csl==stail->next)
1452 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1454 /* found a source line label; look for it in the replacment lines */
1458 while (crl!=rtail->next && crl->isComment)
1460 if (crl==rtail->next)
1462 if (matchLine(csl->line, crl->line, NULL))
1464 reassociate_ic_down(csl,stail,crl,rtail);
1474 /* Try to assign a meaningful iCode to any comment that is missing
1475 one. Since they are comments, it's ok to make mistakes; we are just
1476 trying to improve continuity to simplify other tests.
1479 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1481 if (!crl->ic && ic && crl->isComment)
1488 /*-----------------------------------------------------------------*/
1489 /* replaceRule - does replacement of a matching pattern */
1490 /*-----------------------------------------------------------------*/
1492 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1494 lineNode *cl = NULL;
1495 lineNode *pl = NULL, *lhead = NULL;
1496 /* a long function name and long variable name can evaluate to
1497 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1498 char lb[MAX_PATTERN_LEN*4];
1500 lineNode *comment = NULL;
1502 /* collect all the comment lines in the source */
1503 for (cl = *shead; cl != stail; cl = cl->next)
1505 if (cl->line && (*cl->line == ';' || cl->isDebug))
1507 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1508 (comment = newLineNode (cl->line)));
1509 pl->isDebug = cl->isDebug;
1510 pl->isComment = cl->isComment || (*cl->line == ';');
1515 /* for all the lines in the replacement pattern do */
1516 for (pl = pr->replace; pl; pl = pl->next)
1526 /* if the line contains a variable */
1527 if (*l == '%' && isdigit (*(l + 1)))
1529 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1532 fprintf (stderr, "used unbound variable in replacement\n");
1540 while (isdigit (*l)) {
1550 cl = connectLine (cl, newLineNode (lb));
1552 lhead = cl = newLineNode (lb);
1553 cl->isComment = pl->isComment;
1556 /* add the comments if any to the head of list */
1559 lineNode *lc = comment;
1570 /* determine which iCodes the replacment lines relate to */
1571 reassociate_ic(*shead,stail,lhead,cl);
1573 /* now we need to connect / replace the original chain */
1574 /* if there is a prev then change it */
1577 (*shead)->prev->next = lhead;
1578 lhead->prev = (*shead)->prev;
1581 /* now for the tail */
1582 if (stail && stail->next)
1584 stail->next->prev = cl;
1586 cl->next = stail->next;
1591 /* the replacement is empty - delete the source lines */
1593 (*shead)->prev->next = stail->next;
1595 stail->next->prev = (*shead)->prev;
1596 *shead = stail->next;
1600 /* Returns TRUE if this line is a label definition.
1602 * If so, start will point to the start of the label name,
1603 * and len will be it's length.
1606 isLabelDefinition (const char *line, const char **start, int *len)
1608 const char *cp = line;
1610 /* This line is a label if if consists of:
1611 * [optional whitespace] followed by identifier chars
1612 * (alnum | $ | _ ) followed by a colon.
1615 while (*cp && isspace (*cp))
1627 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1632 if ((cp == *start) || (*cp != ':'))
1637 *len = (cp - (*start));
1641 /* Quick & dirty string hash function. */
1643 hashSymbolName (const char *name)
1649 hash = (hash << 6) ^ *name;
1658 return hash % HTAB_SIZE;
1661 /* Build a hash of all labels in the passed set of lines
1662 * and how many times they are referenced.
1665 buildLabelRefCountHash (lineNode * head)
1672 assert (labelHash == NULL);
1673 labelHash = newHashTable (HTAB_SIZE);
1675 /* First pass: locate all the labels. */
1680 if (isLabelDefinition (line->line, &label, &labelLen)
1681 && labelLen <= SDCC_NAME_MAX)
1683 labelHashEntry *entry;
1685 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1687 memcpy (entry->name, label, labelLen);
1688 entry->name[labelLen] = 0;
1689 entry->refCount = -1;
1691 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1697 /* Second pass: for each line, note all the referenced labels. */
1698 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1702 for (i = 0; i < HTAB_SIZE; i++)
1704 labelHashEntry *thisEntry;
1706 thisEntry = hTabFirstItemWK (labelHash, i);
1710 if (strstr (line->line, thisEntry->name))
1712 thisEntry->refCount++;
1714 thisEntry = hTabNextItemWK (labelHash);
1721 /* Spew the contents of the table. Debugging fun only. */
1722 for (i = 0; i < HTAB_SIZE; i++)
1724 labelHashEntry *thisEntry;
1726 thisEntry = hTabFirstItemWK (labelHash, i);
1730 fprintf (stderr, "label: %s ref %d\n",
1731 thisEntry->name, thisEntry->refCount);
1732 thisEntry = hTabNextItemWK (labelHash);
1738 /* How does this work?
1744 replace and restart.
1749 Where is stuff allocated?
1753 /*-----------------------------------------------------------------*/
1754 /* peepHole - matches & substitutes rules */
1755 /*-----------------------------------------------------------------*/
1757 peepHole (lineNode ** pls)
1761 lineNode *mtail = NULL;
1764 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1765 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1766 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1770 assert(labelHash == NULL);
1777 for (pr = rootRules; pr; pr = pr->next)
1779 for (spl = *pls; spl; spl = spl->next)
1781 /* if inline assembler then no peep hole */
1785 /* don't waste time starting a match on debug symbol
1787 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1792 /* Tidy up any data stored in the hTab */
1795 if (matchRule (spl, &mtail, pr, *pls))
1800 replaceRule (pls, mtail, pr);
1802 replaceRule (&spl, mtail, pr);
1804 /* if restart rule type then
1805 start at the top again */
1814 hTabDeleteAll (pr->vars);
1815 Safe_free (pr->vars);
1819 freeTrace (&_G.values);
1822 } while (restart == TRUE);
1826 hTabDeleteAll (labelHash);
1827 freeTrace (&_G.labels);
1833 /*-----------------------------------------------------------------*/
1834 /* readFileIntoBuffer - reads a file into a string buffer */
1835 /*-----------------------------------------------------------------*/
1837 readFileIntoBuffer (char *fname)
1843 char lb[MAX_PATTERN_LEN];
1845 if (!(f = fopen (fname, "r")))
1847 fprintf (stderr, "cannot open peep rule file\n");
1851 while ((ch = fgetc (f)) != EOF)
1855 /* if we maxed out our local buffer */
1856 if (nch >= (MAX_PATTERN_LEN - 2))
1859 /* copy it into allocated buffer */
1862 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1863 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1867 rs = Safe_strdup (lb);
1873 /* if some charaters left over */
1877 /* copy it into allocated buffer */
1880 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1881 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1885 rs = Safe_strdup (lb);
1891 /*-----------------------------------------------------------------*/
1892 /* initPeepHole - initialises the peep hole optimizer stuff */
1893 /*-----------------------------------------------------------------*/
1899 /* read in the default rules */
1900 readRules (port->peep.default_rules);
1902 /* if we have any additional file read it too */
1903 if (options.peep_file)
1905 readRules (s = readFileIntoBuffer (options.peep_file));
1906 setToNull ((void *) &s);
1910 #if !OPT_DISABLE_PIC
1911 /* Convert the peep rules into pcode.
1912 NOTE: this is only support in the PIC port (at the moment)
1915 peepRules2pCode(rootRules);
1918 #if !OPT_DISABLE_PIC16
1919 /* Convert the peep rules into pcode.
1920 NOTE: this is only support in the PIC port (at the moment)
1921 and the PIC16 port (VR 030601)
1923 if (TARGET_IS_PIC16)
1924 pic16_peepRules2pCode(rootRules);