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 #if !OPT_DISABLE_PIC16
60 void pic16_peepRules2pCode(peepRule *);
63 /*-----------------------------------------------------------------*/
64 /* pcDistance - afinds a label back ward or forward */
65 /*-----------------------------------------------------------------*/
67 mcs51_instruction_size(const char *inst)
69 char *op, op1[256], op2[256];
73 while (*inst && isspace(*inst)) inst++;
75 #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
76 if (ISINST("lcall")) return 3;
77 if (ISINST("ret")) return 1;
78 if (ISINST("ljmp")) return 3;
79 if (ISINST("sjmp")) return 2;
80 if (ISINST("rlc")) return 1;
81 if (ISINST("rrc")) return 1;
82 if (ISINST("rl")) return 1;
83 if (ISINST("rr")) return 1;
84 if (ISINST("swap")) return 1;
85 if (ISINST("movx")) return 1;
86 if (ISINST("movc")) return 1;
87 if (ISINST("push")) return 2;
88 if (ISINST("pop")) return 2;
89 if (ISINST("jc")) return 2;
90 if (ISINST("jnc")) return 2;
91 if (ISINST("jb")) return 3;
92 if (ISINST("jnb")) return 3;
93 if (ISINST("jbc")) return 3;
94 if (ISINST("jmp")) return 1; // always jmp @a+dptr
95 if (ISINST("jz")) return 2;
96 if (ISINST("jnz")) return 2;
97 if (ISINST("cjne")) return 3;
98 if (ISINST("mul")) return 1;
99 if (ISINST("div")) return 1;
100 if (ISINST("da")) return 1;
101 if (ISINST("xchd")) return 1;
102 if (ISINST("reti")) return 1;
103 if (ISINST("nop")) return 1;
104 if (ISINST("acall")) return 1;
105 if (ISINST("ajmp")) return 2;
108 while (*p && isalnum(*p)) p++;
109 for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
110 if (!isspace(*p)) *op++ = *p, opsize++;
114 for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
115 if (!isspace(*p)) *op++ = *p, opsize++;
119 #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
120 #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
121 #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
122 #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
125 if (IS_C(op1) || IS_C(op2)) return 2;
127 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
130 if (IS_Rn(op1) || IS_atRi(op1)) {
131 if (IS_A(op2)) return 1;
134 if (strcmp(op1, "dptr") == 0) return 3;
135 if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
138 if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
139 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
142 if (ISINST("inc") || ISINST("dec")) {
143 if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
144 if (strcmp(op1, "dptr") == 0) return 1;
147 if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
148 if (IS_C(op1)) return 2;
150 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
153 if (IS_A(op2)) return 2;
157 if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
158 if (IS_A(op1) || IS_C(op1)) return 1;
161 if (ISINST("djnz")) {
162 if (IS_Rn(op1)) return 2;
166 if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
167 /* ignore ar0 = 0x00 type definitions */
171 fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
176 pcDistance (lineNode * cpos, char *lbl, bool back)
179 char buff[MAX_PATTERN_LEN];
182 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
188 pl->line[strlen (pl->line) - 1] != ':' &&
190 if (strcmp(port->target,"mcs51") == 0) {
191 dist += mcs51_instruction_size(pl->line);
197 if (strncmp (pl->line, buff, strlen (buff)) == 0)
209 /*-----------------------------------------------------------------*/
210 /* flat24bitModeAndPortDS390 - */
211 /*-----------------------------------------------------------------*/
212 FBYNAME (flat24bitModeAndPortDS390)
214 return ((strcmp(port->target,"ds390") == 0) &&
215 (options.model == MODEL_FLAT24));
218 /*-----------------------------------------------------------------*/
219 /* portIsDS390 - return true if port is DS390 */
220 /*-----------------------------------------------------------------*/
221 FBYNAME (portIsDS390)
223 return (strcmp(port->target,"ds390") == 0);
226 /*-----------------------------------------------------------------*/
227 /* flat24bitMode - will check to see if we are in flat24 mode */
228 /*-----------------------------------------------------------------*/
229 FBYNAME (flat24bitMode)
231 return (options.model == MODEL_FLAT24);
234 /*-----------------------------------------------------------------*/
235 /* xramMovcOption - check if using movc to read xram */
236 /*-----------------------------------------------------------------*/
237 FBYNAME (xramMovcOption)
239 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
247 /*-----------------------------------------------------------------*/
248 /* labelInRange - will check to see if label %5 is within range */
249 /*-----------------------------------------------------------------*/
250 FBYNAME (labelInRange)
252 /* assumes that %5 pattern variable has the label name */
253 char *lbl = hTabItemWithKey (vars, 5);
259 /* if the previous two instructions are "ljmp"s then don't
260 do it since it can be part of a jump table */
261 if (currPl->prev && currPl->prev->prev &&
262 strstr (currPl->prev->line, "ljmp") &&
263 strstr (currPl->prev->prev->line, "ljmp"))
266 /* calculate the label distance : the jump for reladdr can be
267 +/- 127 bytes, here Iam assuming that an average 8051
268 instruction is 2 bytes long, so if the label is more than
269 63 intructions away, the label is considered out of range
270 for a relative jump. we could get more precise this will
271 suffice for now since it catches > 90% cases */
272 dist = (pcDistance (currPl, lbl, TRUE) +
273 pcDistance (currPl, lbl, FALSE));
275 /* changed to 127, now that pcDistance return actual number of bytes */
276 if (!dist || dist > 127)
282 /*-----------------------------------------------------------------*/
283 /* labelIsReturnOnly - Check if label %5 is followed by RET */
284 /*-----------------------------------------------------------------*/
285 FBYNAME (labelIsReturnOnly)
287 /* assumes that %5 pattern variable has the label name */
288 const char *label, *p;
292 label = hTabItemWithKey (vars, 5);
293 if (!label) return FALSE;
296 for(pl = currPl; pl; pl = pl->next) {
297 if (pl->line && !pl->isDebug &&
298 pl->line[strlen(pl->line)-1] == ':') {
299 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
300 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
301 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
302 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
303 *(pl->line+5) != '$') {
304 return FALSE; /* non-local label encountered */
308 if (!pl) return FALSE; /* did not find the label */
310 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
312 for (p = pl->line; *p && isspace(*p); p++)
314 if (strcmp(p, "ret") == 0) return TRUE;
319 /*-----------------------------------------------------------------*/
320 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
321 /* usage of it in the code depends on a value from this section */
322 /*-----------------------------------------------------------------*/
323 FBYNAME (okToRemoveSLOC)
326 const char *sloc, *p;
327 int dummy1, dummy2, dummy3;
329 /* assumes that %1 as the SLOC name */
330 sloc = hTabItemWithKey (vars, 1);
331 if (sloc == NULL) return FALSE;
332 p = strstr(sloc, "sloc");
333 if (p == NULL) return FALSE;
335 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
336 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
337 /* the sloc name begins with that. Probably not really necessary */
339 /* Look for any occurance of this SLOC before the peephole match */
340 for (pl = currPl->prev; pl; pl = pl->prev) {
341 if (pl->line && !pl->isDebug && !pl->isComment
342 && *pl->line != ';' && strstr(pl->line, sloc))
345 /* Look for any occurance of this SLOC after the peephole match */
346 for (pl = endPl->next; pl; pl = pl->next) {
347 if (pl->line && !pl->isDebug && !pl->isComment
348 && *pl->line != ';' && strstr(pl->line, sloc))
351 return TRUE; /* safe for a peephole to remove it :) */
355 /*-----------------------------------------------------------------*/
356 /* operandsNotSame - check if %1 & %2 are the same */
357 /*-----------------------------------------------------------------*/
358 FBYNAME (operandsNotSame)
360 char *op1 = hTabItemWithKey (vars, 1);
361 char *op2 = hTabItemWithKey (vars, 2);
363 if (strcmp (op1, op2) == 0)
369 /*-----------------------------------------------------------------*/
370 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
371 /*-----------------------------------------------------------------*/
372 FBYNAME (operandsNotSame3)
374 char *op1 = hTabItemWithKey (vars, 1);
375 char *op2 = hTabItemWithKey (vars, 2);
376 char *op3 = hTabItemWithKey (vars, 3);
378 if ( (strcmp (op1, op2) == 0) ||
379 (strcmp (op1, op3) == 0) ||
380 (strcmp (op2, op3) == 0) )
386 /*-----------------------------------------------------------------*/
387 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
388 /*-----------------------------------------------------------------*/
389 FBYNAME (operandsNotSame4)
391 char *op1 = hTabItemWithKey (vars, 1);
392 char *op2 = hTabItemWithKey (vars, 2);
393 char *op3 = hTabItemWithKey (vars, 3);
394 char *op4 = hTabItemWithKey (vars, 4);
396 if ( (strcmp (op1, op2) == 0) ||
397 (strcmp (op1, op3) == 0) ||
398 (strcmp (op1, op4) == 0) ||
399 (strcmp (op2, op3) == 0) ||
400 (strcmp (op2, op4) == 0) ||
401 (strcmp (op3, op4) == 0) )
407 /*-----------------------------------------------------------------*/
408 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
409 /*-----------------------------------------------------------------*/
410 FBYNAME (operandsNotSame5)
412 char *op1 = hTabItemWithKey (vars, 1);
413 char *op2 = hTabItemWithKey (vars, 2);
414 char *op3 = hTabItemWithKey (vars, 3);
415 char *op4 = hTabItemWithKey (vars, 4);
416 char *op5 = hTabItemWithKey (vars, 5);
418 if ( (strcmp (op1, op2) == 0) ||
419 (strcmp (op1, op3) == 0) ||
420 (strcmp (op1, op4) == 0) ||
421 (strcmp (op1, op5) == 0) ||
422 (strcmp (op2, op3) == 0) ||
423 (strcmp (op2, op4) == 0) ||
424 (strcmp (op2, op5) == 0) ||
425 (strcmp (op3, op4) == 0) ||
426 (strcmp (op3, op5) == 0) ||
427 (strcmp (op4, op5) == 0) )
433 /*-----------------------------------------------------------------*/
434 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
435 /*-----------------------------------------------------------------*/
436 FBYNAME (operandsNotSame6)
438 char *op1 = hTabItemWithKey (vars, 1);
439 char *op2 = hTabItemWithKey (vars, 2);
440 char *op3 = hTabItemWithKey (vars, 3);
441 char *op4 = hTabItemWithKey (vars, 4);
442 char *op5 = hTabItemWithKey (vars, 5);
443 char *op6 = hTabItemWithKey (vars, 6);
445 if ( (strcmp (op1, op2) == 0) ||
446 (strcmp (op1, op3) == 0) ||
447 (strcmp (op1, op4) == 0) ||
448 (strcmp (op1, op5) == 0) ||
449 (strcmp (op1, op6) == 0) ||
450 (strcmp (op2, op3) == 0) ||
451 (strcmp (op2, op4) == 0) ||
452 (strcmp (op2, op5) == 0) ||
453 (strcmp (op2, op6) == 0) ||
454 (strcmp (op3, op4) == 0) ||
455 (strcmp (op3, op5) == 0) ||
456 (strcmp (op3, op6) == 0) ||
457 (strcmp (op4, op5) == 0) ||
458 (strcmp (op4, op6) == 0) ||
459 (strcmp (op5, op6) == 0) )
466 /*-----------------------------------------------------------------*/
467 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
468 /*-----------------------------------------------------------------*/
469 FBYNAME (operandsNotSame7)
471 char *op1 = hTabItemWithKey (vars, 1);
472 char *op2 = hTabItemWithKey (vars, 2);
473 char *op3 = hTabItemWithKey (vars, 3);
474 char *op4 = hTabItemWithKey (vars, 4);
475 char *op5 = hTabItemWithKey (vars, 5);
476 char *op6 = hTabItemWithKey (vars, 6);
477 char *op7 = hTabItemWithKey (vars, 7);
479 if ( (strcmp (op1, op2) == 0) ||
480 (strcmp (op1, op3) == 0) ||
481 (strcmp (op1, op4) == 0) ||
482 (strcmp (op1, op5) == 0) ||
483 (strcmp (op1, op6) == 0) ||
484 (strcmp (op1, op7) == 0) ||
485 (strcmp (op2, op3) == 0) ||
486 (strcmp (op2, op4) == 0) ||
487 (strcmp (op2, op5) == 0) ||
488 (strcmp (op2, op6) == 0) ||
489 (strcmp (op2, op7) == 0) ||
490 (strcmp (op3, op4) == 0) ||
491 (strcmp (op3, op5) == 0) ||
492 (strcmp (op3, op6) == 0) ||
493 (strcmp (op3, op7) == 0) ||
494 (strcmp (op4, op5) == 0) ||
495 (strcmp (op4, op6) == 0) ||
496 (strcmp (op4, op7) == 0) ||
497 (strcmp (op5, op6) == 0) ||
498 (strcmp (op5, op7) == 0) ||
499 (strcmp (op6, op7) == 0) )
505 /*-----------------------------------------------------------------*/
506 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
507 /*-----------------------------------------------------------------*/
508 FBYNAME (operandsNotSame8)
510 char *op1 = hTabItemWithKey (vars, 1);
511 char *op2 = hTabItemWithKey (vars, 2);
512 char *op3 = hTabItemWithKey (vars, 3);
513 char *op4 = hTabItemWithKey (vars, 4);
514 char *op5 = hTabItemWithKey (vars, 5);
515 char *op6 = hTabItemWithKey (vars, 6);
516 char *op7 = hTabItemWithKey (vars, 7);
517 char *op8 = hTabItemWithKey (vars, 8);
519 if ( (strcmp (op1, op2) == 0) ||
520 (strcmp (op1, op3) == 0) ||
521 (strcmp (op1, op4) == 0) ||
522 (strcmp (op1, op5) == 0) ||
523 (strcmp (op1, op6) == 0) ||
524 (strcmp (op1, op7) == 0) ||
525 (strcmp (op1, op8) == 0) ||
526 (strcmp (op2, op3) == 0) ||
527 (strcmp (op2, op4) == 0) ||
528 (strcmp (op2, op5) == 0) ||
529 (strcmp (op2, op6) == 0) ||
530 (strcmp (op2, op7) == 0) ||
531 (strcmp (op2, op8) == 0) ||
532 (strcmp (op3, op4) == 0) ||
533 (strcmp (op3, op5) == 0) ||
534 (strcmp (op3, op6) == 0) ||
535 (strcmp (op3, op7) == 0) ||
536 (strcmp (op3, op8) == 0) ||
537 (strcmp (op4, op5) == 0) ||
538 (strcmp (op4, op6) == 0) ||
539 (strcmp (op4, op7) == 0) ||
540 (strcmp (op4, op8) == 0) ||
541 (strcmp (op5, op6) == 0) ||
542 (strcmp (op5, op7) == 0) ||
543 (strcmp (op5, op8) == 0) ||
544 (strcmp (op6, op7) == 0) ||
545 (strcmp (op6, op8) == 0) ||
546 (strcmp (op7, op8) == 0) )
555 * takes two parameters: a variable (bound to a label name)
556 * and an expected reference count.
558 * Returns TRUE if that label is defined and referenced exactly
559 * the given number of times.
561 FBYNAME (labelRefCount)
563 int varNumber, expectedRefCount;
566 /* If we don't have the label hash table yet, build it. */
569 buildLabelRefCountHash (head);
572 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
574 char *label = hTabItemWithKey (vars, varNumber);
578 labelHashEntry *entry;
580 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
584 if (!strcmp (label, entry->name))
588 entry = hTabNextItemWK (labelHash);
594 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
595 label, entry->refCount, expectedRefCount);
598 rc = (expectedRefCount == entry->refCount);
602 fprintf (stderr, "*** internal error: no label has entry for"
603 " %s in labelRefCount peephole.\n",
609 fprintf (stderr, "*** internal error: var %d not bound"
610 " in peephole labelRefCount rule.\n",
618 "*** internal error: labelRefCount peephole restriction"
619 " malformed: %s\n", cmdLine);
624 /*-----------------------------------------------------------------*/
625 /* callFuncByName - calls a function as defined in the table */
626 /*-----------------------------------------------------------------*/
628 callFuncByName (char *fname,
637 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
642 "labelInRange", labelInRange
646 "operandsNotSame", operandsNotSame
650 "operandsNotSame3", operandsNotSame3
654 "operandsNotSame4", operandsNotSame4
658 "operandsNotSame5", operandsNotSame5
662 "operandsNotSame6", operandsNotSame6
666 "operandsNotSame7", operandsNotSame7
670 "operandsNotSame8", operandsNotSame8
674 "24bitMode", flat24bitMode
678 "xramMovcOption", xramMovcOption
682 "labelRefCount", labelRefCount
686 "portIsDS390", portIsDS390
689 "labelIsReturnOnly", labelIsReturnOnly
692 "okToRemoveSLOC", okToRemoveSLOC
695 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
699 char *cmdCopy, *funcName, *funcArgs;
702 /* Isolate the function name part (we are passed the full condition
703 * string including arguments)
705 cmdCopy = Safe_strdup(fname);
706 funcName = strtok(cmdCopy, " \t");
707 funcArgs = strtok(NULL, "");
709 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
711 if (strcmp (ftab[i].fname, funcName) == 0)
713 rc = (*ftab[i].func) (vars, currPl, endPl, head,
723 "could not find named function \"%s\" in "
724 "peephole function table\n",
726 // If the function couldn't be found, let's assume it's
727 // a bad rule and refuse it.
734 /*-----------------------------------------------------------------*/
735 /* printLine - prints a line chain into a given file */
736 /*-----------------------------------------------------------------*/
738 printLine (lineNode * head, FILE * of)
745 /* don't indent comments & labels */
747 (*head->line == ';' ||
748 head->line[strlen (head->line) - 1] == ':')) {
749 fprintf (of, "%s\n", head->line);
751 if (head->isInline && *head->line=='#') {
752 // comment out preprocessor directives in inline asm
755 fprintf (of, "\t%s\n", head->line);
761 /*-----------------------------------------------------------------*/
762 /* newPeepRule - creates a new peeprule and attach it to the root */
763 /*-----------------------------------------------------------------*/
765 newPeepRule (lineNode * match,
772 pr = Safe_alloc ( sizeof (peepRule));
774 pr->replace = replace;
775 pr->restart = restart;
779 pr->cond = Safe_strdup (cond);
784 pr->vars = newHashTable (100);
786 /* if root is empty */
788 rootRules = currRule = pr;
790 currRule = currRule->next = pr;
795 /*-----------------------------------------------------------------*/
796 /* newLineNode - creates a new peep line */
797 /*-----------------------------------------------------------------*/
799 newLineNode (char *line)
803 pl = Safe_alloc ( sizeof (lineNode));
804 pl->line = Safe_strdup (line);
808 /*-----------------------------------------------------------------*/
809 /* connectLine - connects two lines */
810 /*-----------------------------------------------------------------*/
812 connectLine (lineNode * pl1, lineNode * pl2)
816 fprintf (stderr, "trying to connect null line\n");
826 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
827 if (!*x) { fprintf(stderr,y); return ; } }
829 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
830 if (!*x) { fprintf(stderr,z); return ; } }
831 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
832 if (!*x) { fprintf(stderr,z); return ; } }
834 /*-----------------------------------------------------------------*/
835 /* getPeepLine - parses the peep lines */
836 /*-----------------------------------------------------------------*/
838 getPeepLine (lineNode ** head, char **bpp)
840 char lines[MAX_PATTERN_LEN];
843 lineNode *currL = NULL;
850 fprintf (stderr, "unexpected end of match pattern\n");
857 while (isspace (*bp) ||
868 /* read till end of line */
870 while ((*bp != '\n' && *bp != '}') && *bp)
875 *head = currL = newLineNode (lines);
877 currL = connectLine (currL, newLineNode (lines));
883 /*-----------------------------------------------------------------*/
884 /* readRules - reads the rules from a string buffer */
885 /*-----------------------------------------------------------------*/
890 char lines[MAX_PATTERN_LEN];
894 lineNode *currL = NULL;
900 /* look for the token "replace" that is the
902 while (*bp && strncmp (bp, "replace", 7))
909 /* then look for either "restart" or '{' */
910 while (strncmp (bp, "restart", 7) &&
917 fprintf (stderr, "expected 'restart' or '{'\n");
925 { /* must be restart */
927 bp += strlen ("restart");
929 EXPECT_CHR (bp, '{', "expected '{'\n");
933 /* skip thru all the blank space */
934 SKIP_SPACE (bp, "unexpected end of rule\n");
936 match = replace = currL = NULL;
937 /* we are the start of a rule */
938 getPeepLine (&match, &bp);
940 /* now look for by */
941 EXPECT_STR (bp, "by", "expected 'by'\n");
943 /* then look for a '{' */
944 EXPECT_CHR (bp, '{', "expected '{'\n");
947 SKIP_SPACE (bp, "unexpected end of rule\n");
948 getPeepLine (&replace, &bp);
950 /* look for a 'if' */
951 while ((isspace (*bp) || *bp == '\n') && *bp)
954 if (strncmp (bp, "if", 2) == 0)
957 while ((isspace (*bp) || *bp == '\n') && *bp)
961 fprintf (stderr, "expected condition name\n");
965 /* look for the condition */
967 while (*bp && (*bp != '\n'))
973 newPeepRule (match, replace, lines, restart);
976 newPeepRule (match, replace, NULL, restart);
981 /*-----------------------------------------------------------------*/
982 /* keyForVar - returns the numeric key for a var */
983 /*-----------------------------------------------------------------*/
998 /*-----------------------------------------------------------------*/
999 /* bindVar - binds a value to a variable in the given hashtable */
1000 /*-----------------------------------------------------------------*/
1002 bindVar (int key, char **s, hTab ** vtab)
1004 char vval[MAX_PATTERN_LEN];
1008 /* first get the value of the variable */
1010 /* the value is ended by a ',' or space or newline or null or ) */
1019 /* if we find a '(' then we need to balance it */
1031 // include the trailing ')'
1040 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1042 hTabAddItem (vtab, key, vvx);
1045 /*-----------------------------------------------------------------*/
1046 /* matchLine - matches one line */
1047 /*-----------------------------------------------------------------*/
1049 matchLine (char *s, char *d, hTab ** vars)
1058 /* skip white space in both */
1059 while (isspace (*s))
1061 while (isspace (*d))
1064 /* if the destination is a var */
1065 if (*d == '%' && isdigit (*(d + 1)))
1067 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1068 /* if the variable is already bound
1069 then it MUST match with dest */
1077 /* variable not bound we need to
1079 bindVar (keyForVar (d + 1), &s, vars);
1081 /* in either case go past the variable */
1083 while (isdigit (*d))
1087 /* they should be an exact match other wise */
1090 while (isspace (*s))
1092 while (isspace (*d))
1100 /* get rid of the trailing spaces
1101 in both source & destination */
1103 while (isspace (*s))
1107 while (isspace (*d))
1110 /* after all this if only one of them
1111 has something left over then no match */
1118 /*-----------------------------------------------------------------*/
1119 /* matchRule - matches a all the rule lines */
1120 /*-----------------------------------------------------------------*/
1122 matchRule (lineNode * pl,
1127 lineNode *spl; /* source pl */
1128 lineNode *rpl; /* rule peep line */
1130 /* setToNull((void **) &pr->vars); */
1131 /* pr->vars = newHashTable(100); */
1133 /* for all the lines defined in the rule */
1139 /* if the source line starts with a ';' then
1140 comment line don't process or the source line
1141 contains == . debugger information skip it */
1143 (*spl->line == ';' || spl->isDebug))
1149 if (!matchLine (spl->line, rpl->line, &pr->vars))
1157 /* if rules ended */
1160 /* if this rule has additional conditions */
1163 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1181 /*-----------------------------------------------------------------*/
1182 /* replaceRule - does replacement of a matching pattern */
1183 /*-----------------------------------------------------------------*/
1185 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1187 lineNode *cl = NULL;
1188 lineNode *pl = NULL, *lhead = NULL;
1189 /* a long function name and long variable name can evaluate to
1190 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1191 char lb[MAX_PATTERN_LEN*4];
1193 lineNode *comment = NULL;
1195 /* collect all the comment lines in the source */
1196 for (cl = *shead; cl != stail; cl = cl->next)
1198 if (cl->line && (*cl->line == ';' || cl->isDebug))
1200 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1201 (comment = newLineNode (cl->line)));
1202 pl->isDebug = cl->isDebug;
1207 /* for all the lines in the replacement pattern do */
1208 for (pl = pr->replace; pl; pl = pl->next)
1218 /* if the line contains a variable */
1219 if (*l == '%' && isdigit (*(l + 1)))
1221 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1224 fprintf (stderr, "used unbound variable in replacement\n");
1232 while (isdigit (*l)) {
1242 cl = connectLine (cl, newLineNode (lb));
1244 lhead = cl = newLineNode (lb);
1247 /* add the comments if any to the head of list */
1250 lineNode *lc = comment;
1259 /* now we need to connect / replace the original chain */
1260 /* if there is a prev then change it */
1263 (*shead)->prev->next = lhead;
1264 lhead->prev = (*shead)->prev;
1267 /* now for the tail */
1268 if (stail && stail->next)
1270 stail->next->prev = cl;
1272 cl->next = stail->next;
1276 /* Returns TRUE if this line is a label definition.
1278 * If so, start will point to the start of the label name,
1279 * and len will be it's length.
1282 isLabelDefinition (const char *line, const char **start, int *len)
1284 const char *cp = line;
1286 /* This line is a label if if consists of:
1287 * [optional whitespace] followed by identifier chars
1288 * (alnum | $ | _ ) followed by a colon.
1291 while (*cp && isspace (*cp))
1303 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1308 if ((cp == *start) || (*cp != ':'))
1313 *len = (cp - (*start));
1317 /* Quick & dirty string hash function. */
1319 hashSymbolName (const char *name)
1325 hash = (hash << 6) ^ *name;
1334 return hash % HTAB_SIZE;
1337 /* Build a hash of all labels in the passed set of lines
1338 * and how many times they are referenced.
1341 buildLabelRefCountHash (lineNode * head)
1348 assert (labelHash == NULL);
1349 labelHash = newHashTable (HTAB_SIZE);
1351 /* First pass: locate all the labels. */
1356 if (isLabelDefinition (line->line, &label, &labelLen)
1357 && labelLen <= SDCC_NAME_MAX)
1359 labelHashEntry *entry;
1361 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1363 memcpy (entry->name, label, labelLen);
1364 entry->name[labelLen] = 0;
1365 entry->refCount = -1;
1367 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1373 /* Second pass: for each line, note all the referenced labels. */
1374 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1378 for (i = 0; i < HTAB_SIZE; i++)
1380 labelHashEntry *thisEntry;
1382 thisEntry = hTabFirstItemWK (labelHash, i);
1386 if (strstr (line->line, thisEntry->name))
1388 thisEntry->refCount++;
1390 thisEntry = hTabNextItemWK (labelHash);
1397 /* Spew the contents of the table. Debugging fun only. */
1398 for (i = 0; i < HTAB_SIZE; i++)
1400 labelHashEntry *thisEntry;
1402 thisEntry = hTabFirstItemWK (labelHash, i);
1406 fprintf (stderr, "label: %s ref %d\n",
1407 thisEntry->name, thisEntry->refCount);
1408 thisEntry = hTabNextItemWK (labelHash);
1414 /* How does this work?
1420 replace and restart.
1425 Where is stuff allocated?
1429 /*-----------------------------------------------------------------*/
1430 /* peepHole - matches & substitutes rules */
1431 /*-----------------------------------------------------------------*/
1433 peepHole (lineNode ** pls)
1437 lineNode *mtail = NULL;
1440 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1441 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1442 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1446 assert(labelHash == NULL);
1453 for (pr = rootRules; pr; pr = pr->next)
1455 for (spl = *pls; spl; spl = spl->next)
1457 /* if inline assembler then no peep hole */
1463 /* Tidy up any data stored in the hTab */
1466 if (matchRule (spl, &mtail, pr, *pls))
1471 replaceRule (pls, mtail, pr);
1473 replaceRule (&spl, mtail, pr);
1475 /* if restart rule type then
1476 start at the top again */
1485 hTabDeleteAll (pr->vars);
1486 Safe_free (pr->vars);
1490 freeTrace (&_G.values);
1493 } while (restart == TRUE);
1497 hTabDeleteAll (labelHash);
1498 freeTrace (&_G.labels);
1504 /*-----------------------------------------------------------------*/
1505 /* readFileIntoBuffer - reads a file into a string buffer */
1506 /*-----------------------------------------------------------------*/
1508 readFileIntoBuffer (char *fname)
1514 char lb[MAX_PATTERN_LEN];
1516 if (!(f = fopen (fname, "r")))
1518 fprintf (stderr, "cannot open peep rule file\n");
1522 while ((ch = fgetc (f)) != EOF)
1526 /* if we maxed out our local buffer */
1527 if (nch >= (MAX_PATTERN_LEN - 2))
1530 /* copy it into allocated buffer */
1533 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1534 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1538 rs = Safe_strdup (lb);
1544 /* if some charaters left over */
1548 /* copy it into allocated buffer */
1551 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1552 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1556 rs = Safe_strdup (lb);
1562 /*-----------------------------------------------------------------*/
1563 /* initPeepHole - initialises the peep hole optimizer stuff */
1564 /*-----------------------------------------------------------------*/
1570 /* read in the default rules */
1571 readRules (port->peep.default_rules);
1573 /* if we have any additional file read it too */
1574 if (options.peep_file)
1576 readRules (s = readFileIntoBuffer (options.peep_file));
1577 setToNull ((void **) &s);
1581 #if !OPT_DISABLE_PIC
1582 /* Convert the peep rules into pcode.
1583 NOTE: this is only support in the PIC port (at the moment)
1586 peepRules2pCode(rootRules);
1589 #if !OPT_DISABLE_PIC16
1590 /* Convert the peep rules into pcode.
1591 NOTE: this is only support in the PIC port (at the moment)
1592 and the PIC16 port (VR 030601)
1594 if (TARGET_IS_PIC16)
1595 pic16_peepRules2pCode(rootRules);