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 &&
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 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
211 for (p = pl->line; *p && isspace(*p); p++)
213 if (strcmp(p, "ret") == 0) return TRUE;
218 /*-----------------------------------------------------------------*/
219 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
220 /* usage of it in the code depends on a value from this section */
221 /*-----------------------------------------------------------------*/
222 FBYNAME (okToRemoveSLOC)
225 const char *sloc, *p;
226 int dummy1, dummy2, dummy3;
228 /* assumes that %1 as the SLOC name */
229 sloc = hTabItemWithKey (vars, 1);
230 if (sloc == NULL) return FALSE;
231 p = strstr(sloc, "sloc");
232 if (p == NULL) return FALSE;
234 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
235 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
236 /* the sloc name begins with that. Probably not really necessary */
238 /* Look for any occurance of this SLOC before the peephole match */
239 for (pl = currPl->prev; pl; pl = pl->prev) {
240 if (pl->line && !pl->isDebug && !pl->isComment
241 && *pl->line != ';' && strstr(pl->line, sloc))
244 /* Look for any occurance of this SLOC after the peephole match */
245 for (pl = endPl->next; pl; pl = pl->next) {
246 if (pl->line && !pl->isDebug && !pl->isComment
247 && *pl->line != ';' && strstr(pl->line, sloc))
250 return TRUE; /* safe for a peephole to remove it :) */
254 /*-----------------------------------------------------------------*/
255 /* operandsNotSame - check if %1 & %2 are the same */
256 /*-----------------------------------------------------------------*/
257 FBYNAME (operandsNotSame)
259 char *op1 = hTabItemWithKey (vars, 1);
260 char *op2 = hTabItemWithKey (vars, 2);
262 if (strcmp (op1, op2) == 0)
268 /*-----------------------------------------------------------------*/
269 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
270 /*-----------------------------------------------------------------*/
271 FBYNAME (operandsNotSame3)
273 char *op1 = hTabItemWithKey (vars, 1);
274 char *op2 = hTabItemWithKey (vars, 2);
275 char *op3 = hTabItemWithKey (vars, 3);
277 if ( (strcmp (op1, op2) == 0) ||
278 (strcmp (op1, op3) == 0) ||
279 (strcmp (op2, op3) == 0) )
285 /*-----------------------------------------------------------------*/
286 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
287 /*-----------------------------------------------------------------*/
288 FBYNAME (operandsNotSame4)
290 char *op1 = hTabItemWithKey (vars, 1);
291 char *op2 = hTabItemWithKey (vars, 2);
292 char *op3 = hTabItemWithKey (vars, 3);
293 char *op4 = hTabItemWithKey (vars, 4);
295 if ( (strcmp (op1, op2) == 0) ||
296 (strcmp (op1, op3) == 0) ||
297 (strcmp (op1, op4) == 0) ||
298 (strcmp (op2, op3) == 0) ||
299 (strcmp (op2, op4) == 0) ||
300 (strcmp (op3, op4) == 0) )
306 /*-----------------------------------------------------------------*/
307 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
308 /*-----------------------------------------------------------------*/
309 FBYNAME (operandsNotSame5)
311 char *op1 = hTabItemWithKey (vars, 1);
312 char *op2 = hTabItemWithKey (vars, 2);
313 char *op3 = hTabItemWithKey (vars, 3);
314 char *op4 = hTabItemWithKey (vars, 4);
315 char *op5 = hTabItemWithKey (vars, 5);
317 if ( (strcmp (op1, op2) == 0) ||
318 (strcmp (op1, op3) == 0) ||
319 (strcmp (op1, op4) == 0) ||
320 (strcmp (op1, op5) == 0) ||
321 (strcmp (op2, op3) == 0) ||
322 (strcmp (op2, op4) == 0) ||
323 (strcmp (op2, op5) == 0) ||
324 (strcmp (op3, op4) == 0) ||
325 (strcmp (op3, op5) == 0) ||
326 (strcmp (op4, op5) == 0) )
332 /*-----------------------------------------------------------------*/
333 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
334 /*-----------------------------------------------------------------*/
335 FBYNAME (operandsNotSame6)
337 char *op1 = hTabItemWithKey (vars, 1);
338 char *op2 = hTabItemWithKey (vars, 2);
339 char *op3 = hTabItemWithKey (vars, 3);
340 char *op4 = hTabItemWithKey (vars, 4);
341 char *op5 = hTabItemWithKey (vars, 5);
342 char *op6 = hTabItemWithKey (vars, 6);
344 if ( (strcmp (op1, op2) == 0) ||
345 (strcmp (op1, op3) == 0) ||
346 (strcmp (op1, op4) == 0) ||
347 (strcmp (op1, op5) == 0) ||
348 (strcmp (op1, op6) == 0) ||
349 (strcmp (op2, op3) == 0) ||
350 (strcmp (op2, op4) == 0) ||
351 (strcmp (op2, op5) == 0) ||
352 (strcmp (op2, op6) == 0) ||
353 (strcmp (op3, op4) == 0) ||
354 (strcmp (op3, op5) == 0) ||
355 (strcmp (op3, op6) == 0) ||
356 (strcmp (op4, op5) == 0) ||
357 (strcmp (op4, op6) == 0) ||
358 (strcmp (op5, op6) == 0) )
365 /*-----------------------------------------------------------------*/
366 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
367 /*-----------------------------------------------------------------*/
368 FBYNAME (operandsNotSame7)
370 char *op1 = hTabItemWithKey (vars, 1);
371 char *op2 = hTabItemWithKey (vars, 2);
372 char *op3 = hTabItemWithKey (vars, 3);
373 char *op4 = hTabItemWithKey (vars, 4);
374 char *op5 = hTabItemWithKey (vars, 5);
375 char *op6 = hTabItemWithKey (vars, 6);
376 char *op7 = hTabItemWithKey (vars, 7);
378 if ( (strcmp (op1, op2) == 0) ||
379 (strcmp (op1, op3) == 0) ||
380 (strcmp (op1, op4) == 0) ||
381 (strcmp (op1, op5) == 0) ||
382 (strcmp (op1, op6) == 0) ||
383 (strcmp (op1, op7) == 0) ||
384 (strcmp (op2, op3) == 0) ||
385 (strcmp (op2, op4) == 0) ||
386 (strcmp (op2, op5) == 0) ||
387 (strcmp (op2, op6) == 0) ||
388 (strcmp (op2, op7) == 0) ||
389 (strcmp (op3, op4) == 0) ||
390 (strcmp (op3, op5) == 0) ||
391 (strcmp (op3, op6) == 0) ||
392 (strcmp (op3, op7) == 0) ||
393 (strcmp (op4, op5) == 0) ||
394 (strcmp (op4, op6) == 0) ||
395 (strcmp (op4, op7) == 0) ||
396 (strcmp (op5, op6) == 0) ||
397 (strcmp (op5, op7) == 0) ||
398 (strcmp (op6, op7) == 0) )
404 /*-----------------------------------------------------------------*/
405 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
406 /*-----------------------------------------------------------------*/
407 FBYNAME (operandsNotSame8)
409 char *op1 = hTabItemWithKey (vars, 1);
410 char *op2 = hTabItemWithKey (vars, 2);
411 char *op3 = hTabItemWithKey (vars, 3);
412 char *op4 = hTabItemWithKey (vars, 4);
413 char *op5 = hTabItemWithKey (vars, 5);
414 char *op6 = hTabItemWithKey (vars, 6);
415 char *op7 = hTabItemWithKey (vars, 7);
416 char *op8 = hTabItemWithKey (vars, 8);
418 if ( (strcmp (op1, op2) == 0) ||
419 (strcmp (op1, op3) == 0) ||
420 (strcmp (op1, op4) == 0) ||
421 (strcmp (op1, op5) == 0) ||
422 (strcmp (op1, op6) == 0) ||
423 (strcmp (op1, op7) == 0) ||
424 (strcmp (op1, op8) == 0) ||
425 (strcmp (op2, op3) == 0) ||
426 (strcmp (op2, op4) == 0) ||
427 (strcmp (op2, op5) == 0) ||
428 (strcmp (op2, op6) == 0) ||
429 (strcmp (op2, op7) == 0) ||
430 (strcmp (op2, op8) == 0) ||
431 (strcmp (op3, op4) == 0) ||
432 (strcmp (op3, op5) == 0) ||
433 (strcmp (op3, op6) == 0) ||
434 (strcmp (op3, op7) == 0) ||
435 (strcmp (op3, op8) == 0) ||
436 (strcmp (op4, op5) == 0) ||
437 (strcmp (op4, op6) == 0) ||
438 (strcmp (op4, op7) == 0) ||
439 (strcmp (op4, op8) == 0) ||
440 (strcmp (op5, op6) == 0) ||
441 (strcmp (op5, op7) == 0) ||
442 (strcmp (op5, op8) == 0) ||
443 (strcmp (op6, op7) == 0) ||
444 (strcmp (op6, op8) == 0) ||
445 (strcmp (op7, op8) == 0) )
454 * takes two parameters: a variable (bound to a label name)
455 * and an expected reference count.
457 * Returns TRUE if that label is defined and referenced exactly
458 * the given number of times.
460 FBYNAME (labelRefCount)
462 int varNumber, expectedRefCount;
465 /* If we don't have the label hash table yet, build it. */
468 buildLabelRefCountHash (head);
471 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
473 char *label = hTabItemWithKey (vars, varNumber);
477 labelHashEntry *entry;
479 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
483 if (!strcmp (label, entry->name))
487 entry = hTabNextItemWK (labelHash);
493 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
494 label, entry->refCount, expectedRefCount);
497 rc = (expectedRefCount == entry->refCount);
501 fprintf (stderr, "*** internal error: no label has entry for"
502 " %s in labelRefCount peephole.\n",
508 fprintf (stderr, "*** internal error: var %d not bound"
509 " in peephole labelRefCount rule.\n",
517 "*** internal error: labelRefCount peephole restriction"
518 " malformed: %s\n", cmdLine);
523 /* Within the context of the lines currPl through endPl, determine
524 ** if the variable var contains a symbol that is volatile. Returns
525 ** TRUE only if it is certain that this was not volatile (the symbol
526 ** was found and not volatile, or var was a constant or CPU register).
527 ** Returns FALSE if the symbol was found and volatile, the symbol was
528 ** not found, or var was a indirect/pointer addressing mode.
531 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
533 char symname[SDCC_NAME_MAX + 1];
540 /* Can't tell if indirect accesses are volatile or not, so
541 ** assume they are, just to be safe.
543 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
548 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
550 if (strstr(var,"(bc)"))
552 if (strstr(var,"(de)"))
554 if (strstr(var,"(hl)"))
556 if (strstr(var,"(ix"))
558 if (strstr(var,"(iy"))
562 /* Extract a symbol name from the variable */
563 while (*vp && (*vp!='_'))
565 while (*vp && (isalnum(*vp) || *vp=='_'))
571 /* Nothing resembling a symbol name was found, so it can't
578 for (cl = currPl; cl!=endPl->next; cl = cl->next)
580 if (cl->ic && (cl->ic!=last_ic))
586 op = IC_COND (cl->ic);
587 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
588 return !op->isvolatile;
590 op = IC_JTCOND (cl->ic);
591 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
592 return !op->isvolatile;
594 op = IC_LEFT (cl->ic);
595 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
596 return !op->isvolatile;
597 op = IC_RIGHT (cl->ic);
598 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
599 return !op->isvolatile;
600 op = IC_RESULT (cl->ic);
601 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
602 return !op->isvolatile;
607 /* Couldn't find the symbol for some reason. Assume volatile. */
613 * This rule restriction has two different behaviours depending on
614 * the number of parameters given.
616 * if notVolatile (no parameters given)
617 * The rule is applied only if none of the iCodes originating
618 * the matched pattern reference a volatile operand.
620 * if notVolatile %1 ... (one or more parameters given)
621 * The rule is applied if the parameters are not expressions
622 * containing volatile symbols and are not pointer accesses.
625 FBYNAME (notVolatile)
636 /* If no parameters given, just scan the iCodes for volatile operands */
637 for (cl = currPl; cl!=endPl->next; cl = cl->next)
644 op = IC_COND (cl->ic);
645 if (IS_SYMOP (op) && op->isvolatile)
648 op = IC_JTCOND (cl->ic);
649 if (IS_SYMOP (op) && op->isvolatile)
652 op = IC_LEFT (cl->ic);
653 if (IS_SYMOP (op) && op->isvolatile)
655 op = IC_RIGHT (cl->ic);
656 if (IS_SYMOP (op) && op->isvolatile)
658 op = IC_RESULT (cl->ic);
659 if (IS_SYMOP (op) && op->isvolatile)
667 /* There were parameters; check the volatility of each */
668 while (*cmdLine && isspace(*cmdLine))
675 if (!isdigit(*cmdLine))
677 varNumber = strtol(cmdLine, &digitend, 10);
679 while (*cmdLine && isspace(*cmdLine))
682 var = hTabItemWithKey (vars, varNumber);
686 notvol = notVolatileVariable (var, currPl, endPl);
692 fprintf (stderr, "*** internal error: var %d not bound"
693 " in peephole notVolatile rule.\n",
704 "*** internal error: notVolatile peephole restriction"
705 " malformed: %s\n", cmdLine);
710 /*-----------------------------------------------------------------*/
711 /* callFuncByName - calls a function as defined in the table */
712 /*-----------------------------------------------------------------*/
714 callFuncByName (char *fname,
723 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
728 "labelInRange", labelInRange
732 "operandsNotSame", operandsNotSame
736 "operandsNotSame3", operandsNotSame3
740 "operandsNotSame4", operandsNotSame4
744 "operandsNotSame5", operandsNotSame5
748 "operandsNotSame6", operandsNotSame6
752 "operandsNotSame7", operandsNotSame7
756 "operandsNotSame8", operandsNotSame8
760 "24bitMode", flat24bitMode
764 "xramMovcOption", xramMovcOption
768 "labelRefCount", labelRefCount
772 "portIsDS390", portIsDS390
775 "labelIsReturnOnly", labelIsReturnOnly
778 "okToRemoveSLOC", okToRemoveSLOC
781 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
784 "notVolatile", notVolatile
788 char *cmdCopy, *funcName, *funcArgs;
791 /* Isolate the function name part (we are passed the full condition
792 * string including arguments)
794 cmdCopy = Safe_strdup(fname);
795 funcName = strtok(cmdCopy, " \t");
796 funcArgs = strtok(NULL, "");
798 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
800 if (strcmp (ftab[i].fname, funcName) == 0)
802 rc = (*ftab[i].func) (vars, currPl, endPl, head,
810 "could not find named function \"%s\" in "
811 "peephole function table\n",
813 // If the function couldn't be found, let's assume it's
814 // a bad rule and refuse it.
823 /*-----------------------------------------------------------------*/
824 /* printLine - prints a line chain into a given file */
825 /*-----------------------------------------------------------------*/
827 printLine (lineNode * head, FILE * of)
829 iCode *last_ic = NULL;
830 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
837 if (head->ic!=last_ic)
840 if (debug_iCode_tracking)
843 fprintf (of, "; block = %d, seq = %d\n",
844 head->ic->block, head->ic->seq);
846 fprintf (of, "; iCode lost\n");
850 /* don't indent comments & labels */
852 (*head->line == ';' ||
853 head->line[strlen (head->line) - 1] == ':')) {
854 fprintf (of, "%s\n", head->line);
856 if (head->isInline && *head->line=='#') {
857 // comment out preprocessor directives in inline asm
860 fprintf (of, "\t%s\n", head->line);
866 /*-----------------------------------------------------------------*/
867 /* newPeepRule - creates a new peeprule and attach it to the root */
868 /*-----------------------------------------------------------------*/
870 newPeepRule (lineNode * match,
877 pr = Safe_alloc ( sizeof (peepRule));
879 pr->replace = replace;
880 pr->restart = restart;
884 pr->cond = Safe_strdup (cond);
889 pr->vars = newHashTable (100);
891 /* if root is empty */
893 rootRules = currRule = pr;
895 currRule = currRule->next = pr;
900 /*-----------------------------------------------------------------*/
901 /* newLineNode - creates a new peep line */
902 /*-----------------------------------------------------------------*/
904 newLineNode (char *line)
908 pl = Safe_alloc ( sizeof (lineNode));
909 pl->line = Safe_strdup (line);
914 /*-----------------------------------------------------------------*/
915 /* connectLine - connects two lines */
916 /*-----------------------------------------------------------------*/
918 connectLine (lineNode * pl1, lineNode * pl2)
922 fprintf (stderr, "trying to connect null line\n");
932 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
933 if (!*x) { fprintf(stderr,y); return ; } }
935 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
936 if (!*x) { fprintf(stderr,z); return ; } }
937 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
938 if (!*x) { fprintf(stderr,z); return ; } }
940 /*-----------------------------------------------------------------*/
941 /* getPeepLine - parses the peep lines */
942 /*-----------------------------------------------------------------*/
944 getPeepLine (lineNode ** head, char **bpp)
946 char lines[MAX_PATTERN_LEN];
949 lineNode *currL = NULL;
956 fprintf (stderr, "unexpected end of match pattern\n");
963 while (isspace (*bp) ||
974 /* read till end of line */
976 while ((*bp != '\n' && *bp != '}') && *bp)
981 *head = currL = newLineNode (lines);
983 currL = connectLine (currL, newLineNode (lines));
986 while (*lp && isspace(*lp))
989 currL->isComment = 1;
995 /*-----------------------------------------------------------------*/
996 /* readRules - reads the rules from a string buffer */
997 /*-----------------------------------------------------------------*/
1002 char lines[MAX_PATTERN_LEN];
1006 lineNode *currL = NULL;
1012 /* look for the token "replace" that is the
1014 while (*bp && strncmp (bp, "replace", 7))
1021 /* then look for either "restart" or '{' */
1022 while (strncmp (bp, "restart", 7) &&
1029 fprintf (stderr, "expected 'restart' or '{'\n");
1037 { /* must be restart */
1039 bp += strlen ("restart");
1041 EXPECT_CHR (bp, '{', "expected '{'\n");
1045 /* skip thru all the blank space */
1046 SKIP_SPACE (bp, "unexpected end of rule\n");
1048 match = replace = currL = NULL;
1049 /* we are the start of a rule */
1050 getPeepLine (&match, &bp);
1052 /* now look for by */
1053 EXPECT_STR (bp, "by", "expected 'by'\n");
1055 /* then look for a '{' */
1056 EXPECT_CHR (bp, '{', "expected '{'\n");
1059 SKIP_SPACE (bp, "unexpected end of rule\n");
1060 getPeepLine (&replace, &bp);
1062 /* look for a 'if' */
1063 while ((isspace (*bp) || *bp == '\n') && *bp)
1066 if (strncmp (bp, "if", 2) == 0)
1069 while ((isspace (*bp) || *bp == '\n') && *bp)
1073 fprintf (stderr, "expected condition name\n");
1077 /* look for the condition */
1079 while (*bp && (*bp != '\n'))
1085 newPeepRule (match, replace, lines, restart);
1088 newPeepRule (match, replace, NULL, restart);
1093 /*-----------------------------------------------------------------*/
1094 /* keyForVar - returns the numeric key for a var */
1095 /*-----------------------------------------------------------------*/
1101 while (isdigit (*d))
1110 /*-----------------------------------------------------------------*/
1111 /* bindVar - binds a value to a variable in the given hashtable */
1112 /*-----------------------------------------------------------------*/
1114 bindVar (int key, char **s, hTab ** vtab)
1116 char vval[MAX_PATTERN_LEN];
1120 /* first get the value of the variable */
1122 /* the value is ended by a ',' or space or newline or null or ) */
1131 /* if we find a '(' then we need to balance it */
1143 // include the trailing ')'
1152 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1154 hTabAddItem (vtab, key, vvx);
1157 /*-----------------------------------------------------------------*/
1158 /* matchLine - matches one line */
1159 /*-----------------------------------------------------------------*/
1161 matchLine (char *s, char *d, hTab ** vars)
1170 /* skip white space in both */
1171 while (isspace (*s))
1173 while (isspace (*d))
1176 /* if the destination is a var */
1177 if (*d == '%' && isdigit (*(d + 1)) && vars)
1179 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1180 /* if the variable is already bound
1181 then it MUST match with dest */
1189 /* variable not bound we need to
1191 bindVar (keyForVar (d + 1), &s, vars);
1193 /* in either case go past the variable */
1195 while (isdigit (*d))
1198 while (isspace (*s))
1200 while (isspace (*d))
1204 /* they should be an exact match other wise */
1213 /* get rid of the trailing spaces
1214 in both source & destination */
1216 while (isspace (*s))
1220 while (isspace (*d))
1223 /* after all this if only one of them
1224 has something left over then no match */
1231 /*-----------------------------------------------------------------*/
1232 /* matchRule - matches a all the rule lines */
1233 /*-----------------------------------------------------------------*/
1235 matchRule (lineNode * pl,
1240 lineNode *spl; /* source pl */
1241 lineNode *rpl; /* rule peep line */
1243 /* setToNull((void *) &pr->vars); */
1244 /* pr->vars = newHashTable(100); */
1246 /* for all the lines defined in the rule */
1252 /* if the source line starts with a ';' then
1253 comment line don't process or the source line
1254 contains == . debugger information skip it */
1256 (*spl->line == ';' || spl->isDebug))
1262 if (!matchLine (spl->line, rpl->line, &pr->vars))
1270 /* if rules ended */
1273 /* if this rule has additional conditions */
1276 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1295 reassociate_ic_down (lineNode *shead, lineNode *stail,
1296 lineNode *rhead, lineNode *rtail)
1298 lineNode *csl; /* current source line */
1299 lineNode *crl; /* current replacement line */
1305 /* skip over any comments */
1306 while (csl!=stail->next && csl->isComment)
1308 while (crl!=rtail->next && crl->isComment)
1311 /* quit if we reach the end */
1312 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1315 if (matchLine(csl->line,crl->line,NULL))
1327 reassociate_ic_up (lineNode *shead, lineNode *stail,
1328 lineNode *rhead, lineNode *rtail)
1330 lineNode *csl; /* current source line */
1331 lineNode *crl; /* current replacement line */
1337 /* skip over any comments */
1338 while (csl!=shead->prev && csl->isComment)
1340 while (crl!=rhead->prev && crl->isComment)
1343 /* quit if we reach the end */
1344 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1347 if (matchLine(csl->line,crl->line,NULL))
1358 /*------------------------------------------------------------------*/
1359 /* reassociate_ic - reassociate replacement lines with origin iCode */
1360 /*------------------------------------------------------------------*/
1362 reassociate_ic (lineNode *shead, lineNode *stail,
1363 lineNode *rhead, lineNode *rtail)
1365 lineNode *csl; /* current source line */
1366 lineNode *crl; /* current replacement line */
1370 /* Check to see if all the source lines (excluding comments) came
1371 ** for the same iCode
1374 for (csl=shead;csl!=stail->next;csl=csl->next)
1375 if (csl->ic && !csl->isComment)
1380 single_iCode = (ic!=NULL);
1381 for (csl=shead;csl!=stail->next;csl=csl->next)
1382 if ((csl->ic != ic) && !csl->isComment)
1384 /* More than one iCode was found. However, if it's just the
1385 ** last line with the different iCode and it was not changed
1386 ** in the replacement, everything else must be the first iCode.
1388 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1390 rtail->ic = stail->ic;
1391 for (crl=rhead;crl!=rtail;crl=crl->next)
1396 single_iCode = FALSE;
1400 /* If all of the source lines came from the same iCode, then so have
1401 ** all of the replacement lines too.
1405 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1410 /* The source lines span iCodes, so we may end up with replacement
1411 ** lines that we don't know which iCode(s) to associate with. Do the
1412 ** best we can by using the following strategies:
1413 ** 1) Start at the top and scan down. As long as the source line
1414 ** matches the replacement line, they have the same iCode.
1415 ** 2) Start at the bottom and scan up. As long as the source line
1416 ** matches the replacement line, they have the same iCode.
1417 ** 3) For any label in the source, look for a matching label in
1418 ** the replacment. If found, they have the same iCode. From
1419 ** these matching labels, scan down for additional matching
1420 ** lines; if found, they also have the same iCode.
1423 /* Strategy #1: Start at the top and scan down for matches
1425 reassociate_ic_down(shead,stail,rhead,rtail);
1427 /* Strategy #2: Start at the bottom and scan up for matches
1429 reassociate_ic_up(shead,stail,rhead,rtail);
1431 /* Strategy #3: Try to match labels
1436 const char *labelStart;
1439 /* skip over any comments */
1440 while (csl!=stail->next && csl->isComment)
1442 if (csl==stail->next)
1445 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1447 /* found a source line label; look for it in the replacment lines */
1451 while (crl!=rtail->next && crl->isComment)
1453 if (crl==rtail->next)
1455 if (matchLine(csl->line, crl->line, NULL))
1457 reassociate_ic_down(csl,stail,crl,rtail);
1467 /* Try to assign a meaningful iCode to any comment that is missing
1468 one. Since they are comments, it's ok to make mistakes; we are just
1469 trying to improve continuity to simplify other tests.
1472 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1474 if (!crl->ic && ic && crl->isComment)
1481 /*-----------------------------------------------------------------*/
1482 /* replaceRule - does replacement of a matching pattern */
1483 /*-----------------------------------------------------------------*/
1485 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1487 lineNode *cl = NULL;
1488 lineNode *pl = NULL, *lhead = NULL;
1489 /* a long function name and long variable name can evaluate to
1490 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1491 char lb[MAX_PATTERN_LEN*4];
1493 lineNode *comment = NULL;
1495 /* collect all the comment lines in the source */
1496 for (cl = *shead; cl != stail; cl = cl->next)
1498 if (cl->line && (*cl->line == ';' || cl->isDebug))
1500 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1501 (comment = newLineNode (cl->line)));
1502 pl->isDebug = cl->isDebug;
1503 pl->isComment = cl->isComment || (*cl->line == ';');
1508 /* for all the lines in the replacement pattern do */
1509 for (pl = pr->replace; pl; pl = pl->next)
1519 /* if the line contains a variable */
1520 if (*l == '%' && isdigit (*(l + 1)))
1522 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1525 fprintf (stderr, "used unbound variable in replacement\n");
1533 while (isdigit (*l)) {
1543 cl = connectLine (cl, newLineNode (lb));
1545 lhead = cl = newLineNode (lb);
1546 cl->isComment = pl->isComment;
1549 /* add the comments if any to the head of list */
1552 lineNode *lc = comment;
1561 /* determine which iCodes the replacment lines relate to */
1562 reassociate_ic(*shead,stail,lhead,cl);
1564 /* now we need to connect / replace the original chain */
1565 /* if there is a prev then change it */
1568 (*shead)->prev->next = lhead;
1569 lhead->prev = (*shead)->prev;
1572 /* now for the tail */
1573 if (stail && stail->next)
1575 stail->next->prev = cl;
1577 cl->next = stail->next;
1581 /* Returns TRUE if this line is a label definition.
1583 * If so, start will point to the start of the label name,
1584 * and len will be it's length.
1587 isLabelDefinition (const char *line, const char **start, int *len)
1589 const char *cp = line;
1591 /* This line is a label if if consists of:
1592 * [optional whitespace] followed by identifier chars
1593 * (alnum | $ | _ ) followed by a colon.
1596 while (*cp && isspace (*cp))
1608 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1613 if ((cp == *start) || (*cp != ':'))
1618 *len = (cp - (*start));
1622 /* Quick & dirty string hash function. */
1624 hashSymbolName (const char *name)
1630 hash = (hash << 6) ^ *name;
1639 return hash % HTAB_SIZE;
1642 /* Build a hash of all labels in the passed set of lines
1643 * and how many times they are referenced.
1646 buildLabelRefCountHash (lineNode * head)
1653 assert (labelHash == NULL);
1654 labelHash = newHashTable (HTAB_SIZE);
1656 /* First pass: locate all the labels. */
1661 if (isLabelDefinition (line->line, &label, &labelLen)
1662 && labelLen <= SDCC_NAME_MAX)
1664 labelHashEntry *entry;
1666 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1668 memcpy (entry->name, label, labelLen);
1669 entry->name[labelLen] = 0;
1670 entry->refCount = -1;
1672 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1678 /* Second pass: for each line, note all the referenced labels. */
1679 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1683 for (i = 0; i < HTAB_SIZE; i++)
1685 labelHashEntry *thisEntry;
1687 thisEntry = hTabFirstItemWK (labelHash, i);
1691 if (strstr (line->line, thisEntry->name))
1693 thisEntry->refCount++;
1695 thisEntry = hTabNextItemWK (labelHash);
1702 /* Spew the contents of the table. Debugging fun only. */
1703 for (i = 0; i < HTAB_SIZE; i++)
1705 labelHashEntry *thisEntry;
1707 thisEntry = hTabFirstItemWK (labelHash, i);
1711 fprintf (stderr, "label: %s ref %d\n",
1712 thisEntry->name, thisEntry->refCount);
1713 thisEntry = hTabNextItemWK (labelHash);
1719 /* How does this work?
1725 replace and restart.
1730 Where is stuff allocated?
1734 /*-----------------------------------------------------------------*/
1735 /* peepHole - matches & substitutes rules */
1736 /*-----------------------------------------------------------------*/
1738 peepHole (lineNode ** pls)
1742 lineNode *mtail = NULL;
1745 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1746 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1747 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1751 assert(labelHash == NULL);
1758 for (pr = rootRules; pr; pr = pr->next)
1760 for (spl = *pls; spl; spl = spl->next)
1762 /* if inline assembler then no peep hole */
1766 /* don't waste time starting a match on debug symbol
1768 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1773 /* Tidy up any data stored in the hTab */
1776 if (matchRule (spl, &mtail, pr, *pls))
1781 replaceRule (pls, mtail, pr);
1783 replaceRule (&spl, mtail, pr);
1785 /* if restart rule type then
1786 start at the top again */
1795 hTabDeleteAll (pr->vars);
1796 Safe_free (pr->vars);
1800 freeTrace (&_G.values);
1803 } while (restart == TRUE);
1807 hTabDeleteAll (labelHash);
1808 freeTrace (&_G.labels);
1814 /*-----------------------------------------------------------------*/
1815 /* readFileIntoBuffer - reads a file into a string buffer */
1816 /*-----------------------------------------------------------------*/
1818 readFileIntoBuffer (char *fname)
1824 char lb[MAX_PATTERN_LEN];
1826 if (!(f = fopen (fname, "r")))
1828 fprintf (stderr, "cannot open peep rule file\n");
1832 while ((ch = fgetc (f)) != EOF)
1836 /* if we maxed out our local buffer */
1837 if (nch >= (MAX_PATTERN_LEN - 2))
1840 /* copy it into allocated buffer */
1843 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1844 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1848 rs = Safe_strdup (lb);
1854 /* if some charaters left over */
1858 /* copy it into allocated buffer */
1861 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1862 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1866 rs = Safe_strdup (lb);
1872 /*-----------------------------------------------------------------*/
1873 /* initPeepHole - initialises the peep hole optimizer stuff */
1874 /*-----------------------------------------------------------------*/
1880 /* read in the default rules */
1881 readRules (port->peep.default_rules);
1883 /* if we have any additional file read it too */
1884 if (options.peep_file)
1886 readRules (s = readFileIntoBuffer (options.peep_file));
1887 setToNull ((void *) &s);
1891 #if !OPT_DISABLE_PIC
1892 /* Convert the peep rules into pcode.
1893 NOTE: this is only support in the PIC port (at the moment)
1896 peepRules2pCode(rootRules);
1899 #if !OPT_DISABLE_PIC16
1900 /* Convert the peep rules into pcode.
1901 NOTE: this is only support in the PIC port (at the moment)
1902 and the PIC16 port (VR 030601)
1904 if (TARGET_IS_PIC16)
1905 pic16_peepRules2pCode(rootRules);