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 **);
52 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
53 lineNode *head, const char *cmdLine)
56 void peepRules2pCode(peepRule *);
59 /*-----------------------------------------------------------------*/
60 /* pcDistance - afinds a label back ward or forward */
61 /*-----------------------------------------------------------------*/
63 mcs51_instruction_size(const char *inst)
65 char *op, op1[256], op2[256];
69 while (*inst && isspace(*inst)) inst++;
71 #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
72 if (ISINST("lcall")) return 3;
73 if (ISINST("ret")) return 1;
74 if (ISINST("ljmp")) return 3;
75 if (ISINST("sjmp")) return 2;
76 if (ISINST("rlc")) return 1;
77 if (ISINST("rrc")) return 1;
78 if (ISINST("rl")) return 1;
79 if (ISINST("rr")) return 1;
80 if (ISINST("swap")) return 1;
81 if (ISINST("movx")) return 1;
82 if (ISINST("movc")) return 1;
83 if (ISINST("push")) return 2;
84 if (ISINST("pop")) return 2;
85 if (ISINST("jc")) return 2;
86 if (ISINST("jnc")) return 2;
87 if (ISINST("jb")) return 3;
88 if (ISINST("jnb")) return 3;
89 if (ISINST("jbc")) return 3;
90 if (ISINST("jmp")) return 1; // always jmp @a+dptr
91 if (ISINST("jz")) return 2;
92 if (ISINST("jnz")) return 2;
93 if (ISINST("cjne")) return 3;
94 if (ISINST("mul")) return 1;
95 if (ISINST("div")) return 1;
96 if (ISINST("da")) return 1;
97 if (ISINST("xchd")) return 1;
98 if (ISINST("reti")) return 1;
99 if (ISINST("nop")) return 1;
100 if (ISINST("acall")) return 1;
101 if (ISINST("ajmp")) return 2;
104 while (*p && isalnum(*p)) p++;
105 for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
106 if (!isspace(*p)) *op++ = *p, opsize++;
110 for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
111 if (!isspace(*p)) *op++ = *p, opsize++;
115 #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
116 #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
117 #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
118 #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
121 if (IS_C(op1) || IS_C(op2)) return 2;
123 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
126 if (IS_Rn(op1) || IS_atRi(op1)) {
127 if (IS_A(op2)) return 1;
130 if (strcmp(op1, "dptr") == 0) return 3;
131 if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
134 if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
135 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
138 if (ISINST("inc") || ISINST("dec")) {
139 if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
140 if (strcmp(op1, "dptr") == 0) return 1;
143 if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
144 if (IS_C(op1)) return 2;
146 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
149 if (IS_A(op2)) return 2;
153 if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
154 if (IS_A(op1) || IS_C(op1)) return 1;
157 if (ISINST("djnz")) {
158 if (IS_Rn(op1)) return 2;
162 if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
163 /* ignore ar0 = 0x00 type definitions */
167 fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
172 pcDistance (lineNode * cpos, char *lbl, bool back)
175 char buff[MAX_PATTERN_LEN];
178 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
184 pl->line[strlen (pl->line) - 1] != ':' &&
186 if (strcmp(port->target,"mcs51") == 0) {
187 dist += mcs51_instruction_size(pl->line);
193 if (strncmp (pl->line, buff, strlen (buff)) == 0)
205 /*-----------------------------------------------------------------*/
206 /* flat24bitModeAndPortDS390 - */
207 /*-----------------------------------------------------------------*/
208 FBYNAME (flat24bitModeAndPortDS390)
210 return ((strcmp(port->target,"ds390") == 0) &&
211 (options.model == MODEL_FLAT24));
214 /*-----------------------------------------------------------------*/
215 /* portIsDS390 - return true if port is DS390 */
216 /*-----------------------------------------------------------------*/
217 FBYNAME (portIsDS390)
219 return (strcmp(port->target,"ds390") == 0);
222 /*-----------------------------------------------------------------*/
223 /* flat24bitMode - will check to see if we are in flat24 mode */
224 /*-----------------------------------------------------------------*/
225 FBYNAME (flat24bitMode)
227 return (options.model == MODEL_FLAT24);
230 /*-----------------------------------------------------------------*/
231 /* xramMovcOption - check if using movc to read xram */
232 /*-----------------------------------------------------------------*/
233 FBYNAME (xramMovcOption)
235 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
243 /*-----------------------------------------------------------------*/
244 /* labelInRange - will check to see if label %5 is within range */
245 /*-----------------------------------------------------------------*/
246 FBYNAME (labelInRange)
248 /* assumes that %5 pattern variable has the label name */
249 char *lbl = hTabItemWithKey (vars, 5);
255 /* if the previous two instructions are "ljmp"s then don't
256 do it since it can be part of a jump table */
257 if (currPl->prev && currPl->prev->prev &&
258 strstr (currPl->prev->line, "ljmp") &&
259 strstr (currPl->prev->prev->line, "ljmp"))
262 /* calculate the label distance : the jump for reladdr can be
263 +/- 127 bytes, here Iam assuming that an average 8051
264 instruction is 2 bytes long, so if the label is more than
265 63 intructions away, the label is considered out of range
266 for a relative jump. we could get more precise this will
267 suffice for now since it catches > 90% cases */
268 dist = (pcDistance (currPl, lbl, TRUE) +
269 pcDistance (currPl, lbl, FALSE));
271 /* changed to 127, now that pcDistance return actual number of bytes */
272 if (!dist || dist > 127)
278 /*-----------------------------------------------------------------*/
279 /* labelIsReturnOnly - Check if label %5 is followed by RET */
280 /*-----------------------------------------------------------------*/
281 FBYNAME (labelIsReturnOnly)
283 /* assumes that %5 pattern variable has the label name */
284 const char *label, *p;
288 label = hTabItemWithKey (vars, 5);
289 if (!label) return FALSE;
292 for(pl = currPl; pl; pl = pl->next) {
293 if (pl->line && !pl->isDebug &&
294 pl->line[strlen(pl->line)-1] == ':') {
295 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
296 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
297 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
298 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
299 *(pl->line+5) != '$') {
300 return FALSE; /* non-local label encountered */
304 if (!pl) return FALSE; /* did not find the label */
306 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
308 for (p = pl->line; *p && isspace(*p); p++)
310 if (strcmp(p, "ret") == 0) return TRUE;
315 /*-----------------------------------------------------------------*/
316 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
317 /* usage of it in the code depends on a value from this section */
318 /*-----------------------------------------------------------------*/
319 FBYNAME (okToRemoveSLOC)
322 const char *sloc, *p;
323 int dummy1, dummy2, dummy3;
325 /* assumes that %1 as the SLOC name */
326 sloc = hTabItemWithKey (vars, 1);
327 if (sloc == NULL) return FALSE;
328 p = strstr(sloc, "sloc");
329 if (p == NULL) return FALSE;
331 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
332 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
333 /* the sloc name begins with that. Probably not really necessary */
335 /* Look for any occurance of this SLOC before the peephole match */
336 for (pl = currPl->prev; pl; pl = pl->prev) {
337 if (pl->line && !pl->isDebug && !pl->isComment
338 && *pl->line != ';' && strstr(pl->line, sloc))
341 /* Look for any occurance of this SLOC after the peephole match */
342 for (pl = endPl->next; pl; pl = pl->next) {
343 if (pl->line && !pl->isDebug && !pl->isComment
344 && *pl->line != ';' && strstr(pl->line, sloc))
347 return TRUE; /* safe for a peephole to remove it :) */
351 /*-----------------------------------------------------------------*/
352 /* operandsNotSame - check if %1 & %2 are the same */
353 /*-----------------------------------------------------------------*/
354 FBYNAME (operandsNotSame)
356 char *op1 = hTabItemWithKey (vars, 1);
357 char *op2 = hTabItemWithKey (vars, 2);
359 if (strcmp (op1, op2) == 0)
365 /*-----------------------------------------------------------------*/
366 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
367 /*-----------------------------------------------------------------*/
368 FBYNAME (operandsNotSame3)
370 char *op1 = hTabItemWithKey (vars, 1);
371 char *op2 = hTabItemWithKey (vars, 2);
372 char *op3 = hTabItemWithKey (vars, 3);
374 if ( (strcmp (op1, op2) == 0) ||
375 (strcmp (op1, op3) == 0) ||
376 (strcmp (op2, op3) == 0) )
382 /*-----------------------------------------------------------------*/
383 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
384 /*-----------------------------------------------------------------*/
385 FBYNAME (operandsNotSame4)
387 char *op1 = hTabItemWithKey (vars, 1);
388 char *op2 = hTabItemWithKey (vars, 2);
389 char *op3 = hTabItemWithKey (vars, 3);
390 char *op4 = hTabItemWithKey (vars, 4);
392 if ( (strcmp (op1, op2) == 0) ||
393 (strcmp (op1, op3) == 0) ||
394 (strcmp (op1, op4) == 0) ||
395 (strcmp (op2, op3) == 0) ||
396 (strcmp (op2, op4) == 0) ||
397 (strcmp (op3, op4) == 0) )
403 /*-----------------------------------------------------------------*/
404 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
405 /*-----------------------------------------------------------------*/
406 FBYNAME (operandsNotSame5)
408 char *op1 = hTabItemWithKey (vars, 1);
409 char *op2 = hTabItemWithKey (vars, 2);
410 char *op3 = hTabItemWithKey (vars, 3);
411 char *op4 = hTabItemWithKey (vars, 4);
412 char *op5 = hTabItemWithKey (vars, 5);
414 if ( (strcmp (op1, op2) == 0) ||
415 (strcmp (op1, op3) == 0) ||
416 (strcmp (op1, op4) == 0) ||
417 (strcmp (op1, op5) == 0) ||
418 (strcmp (op2, op3) == 0) ||
419 (strcmp (op2, op4) == 0) ||
420 (strcmp (op2, op5) == 0) ||
421 (strcmp (op3, op4) == 0) ||
422 (strcmp (op3, op5) == 0) ||
423 (strcmp (op4, op5) == 0) )
429 /*-----------------------------------------------------------------*/
430 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
431 /*-----------------------------------------------------------------*/
432 FBYNAME (operandsNotSame6)
434 char *op1 = hTabItemWithKey (vars, 1);
435 char *op2 = hTabItemWithKey (vars, 2);
436 char *op3 = hTabItemWithKey (vars, 3);
437 char *op4 = hTabItemWithKey (vars, 4);
438 char *op5 = hTabItemWithKey (vars, 5);
439 char *op6 = hTabItemWithKey (vars, 6);
441 if ( (strcmp (op1, op2) == 0) ||
442 (strcmp (op1, op3) == 0) ||
443 (strcmp (op1, op4) == 0) ||
444 (strcmp (op1, op5) == 0) ||
445 (strcmp (op1, op6) == 0) ||
446 (strcmp (op2, op3) == 0) ||
447 (strcmp (op2, op4) == 0) ||
448 (strcmp (op2, op5) == 0) ||
449 (strcmp (op2, op6) == 0) ||
450 (strcmp (op3, op4) == 0) ||
451 (strcmp (op3, op5) == 0) ||
452 (strcmp (op3, op6) == 0) ||
453 (strcmp (op4, op5) == 0) ||
454 (strcmp (op4, op6) == 0) ||
455 (strcmp (op5, op6) == 0) )
462 /*-----------------------------------------------------------------*/
463 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
464 /*-----------------------------------------------------------------*/
465 FBYNAME (operandsNotSame7)
467 char *op1 = hTabItemWithKey (vars, 1);
468 char *op2 = hTabItemWithKey (vars, 2);
469 char *op3 = hTabItemWithKey (vars, 3);
470 char *op4 = hTabItemWithKey (vars, 4);
471 char *op5 = hTabItemWithKey (vars, 5);
472 char *op6 = hTabItemWithKey (vars, 6);
473 char *op7 = hTabItemWithKey (vars, 7);
475 if ( (strcmp (op1, op2) == 0) ||
476 (strcmp (op1, op3) == 0) ||
477 (strcmp (op1, op4) == 0) ||
478 (strcmp (op1, op5) == 0) ||
479 (strcmp (op1, op6) == 0) ||
480 (strcmp (op1, op7) == 0) ||
481 (strcmp (op2, op3) == 0) ||
482 (strcmp (op2, op4) == 0) ||
483 (strcmp (op2, op5) == 0) ||
484 (strcmp (op2, op6) == 0) ||
485 (strcmp (op2, op7) == 0) ||
486 (strcmp (op3, op4) == 0) ||
487 (strcmp (op3, op5) == 0) ||
488 (strcmp (op3, op6) == 0) ||
489 (strcmp (op3, op7) == 0) ||
490 (strcmp (op4, op5) == 0) ||
491 (strcmp (op4, op6) == 0) ||
492 (strcmp (op4, op7) == 0) ||
493 (strcmp (op5, op6) == 0) ||
494 (strcmp (op5, op7) == 0) ||
495 (strcmp (op6, op7) == 0) )
501 /*-----------------------------------------------------------------*/
502 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
503 /*-----------------------------------------------------------------*/
504 FBYNAME (operandsNotSame8)
506 char *op1 = hTabItemWithKey (vars, 1);
507 char *op2 = hTabItemWithKey (vars, 2);
508 char *op3 = hTabItemWithKey (vars, 3);
509 char *op4 = hTabItemWithKey (vars, 4);
510 char *op5 = hTabItemWithKey (vars, 5);
511 char *op6 = hTabItemWithKey (vars, 6);
512 char *op7 = hTabItemWithKey (vars, 7);
513 char *op8 = hTabItemWithKey (vars, 8);
515 if ( (strcmp (op1, op2) == 0) ||
516 (strcmp (op1, op3) == 0) ||
517 (strcmp (op1, op4) == 0) ||
518 (strcmp (op1, op5) == 0) ||
519 (strcmp (op1, op6) == 0) ||
520 (strcmp (op1, op7) == 0) ||
521 (strcmp (op1, op8) == 0) ||
522 (strcmp (op2, op3) == 0) ||
523 (strcmp (op2, op4) == 0) ||
524 (strcmp (op2, op5) == 0) ||
525 (strcmp (op2, op6) == 0) ||
526 (strcmp (op2, op7) == 0) ||
527 (strcmp (op2, op8) == 0) ||
528 (strcmp (op3, op4) == 0) ||
529 (strcmp (op3, op5) == 0) ||
530 (strcmp (op3, op6) == 0) ||
531 (strcmp (op3, op7) == 0) ||
532 (strcmp (op3, op8) == 0) ||
533 (strcmp (op4, op5) == 0) ||
534 (strcmp (op4, op6) == 0) ||
535 (strcmp (op4, op7) == 0) ||
536 (strcmp (op4, op8) == 0) ||
537 (strcmp (op5, op6) == 0) ||
538 (strcmp (op5, op7) == 0) ||
539 (strcmp (op5, op8) == 0) ||
540 (strcmp (op6, op7) == 0) ||
541 (strcmp (op6, op8) == 0) ||
542 (strcmp (op7, op8) == 0) )
551 * takes two parameters: a variable (bound to a label name)
552 * and an expected reference count.
554 * Returns TRUE if that label is defined and referenced exactly
555 * the given number of times.
557 FBYNAME (labelRefCount)
559 int varNumber, expectedRefCount;
562 /* If we don't have the label hash table yet, build it. */
565 buildLabelRefCountHash (head);
568 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
570 char *label = hTabItemWithKey (vars, varNumber);
574 labelHashEntry *entry;
576 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
580 if (!strcmp (label, entry->name))
584 entry = hTabNextItemWK (labelHash);
590 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
591 label, entry->refCount, expectedRefCount);
594 rc = (expectedRefCount == entry->refCount);
598 fprintf (stderr, "*** internal error: no label has entry for"
599 " %s in labelRefCount peephole.\n",
605 fprintf (stderr, "*** internal error: var %d not bound"
606 " in peephole labelRefCount rule.\n",
614 "*** internal error: labelRefCount peephole restriction"
615 " malformed: %s\n", cmdLine);
620 /*-----------------------------------------------------------------*/
621 /* callFuncByName - calls a function as defined in the table */
622 /*-----------------------------------------------------------------*/
624 callFuncByName (char *fname,
633 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
638 "labelInRange", labelInRange
642 "operandsNotSame", operandsNotSame
646 "operandsNotSame3", operandsNotSame3
650 "operandsNotSame4", operandsNotSame4
654 "operandsNotSame5", operandsNotSame5
658 "operandsNotSame6", operandsNotSame6
662 "operandsNotSame7", operandsNotSame7
666 "operandsNotSame8", operandsNotSame8
670 "24bitMode", flat24bitMode
674 "xramMovcOption", xramMovcOption
678 "labelRefCount", labelRefCount
682 "portIsDS390", portIsDS390
685 "labelIsReturnOnly", labelIsReturnOnly
688 "okToRemoveSLOC", okToRemoveSLOC
691 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
695 char *cmdCopy, *funcName, *funcArgs;
698 /* Isolate the function name part (we are passed the full condition
699 * string including arguments)
701 cmdCopy = Safe_strdup(fname);
702 funcName = strtok(cmdCopy, " \t");
703 funcArgs = strtok(NULL, "");
705 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
707 if (strcmp (ftab[i].fname, funcName) == 0)
709 rc = (*ftab[i].func) (vars, currPl, endPl, head,
719 "could not find named function \"%s\" in "
720 "peephole function table\n",
722 // If the function couldn't be found, let's assume it's
723 // a bad rule and refuse it.
730 /*-----------------------------------------------------------------*/
731 /* printLine - prints a line chain into a given file */
732 /*-----------------------------------------------------------------*/
734 printLine (lineNode * head, FILE * of)
741 /* don't indent comments & labels */
743 (*head->line == ';' ||
744 head->line[strlen (head->line) - 1] == ':')) {
745 fprintf (of, "%s\n", head->line);
747 if (head->isInline && *head->line=='#') {
748 // comment out preprocessor directives in inline asm
751 fprintf (of, "\t%s\n", head->line);
757 /*-----------------------------------------------------------------*/
758 /* newPeepRule - creates a new peeprule and attach it to the root */
759 /*-----------------------------------------------------------------*/
761 newPeepRule (lineNode * match,
768 pr = Safe_alloc ( sizeof (peepRule));
770 pr->replace = replace;
771 pr->restart = restart;
775 pr->cond = Safe_strdup (cond);
780 pr->vars = newHashTable (100);
782 /* if root is empty */
784 rootRules = currRule = pr;
786 currRule = currRule->next = pr;
791 /*-----------------------------------------------------------------*/
792 /* newLineNode - creates a new peep line */
793 /*-----------------------------------------------------------------*/
795 newLineNode (char *line)
799 pl = Safe_alloc ( sizeof (lineNode));
800 pl->line = Safe_strdup (line);
804 /*-----------------------------------------------------------------*/
805 /* connectLine - connects two lines */
806 /*-----------------------------------------------------------------*/
808 connectLine (lineNode * pl1, lineNode * pl2)
812 fprintf (stderr, "trying to connect null line\n");
822 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
823 if (!*x) { fprintf(stderr,y); return ; } }
825 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
826 if (!*x) { fprintf(stderr,z); return ; } }
827 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
828 if (!*x) { fprintf(stderr,z); return ; } }
830 /*-----------------------------------------------------------------*/
831 /* getPeepLine - parses the peep lines */
832 /*-----------------------------------------------------------------*/
834 getPeepLine (lineNode ** head, char **bpp)
836 char lines[MAX_PATTERN_LEN];
839 lineNode *currL = NULL;
846 fprintf (stderr, "unexpected end of match pattern\n");
853 while (isspace (*bp) ||
864 /* read till end of line */
866 while ((*bp != '\n' && *bp != '}') && *bp)
871 *head = currL = newLineNode (lines);
873 currL = connectLine (currL, newLineNode (lines));
879 /*-----------------------------------------------------------------*/
880 /* readRules - reads the rules from a string buffer */
881 /*-----------------------------------------------------------------*/
886 char lines[MAX_PATTERN_LEN];
890 lineNode *currL = NULL;
896 /* look for the token "replace" that is the
898 while (*bp && strncmp (bp, "replace", 7))
905 /* then look for either "restart" or '{' */
906 while (strncmp (bp, "restart", 7) &&
913 fprintf (stderr, "expected 'restart' or '{'\n");
921 { /* must be restart */
923 bp += strlen ("restart");
925 EXPECT_CHR (bp, '{', "expected '{'\n");
929 /* skip thru all the blank space */
930 SKIP_SPACE (bp, "unexpected end of rule\n");
932 match = replace = currL = NULL;
933 /* we are the start of a rule */
934 getPeepLine (&match, &bp);
936 /* now look for by */
937 EXPECT_STR (bp, "by", "expected 'by'\n");
939 /* then look for a '{' */
940 EXPECT_CHR (bp, '{', "expected '{'\n");
943 SKIP_SPACE (bp, "unexpected end of rule\n");
944 getPeepLine (&replace, &bp);
946 /* look for a 'if' */
947 while ((isspace (*bp) || *bp == '\n') && *bp)
950 if (strncmp (bp, "if", 2) == 0)
953 while ((isspace (*bp) || *bp == '\n') && *bp)
957 fprintf (stderr, "expected condition name\n");
961 /* look for the condition */
963 while (*bp && (*bp != '\n'))
969 newPeepRule (match, replace, lines, restart);
972 newPeepRule (match, replace, NULL, restart);
977 /*-----------------------------------------------------------------*/
978 /* keyForVar - returns the numeric key for a var */
979 /*-----------------------------------------------------------------*/
994 /*-----------------------------------------------------------------*/
995 /* bindVar - binds a value to a variable in the given hashtable */
996 /*-----------------------------------------------------------------*/
998 bindVar (int key, char **s, hTab ** vtab)
1000 char vval[MAX_PATTERN_LEN];
1004 /* first get the value of the variable */
1006 /* the value is ended by a ',' or space or newline or null or ) */
1015 /* if we find a '(' then we need to balance it */
1027 // include the trailing ')'
1036 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1038 hTabAddItem (vtab, key, vvx);
1041 /*-----------------------------------------------------------------*/
1042 /* matchLine - matches one line */
1043 /*-----------------------------------------------------------------*/
1045 matchLine (char *s, char *d, hTab ** vars)
1054 /* skip white space in both */
1055 while (isspace (*s))
1057 while (isspace (*d))
1060 /* if the destination is a var */
1061 if (*d == '%' && isdigit (*(d + 1)))
1063 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1064 /* if the variable is already bound
1065 then it MUST match with dest */
1073 /* variable not bound we need to
1075 bindVar (keyForVar (d + 1), &s, vars);
1077 /* in either case go past the variable */
1079 while (isdigit (*d))
1083 /* they should be an exact match other wise */
1086 while (isspace (*s))
1088 while (isspace (*d))
1096 /* get rid of the trailing spaces
1097 in both source & destination */
1099 while (isspace (*s))
1103 while (isspace (*d))
1106 /* after all this if only one of them
1107 has something left over then no match */
1114 /*-----------------------------------------------------------------*/
1115 /* matchRule - matches a all the rule lines */
1116 /*-----------------------------------------------------------------*/
1118 matchRule (lineNode * pl,
1123 lineNode *spl; /* source pl */
1124 lineNode *rpl; /* rule peep line */
1126 /* setToNull((void **) &pr->vars); */
1127 /* pr->vars = newHashTable(100); */
1129 /* for all the lines defined in the rule */
1135 /* if the source line starts with a ';' then
1136 comment line don't process or the source line
1137 contains == . debugger information skip it */
1139 (*spl->line == ';' || spl->isDebug))
1145 if (!matchLine (spl->line, rpl->line, &pr->vars))
1153 /* if rules ended */
1156 /* if this rule has additional conditions */
1159 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1177 /*-----------------------------------------------------------------*/
1178 /* replaceRule - does replacement of a matching pattern */
1179 /*-----------------------------------------------------------------*/
1181 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1183 lineNode *cl = NULL;
1184 lineNode *pl = NULL, *lhead = NULL;
1185 /* a long function name and long variable name can evaluate to
1186 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1187 char lb[MAX_PATTERN_LEN*4];
1189 lineNode *comment = NULL;
1191 /* collect all the comment lines in the source */
1192 for (cl = *shead; cl != stail; cl = cl->next)
1194 if (cl->line && (*cl->line == ';' || cl->isDebug))
1196 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1197 (comment = newLineNode (cl->line)));
1198 pl->isDebug = cl->isDebug;
1203 /* for all the lines in the replacement pattern do */
1204 for (pl = pr->replace; pl; pl = pl->next)
1214 /* if the line contains a variable */
1215 if (*l == '%' && isdigit (*(l + 1)))
1217 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1220 fprintf (stderr, "used unbound variable in replacement\n");
1228 while (isdigit (*l)) {
1238 cl = connectLine (cl, newLineNode (lb));
1240 lhead = cl = newLineNode (lb);
1243 /* add the comments if any to the head of list */
1246 lineNode *lc = comment;
1255 /* now we need to connect / replace the original chain */
1256 /* if there is a prev then change it */
1259 (*shead)->prev->next = lhead;
1260 lhead->prev = (*shead)->prev;
1263 /* now for the tail */
1264 if (stail && stail->next)
1266 stail->next->prev = cl;
1268 cl->next = stail->next;
1272 /* Returns TRUE if this line is a label definition.
1274 * If so, start will point to the start of the label name,
1275 * and len will be it's length.
1278 isLabelDefinition (const char *line, const char **start, int *len)
1280 const char *cp = line;
1282 /* This line is a label if if consists of:
1283 * [optional whitespace] followed by identifier chars
1284 * (alnum | $ | _ ) followed by a colon.
1287 while (*cp && isspace (*cp))
1299 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1304 if ((cp == *start) || (*cp != ':'))
1309 *len = (cp - (*start));
1313 /* Quick & dirty string hash function. */
1315 hashSymbolName (const char *name)
1321 hash = (hash << 6) ^ *name;
1330 return hash % HTAB_SIZE;
1333 /* Build a hash of all labels in the passed set of lines
1334 * and how many times they are referenced.
1337 buildLabelRefCountHash (lineNode * head)
1344 assert (labelHash == NULL);
1345 labelHash = newHashTable (HTAB_SIZE);
1347 /* First pass: locate all the labels. */
1352 if (isLabelDefinition (line->line, &label, &labelLen)
1353 && labelLen <= SDCC_NAME_MAX)
1355 labelHashEntry *entry;
1357 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1359 memcpy (entry->name, label, labelLen);
1360 entry->name[labelLen] = 0;
1361 entry->refCount = -1;
1363 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1369 /* Second pass: for each line, note all the referenced labels. */
1370 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1374 for (i = 0; i < HTAB_SIZE; i++)
1376 labelHashEntry *thisEntry;
1378 thisEntry = hTabFirstItemWK (labelHash, i);
1382 if (strstr (line->line, thisEntry->name))
1384 thisEntry->refCount++;
1386 thisEntry = hTabNextItemWK (labelHash);
1393 /* Spew the contents of the table. Debugging fun only. */
1394 for (i = 0; i < HTAB_SIZE; i++)
1396 labelHashEntry *thisEntry;
1398 thisEntry = hTabFirstItemWK (labelHash, i);
1402 fprintf (stderr, "label: %s ref %d\n",
1403 thisEntry->name, thisEntry->refCount);
1404 thisEntry = hTabNextItemWK (labelHash);
1410 /* How does this work?
1416 replace and restart.
1421 Where is stuff allocated?
1425 /*-----------------------------------------------------------------*/
1426 /* peepHole - matches & substitutes rules */
1427 /*-----------------------------------------------------------------*/
1429 peepHole (lineNode ** pls)
1433 lineNode *mtail = NULL;
1436 #if !OPT_DISABLE_PIC
1437 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1442 assert(labelHash == NULL);
1449 for (pr = rootRules; pr; pr = pr->next)
1451 for (spl = *pls; spl; spl = spl->next)
1453 /* if inline assembler then no peep hole */
1459 /* Tidy up any data stored in the hTab */
1462 if (matchRule (spl, &mtail, pr, *pls))
1467 replaceRule (pls, mtail, pr);
1469 replaceRule (&spl, mtail, pr);
1471 /* if restart rule type then
1472 start at the top again */
1481 hTabDeleteAll (pr->vars);
1482 Safe_free (pr->vars);
1486 freeTrace (&_G.values);
1489 } while (restart == TRUE);
1493 hTabDeleteAll (labelHash);
1494 freeTrace (&_G.labels);
1500 /*-----------------------------------------------------------------*/
1501 /* readFileIntoBuffer - reads a file into a string buffer */
1502 /*-----------------------------------------------------------------*/
1504 readFileIntoBuffer (char *fname)
1510 char lb[MAX_PATTERN_LEN];
1512 if (!(f = fopen (fname, "r")))
1514 fprintf (stderr, "cannot open peep rule file\n");
1518 while ((ch = fgetc (f)) != EOF)
1522 /* if we maxed out our local buffer */
1523 if (nch >= (MAX_PATTERN_LEN - 2))
1526 /* copy it into allocated buffer */
1529 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1530 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1534 rs = Safe_strdup (lb);
1540 /* if some charaters left over */
1544 /* copy it into allocated buffer */
1547 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1548 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1552 rs = Safe_strdup (lb);
1558 /*-----------------------------------------------------------------*/
1559 /* initPeepHole - initialises the peep hole optimizer stuff */
1560 /*-----------------------------------------------------------------*/
1566 /* read in the default rules */
1567 readRules (port->peep.default_rules);
1569 /* if we have any additional file read it too */
1570 if (options.peep_file)
1572 readRules (s = readFileIntoBuffer (options.peep_file));
1573 setToNull ((void **) &s);
1577 #if !OPT_DISABLE_PIC
1578 /* Convert the peep rules into pcode.
1579 NOTE: this is only support in the PIC port (at the moment)
1581 if (TARGET_IS_PIC) {
1582 peepRules2pCode(rootRules);