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 (strcmp(port->target,"ds400") == 0)) &&
216 (options.model == MODEL_FLAT24));
219 /*-----------------------------------------------------------------*/
220 /* portIsDS390 - return true if port is DS390 */
221 /*-----------------------------------------------------------------*/
222 FBYNAME (portIsDS390)
224 return ((strcmp(port->target,"ds390") == 0) ||
225 (strcmp(port->target,"ds400") == 0));
228 /*-----------------------------------------------------------------*/
229 /* flat24bitMode - will check to see if we are in flat24 mode */
230 /*-----------------------------------------------------------------*/
231 FBYNAME (flat24bitMode)
233 return (options.model == MODEL_FLAT24);
236 /*-----------------------------------------------------------------*/
237 /* xramMovcOption - check if using movc to read xram */
238 /*-----------------------------------------------------------------*/
239 FBYNAME (xramMovcOption)
241 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
249 /*-----------------------------------------------------------------*/
250 /* labelInRange - will check to see if label %5 is within range */
251 /*-----------------------------------------------------------------*/
252 FBYNAME (labelInRange)
254 /* assumes that %5 pattern variable has the label name */
255 char *lbl = hTabItemWithKey (vars, 5);
261 /* if the previous two instructions are "ljmp"s then don't
262 do it since it can be part of a jump table */
263 if (currPl->prev && currPl->prev->prev &&
264 strstr (currPl->prev->line, "ljmp") &&
265 strstr (currPl->prev->prev->line, "ljmp"))
268 /* calculate the label distance : the jump for reladdr can be
269 +/- 127 bytes, here Iam assuming that an average 8051
270 instruction is 2 bytes long, so if the label is more than
271 63 intructions away, the label is considered out of range
272 for a relative jump. we could get more precise this will
273 suffice for now since it catches > 90% cases */
274 dist = (pcDistance (currPl, lbl, TRUE) +
275 pcDistance (currPl, lbl, FALSE));
277 /* changed to 127, now that pcDistance return actual number of bytes */
278 if (!dist || dist > 127)
284 /*-----------------------------------------------------------------*/
285 /* labelIsReturnOnly - Check if label %5 is followed by RET */
286 /*-----------------------------------------------------------------*/
287 FBYNAME (labelIsReturnOnly)
289 /* assumes that %5 pattern variable has the label name */
290 const char *label, *p;
294 label = hTabItemWithKey (vars, 5);
295 if (!label) return FALSE;
298 for(pl = currPl; pl; pl = pl->next) {
299 if (pl->line && !pl->isDebug &&
300 pl->line[strlen(pl->line)-1] == ':') {
301 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
302 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
303 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
304 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
305 *(pl->line+5) != '$') {
306 return FALSE; /* non-local label encountered */
310 if (!pl) return FALSE; /* did not find the label */
312 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
314 for (p = pl->line; *p && isspace(*p); p++)
316 if (strcmp(p, "ret") == 0) return TRUE;
321 /*-----------------------------------------------------------------*/
322 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
323 /* usage of it in the code depends on a value from this section */
324 /*-----------------------------------------------------------------*/
325 FBYNAME (okToRemoveSLOC)
328 const char *sloc, *p;
329 int dummy1, dummy2, dummy3;
331 /* assumes that %1 as the SLOC name */
332 sloc = hTabItemWithKey (vars, 1);
333 if (sloc == NULL) return FALSE;
334 p = strstr(sloc, "sloc");
335 if (p == NULL) return FALSE;
337 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
338 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
339 /* the sloc name begins with that. Probably not really necessary */
341 /* Look for any occurance of this SLOC before the peephole match */
342 for (pl = currPl->prev; pl; pl = pl->prev) {
343 if (pl->line && !pl->isDebug && !pl->isComment
344 && *pl->line != ';' && strstr(pl->line, sloc))
347 /* Look for any occurance of this SLOC after the peephole match */
348 for (pl = endPl->next; pl; pl = pl->next) {
349 if (pl->line && !pl->isDebug && !pl->isComment
350 && *pl->line != ';' && strstr(pl->line, sloc))
353 return TRUE; /* safe for a peephole to remove it :) */
357 /*-----------------------------------------------------------------*/
358 /* operandsNotSame - check if %1 & %2 are the same */
359 /*-----------------------------------------------------------------*/
360 FBYNAME (operandsNotSame)
362 char *op1 = hTabItemWithKey (vars, 1);
363 char *op2 = hTabItemWithKey (vars, 2);
365 if (strcmp (op1, op2) == 0)
371 /*-----------------------------------------------------------------*/
372 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
373 /*-----------------------------------------------------------------*/
374 FBYNAME (operandsNotSame3)
376 char *op1 = hTabItemWithKey (vars, 1);
377 char *op2 = hTabItemWithKey (vars, 2);
378 char *op3 = hTabItemWithKey (vars, 3);
380 if ( (strcmp (op1, op2) == 0) ||
381 (strcmp (op1, op3) == 0) ||
382 (strcmp (op2, op3) == 0) )
388 /*-----------------------------------------------------------------*/
389 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
390 /*-----------------------------------------------------------------*/
391 FBYNAME (operandsNotSame4)
393 char *op1 = hTabItemWithKey (vars, 1);
394 char *op2 = hTabItemWithKey (vars, 2);
395 char *op3 = hTabItemWithKey (vars, 3);
396 char *op4 = hTabItemWithKey (vars, 4);
398 if ( (strcmp (op1, op2) == 0) ||
399 (strcmp (op1, op3) == 0) ||
400 (strcmp (op1, op4) == 0) ||
401 (strcmp (op2, op3) == 0) ||
402 (strcmp (op2, op4) == 0) ||
403 (strcmp (op3, op4) == 0) )
409 /*-----------------------------------------------------------------*/
410 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
411 /*-----------------------------------------------------------------*/
412 FBYNAME (operandsNotSame5)
414 char *op1 = hTabItemWithKey (vars, 1);
415 char *op2 = hTabItemWithKey (vars, 2);
416 char *op3 = hTabItemWithKey (vars, 3);
417 char *op4 = hTabItemWithKey (vars, 4);
418 char *op5 = hTabItemWithKey (vars, 5);
420 if ( (strcmp (op1, op2) == 0) ||
421 (strcmp (op1, op3) == 0) ||
422 (strcmp (op1, op4) == 0) ||
423 (strcmp (op1, op5) == 0) ||
424 (strcmp (op2, op3) == 0) ||
425 (strcmp (op2, op4) == 0) ||
426 (strcmp (op2, op5) == 0) ||
427 (strcmp (op3, op4) == 0) ||
428 (strcmp (op3, op5) == 0) ||
429 (strcmp (op4, op5) == 0) )
435 /*-----------------------------------------------------------------*/
436 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
437 /*-----------------------------------------------------------------*/
438 FBYNAME (operandsNotSame6)
440 char *op1 = hTabItemWithKey (vars, 1);
441 char *op2 = hTabItemWithKey (vars, 2);
442 char *op3 = hTabItemWithKey (vars, 3);
443 char *op4 = hTabItemWithKey (vars, 4);
444 char *op5 = hTabItemWithKey (vars, 5);
445 char *op6 = hTabItemWithKey (vars, 6);
447 if ( (strcmp (op1, op2) == 0) ||
448 (strcmp (op1, op3) == 0) ||
449 (strcmp (op1, op4) == 0) ||
450 (strcmp (op1, op5) == 0) ||
451 (strcmp (op1, op6) == 0) ||
452 (strcmp (op2, op3) == 0) ||
453 (strcmp (op2, op4) == 0) ||
454 (strcmp (op2, op5) == 0) ||
455 (strcmp (op2, op6) == 0) ||
456 (strcmp (op3, op4) == 0) ||
457 (strcmp (op3, op5) == 0) ||
458 (strcmp (op3, op6) == 0) ||
459 (strcmp (op4, op5) == 0) ||
460 (strcmp (op4, op6) == 0) ||
461 (strcmp (op5, op6) == 0) )
468 /*-----------------------------------------------------------------*/
469 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
470 /*-----------------------------------------------------------------*/
471 FBYNAME (operandsNotSame7)
473 char *op1 = hTabItemWithKey (vars, 1);
474 char *op2 = hTabItemWithKey (vars, 2);
475 char *op3 = hTabItemWithKey (vars, 3);
476 char *op4 = hTabItemWithKey (vars, 4);
477 char *op5 = hTabItemWithKey (vars, 5);
478 char *op6 = hTabItemWithKey (vars, 6);
479 char *op7 = hTabItemWithKey (vars, 7);
481 if ( (strcmp (op1, op2) == 0) ||
482 (strcmp (op1, op3) == 0) ||
483 (strcmp (op1, op4) == 0) ||
484 (strcmp (op1, op5) == 0) ||
485 (strcmp (op1, op6) == 0) ||
486 (strcmp (op1, op7) == 0) ||
487 (strcmp (op2, op3) == 0) ||
488 (strcmp (op2, op4) == 0) ||
489 (strcmp (op2, op5) == 0) ||
490 (strcmp (op2, op6) == 0) ||
491 (strcmp (op2, op7) == 0) ||
492 (strcmp (op3, op4) == 0) ||
493 (strcmp (op3, op5) == 0) ||
494 (strcmp (op3, op6) == 0) ||
495 (strcmp (op3, op7) == 0) ||
496 (strcmp (op4, op5) == 0) ||
497 (strcmp (op4, op6) == 0) ||
498 (strcmp (op4, op7) == 0) ||
499 (strcmp (op5, op6) == 0) ||
500 (strcmp (op5, op7) == 0) ||
501 (strcmp (op6, op7) == 0) )
507 /*-----------------------------------------------------------------*/
508 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
509 /*-----------------------------------------------------------------*/
510 FBYNAME (operandsNotSame8)
512 char *op1 = hTabItemWithKey (vars, 1);
513 char *op2 = hTabItemWithKey (vars, 2);
514 char *op3 = hTabItemWithKey (vars, 3);
515 char *op4 = hTabItemWithKey (vars, 4);
516 char *op5 = hTabItemWithKey (vars, 5);
517 char *op6 = hTabItemWithKey (vars, 6);
518 char *op7 = hTabItemWithKey (vars, 7);
519 char *op8 = hTabItemWithKey (vars, 8);
521 if ( (strcmp (op1, op2) == 0) ||
522 (strcmp (op1, op3) == 0) ||
523 (strcmp (op1, op4) == 0) ||
524 (strcmp (op1, op5) == 0) ||
525 (strcmp (op1, op6) == 0) ||
526 (strcmp (op1, op7) == 0) ||
527 (strcmp (op1, op8) == 0) ||
528 (strcmp (op2, op3) == 0) ||
529 (strcmp (op2, op4) == 0) ||
530 (strcmp (op2, op5) == 0) ||
531 (strcmp (op2, op6) == 0) ||
532 (strcmp (op2, op7) == 0) ||
533 (strcmp (op2, op8) == 0) ||
534 (strcmp (op3, op4) == 0) ||
535 (strcmp (op3, op5) == 0) ||
536 (strcmp (op3, op6) == 0) ||
537 (strcmp (op3, op7) == 0) ||
538 (strcmp (op3, op8) == 0) ||
539 (strcmp (op4, op5) == 0) ||
540 (strcmp (op4, op6) == 0) ||
541 (strcmp (op4, op7) == 0) ||
542 (strcmp (op4, op8) == 0) ||
543 (strcmp (op5, op6) == 0) ||
544 (strcmp (op5, op7) == 0) ||
545 (strcmp (op5, op8) == 0) ||
546 (strcmp (op6, op7) == 0) ||
547 (strcmp (op6, op8) == 0) ||
548 (strcmp (op7, op8) == 0) )
557 * takes two parameters: a variable (bound to a label name)
558 * and an expected reference count.
560 * Returns TRUE if that label is defined and referenced exactly
561 * the given number of times.
563 FBYNAME (labelRefCount)
565 int varNumber, expectedRefCount;
568 /* If we don't have the label hash table yet, build it. */
571 buildLabelRefCountHash (head);
574 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
576 char *label = hTabItemWithKey (vars, varNumber);
580 labelHashEntry *entry;
582 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
586 if (!strcmp (label, entry->name))
590 entry = hTabNextItemWK (labelHash);
596 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
597 label, entry->refCount, expectedRefCount);
600 rc = (expectedRefCount == entry->refCount);
604 fprintf (stderr, "*** internal error: no label has entry for"
605 " %s in labelRefCount peephole.\n",
611 fprintf (stderr, "*** internal error: var %d not bound"
612 " in peephole labelRefCount rule.\n",
620 "*** internal error: labelRefCount peephole restriction"
621 " malformed: %s\n", cmdLine);
626 /*-----------------------------------------------------------------*/
627 /* callFuncByName - calls a function as defined in the table */
628 /*-----------------------------------------------------------------*/
630 callFuncByName (char *fname,
639 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
644 "labelInRange", labelInRange
648 "operandsNotSame", operandsNotSame
652 "operandsNotSame3", operandsNotSame3
656 "operandsNotSame4", operandsNotSame4
660 "operandsNotSame5", operandsNotSame5
664 "operandsNotSame6", operandsNotSame6
668 "operandsNotSame7", operandsNotSame7
672 "operandsNotSame8", operandsNotSame8
676 "24bitMode", flat24bitMode
680 "xramMovcOption", xramMovcOption
684 "labelRefCount", labelRefCount
688 "portIsDS390", portIsDS390
691 "labelIsReturnOnly", labelIsReturnOnly
694 "okToRemoveSLOC", okToRemoveSLOC
697 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
701 char *cmdCopy, *funcName, *funcArgs;
704 /* Isolate the function name part (we are passed the full condition
705 * string including arguments)
707 cmdCopy = Safe_strdup(fname);
708 funcName = strtok(cmdCopy, " \t");
709 funcArgs = strtok(NULL, "");
711 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
713 if (strcmp (ftab[i].fname, funcName) == 0)
715 rc = (*ftab[i].func) (vars, currPl, endPl, head,
725 "could not find named function \"%s\" in "
726 "peephole function table\n",
728 // If the function couldn't be found, let's assume it's
729 // a bad rule and refuse it.
736 /*-----------------------------------------------------------------*/
737 /* printLine - prints a line chain into a given file */
738 /*-----------------------------------------------------------------*/
740 printLine (lineNode * head, FILE * of)
747 /* don't indent comments & labels */
749 (*head->line == ';' ||
750 head->line[strlen (head->line) - 1] == ':')) {
751 fprintf (of, "%s\n", head->line);
753 if (head->isInline && *head->line=='#') {
754 // comment out preprocessor directives in inline asm
757 fprintf (of, "\t%s\n", head->line);
763 /*-----------------------------------------------------------------*/
764 /* newPeepRule - creates a new peeprule and attach it to the root */
765 /*-----------------------------------------------------------------*/
767 newPeepRule (lineNode * match,
774 pr = Safe_alloc ( sizeof (peepRule));
776 pr->replace = replace;
777 pr->restart = restart;
781 pr->cond = Safe_strdup (cond);
786 pr->vars = newHashTable (100);
788 /* if root is empty */
790 rootRules = currRule = pr;
792 currRule = currRule->next = pr;
797 /*-----------------------------------------------------------------*/
798 /* newLineNode - creates a new peep line */
799 /*-----------------------------------------------------------------*/
801 newLineNode (char *line)
805 pl = Safe_alloc ( sizeof (lineNode));
806 pl->line = Safe_strdup (line);
810 /*-----------------------------------------------------------------*/
811 /* connectLine - connects two lines */
812 /*-----------------------------------------------------------------*/
814 connectLine (lineNode * pl1, lineNode * pl2)
818 fprintf (stderr, "trying to connect null line\n");
828 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
829 if (!*x) { fprintf(stderr,y); return ; } }
831 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
832 if (!*x) { fprintf(stderr,z); return ; } }
833 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
834 if (!*x) { fprintf(stderr,z); return ; } }
836 /*-----------------------------------------------------------------*/
837 /* getPeepLine - parses the peep lines */
838 /*-----------------------------------------------------------------*/
840 getPeepLine (lineNode ** head, char **bpp)
842 char lines[MAX_PATTERN_LEN];
845 lineNode *currL = NULL;
852 fprintf (stderr, "unexpected end of match pattern\n");
859 while (isspace (*bp) ||
870 /* read till end of line */
872 while ((*bp != '\n' && *bp != '}') && *bp)
877 *head = currL = newLineNode (lines);
879 currL = connectLine (currL, newLineNode (lines));
885 /*-----------------------------------------------------------------*/
886 /* readRules - reads the rules from a string buffer */
887 /*-----------------------------------------------------------------*/
892 char lines[MAX_PATTERN_LEN];
896 lineNode *currL = NULL;
902 /* look for the token "replace" that is the
904 while (*bp && strncmp (bp, "replace", 7))
911 /* then look for either "restart" or '{' */
912 while (strncmp (bp, "restart", 7) &&
919 fprintf (stderr, "expected 'restart' or '{'\n");
927 { /* must be restart */
929 bp += strlen ("restart");
931 EXPECT_CHR (bp, '{', "expected '{'\n");
935 /* skip thru all the blank space */
936 SKIP_SPACE (bp, "unexpected end of rule\n");
938 match = replace = currL = NULL;
939 /* we are the start of a rule */
940 getPeepLine (&match, &bp);
942 /* now look for by */
943 EXPECT_STR (bp, "by", "expected 'by'\n");
945 /* then look for a '{' */
946 EXPECT_CHR (bp, '{', "expected '{'\n");
949 SKIP_SPACE (bp, "unexpected end of rule\n");
950 getPeepLine (&replace, &bp);
952 /* look for a 'if' */
953 while ((isspace (*bp) || *bp == '\n') && *bp)
956 if (strncmp (bp, "if", 2) == 0)
959 while ((isspace (*bp) || *bp == '\n') && *bp)
963 fprintf (stderr, "expected condition name\n");
967 /* look for the condition */
969 while (*bp && (*bp != '\n'))
975 newPeepRule (match, replace, lines, restart);
978 newPeepRule (match, replace, NULL, restart);
983 /*-----------------------------------------------------------------*/
984 /* keyForVar - returns the numeric key for a var */
985 /*-----------------------------------------------------------------*/
1000 /*-----------------------------------------------------------------*/
1001 /* bindVar - binds a value to a variable in the given hashtable */
1002 /*-----------------------------------------------------------------*/
1004 bindVar (int key, char **s, hTab ** vtab)
1006 char vval[MAX_PATTERN_LEN];
1010 /* first get the value of the variable */
1012 /* the value is ended by a ',' or space or newline or null or ) */
1021 /* if we find a '(' then we need to balance it */
1033 // include the trailing ')'
1042 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1044 hTabAddItem (vtab, key, vvx);
1047 /*-----------------------------------------------------------------*/
1048 /* matchLine - matches one line */
1049 /*-----------------------------------------------------------------*/
1051 matchLine (char *s, char *d, hTab ** vars)
1060 /* skip white space in both */
1061 while (isspace (*s))
1063 while (isspace (*d))
1066 /* if the destination is a var */
1067 if (*d == '%' && isdigit (*(d + 1)))
1069 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1070 /* if the variable is already bound
1071 then it MUST match with dest */
1079 /* variable not bound we need to
1081 bindVar (keyForVar (d + 1), &s, vars);
1083 /* in either case go past the variable */
1085 while (isdigit (*d))
1089 /* they should be an exact match other wise */
1092 while (isspace (*s))
1094 while (isspace (*d))
1102 /* get rid of the trailing spaces
1103 in both source & destination */
1105 while (isspace (*s))
1109 while (isspace (*d))
1112 /* after all this if only one of them
1113 has something left over then no match */
1120 /*-----------------------------------------------------------------*/
1121 /* matchRule - matches a all the rule lines */
1122 /*-----------------------------------------------------------------*/
1124 matchRule (lineNode * pl,
1129 lineNode *spl; /* source pl */
1130 lineNode *rpl; /* rule peep line */
1132 /* setToNull((void **) &pr->vars); */
1133 /* pr->vars = newHashTable(100); */
1135 /* for all the lines defined in the rule */
1141 /* if the source line starts with a ';' then
1142 comment line don't process or the source line
1143 contains == . debugger information skip it */
1145 (*spl->line == ';' || spl->isDebug))
1151 if (!matchLine (spl->line, rpl->line, &pr->vars))
1159 /* if rules ended */
1162 /* if this rule has additional conditions */
1165 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1183 /*-----------------------------------------------------------------*/
1184 /* replaceRule - does replacement of a matching pattern */
1185 /*-----------------------------------------------------------------*/
1187 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1189 lineNode *cl = NULL;
1190 lineNode *pl = NULL, *lhead = NULL;
1191 /* a long function name and long variable name can evaluate to
1192 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1193 char lb[MAX_PATTERN_LEN*4];
1195 lineNode *comment = NULL;
1197 /* collect all the comment lines in the source */
1198 for (cl = *shead; cl != stail; cl = cl->next)
1200 if (cl->line && (*cl->line == ';' || cl->isDebug))
1202 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1203 (comment = newLineNode (cl->line)));
1204 pl->isDebug = cl->isDebug;
1209 /* for all the lines in the replacement pattern do */
1210 for (pl = pr->replace; pl; pl = pl->next)
1220 /* if the line contains a variable */
1221 if (*l == '%' && isdigit (*(l + 1)))
1223 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1226 fprintf (stderr, "used unbound variable in replacement\n");
1234 while (isdigit (*l)) {
1244 cl = connectLine (cl, newLineNode (lb));
1246 lhead = cl = newLineNode (lb);
1249 /* add the comments if any to the head of list */
1252 lineNode *lc = comment;
1261 /* now we need to connect / replace the original chain */
1262 /* if there is a prev then change it */
1265 (*shead)->prev->next = lhead;
1266 lhead->prev = (*shead)->prev;
1269 /* now for the tail */
1270 if (stail && stail->next)
1272 stail->next->prev = cl;
1274 cl->next = stail->next;
1278 /* Returns TRUE if this line is a label definition.
1280 * If so, start will point to the start of the label name,
1281 * and len will be it's length.
1284 isLabelDefinition (const char *line, const char **start, int *len)
1286 const char *cp = line;
1288 /* This line is a label if if consists of:
1289 * [optional whitespace] followed by identifier chars
1290 * (alnum | $ | _ ) followed by a colon.
1293 while (*cp && isspace (*cp))
1305 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1310 if ((cp == *start) || (*cp != ':'))
1315 *len = (cp - (*start));
1319 /* Quick & dirty string hash function. */
1321 hashSymbolName (const char *name)
1327 hash = (hash << 6) ^ *name;
1336 return hash % HTAB_SIZE;
1339 /* Build a hash of all labels in the passed set of lines
1340 * and how many times they are referenced.
1343 buildLabelRefCountHash (lineNode * head)
1350 assert (labelHash == NULL);
1351 labelHash = newHashTable (HTAB_SIZE);
1353 /* First pass: locate all the labels. */
1358 if (isLabelDefinition (line->line, &label, &labelLen)
1359 && labelLen <= SDCC_NAME_MAX)
1361 labelHashEntry *entry;
1363 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1365 memcpy (entry->name, label, labelLen);
1366 entry->name[labelLen] = 0;
1367 entry->refCount = -1;
1369 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1375 /* Second pass: for each line, note all the referenced labels. */
1376 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1380 for (i = 0; i < HTAB_SIZE; i++)
1382 labelHashEntry *thisEntry;
1384 thisEntry = hTabFirstItemWK (labelHash, i);
1388 if (strstr (line->line, thisEntry->name))
1390 thisEntry->refCount++;
1392 thisEntry = hTabNextItemWK (labelHash);
1399 /* Spew the contents of the table. Debugging fun only. */
1400 for (i = 0; i < HTAB_SIZE; i++)
1402 labelHashEntry *thisEntry;
1404 thisEntry = hTabFirstItemWK (labelHash, i);
1408 fprintf (stderr, "label: %s ref %d\n",
1409 thisEntry->name, thisEntry->refCount);
1410 thisEntry = hTabNextItemWK (labelHash);
1416 /* How does this work?
1422 replace and restart.
1427 Where is stuff allocated?
1431 /*-----------------------------------------------------------------*/
1432 /* peepHole - matches & substitutes rules */
1433 /*-----------------------------------------------------------------*/
1435 peepHole (lineNode ** pls)
1439 lineNode *mtail = NULL;
1442 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1443 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1444 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1448 assert(labelHash == NULL);
1455 for (pr = rootRules; pr; pr = pr->next)
1457 for (spl = *pls; spl; spl = spl->next)
1459 /* if inline assembler then no peep hole */
1465 /* Tidy up any data stored in the hTab */
1468 if (matchRule (spl, &mtail, pr, *pls))
1473 replaceRule (pls, mtail, pr);
1475 replaceRule (&spl, mtail, pr);
1477 /* if restart rule type then
1478 start at the top again */
1487 hTabDeleteAll (pr->vars);
1488 Safe_free (pr->vars);
1492 freeTrace (&_G.values);
1495 } while (restart == TRUE);
1499 hTabDeleteAll (labelHash);
1500 freeTrace (&_G.labels);
1506 /*-----------------------------------------------------------------*/
1507 /* readFileIntoBuffer - reads a file into a string buffer */
1508 /*-----------------------------------------------------------------*/
1510 readFileIntoBuffer (char *fname)
1516 char lb[MAX_PATTERN_LEN];
1518 if (!(f = fopen (fname, "r")))
1520 fprintf (stderr, "cannot open peep rule file\n");
1524 while ((ch = fgetc (f)) != EOF)
1528 /* if we maxed out our local buffer */
1529 if (nch >= (MAX_PATTERN_LEN - 2))
1532 /* copy it into allocated buffer */
1535 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1536 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1540 rs = Safe_strdup (lb);
1546 /* if some charaters left over */
1550 /* copy it into allocated buffer */
1553 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1554 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1558 rs = Safe_strdup (lb);
1564 /*-----------------------------------------------------------------*/
1565 /* initPeepHole - initialises the peep hole optimizer stuff */
1566 /*-----------------------------------------------------------------*/
1572 /* read in the default rules */
1573 readRules (port->peep.default_rules);
1575 /* if we have any additional file read it too */
1576 if (options.peep_file)
1578 readRules (s = readFileIntoBuffer (options.peep_file));
1579 setToNull ((void **) &s);
1583 #if !OPT_DISABLE_PIC
1584 /* Convert the peep rules into pcode.
1585 NOTE: this is only support in the PIC port (at the moment)
1588 peepRules2pCode(rootRules);
1591 #if !OPT_DISABLE_PIC16
1592 /* Convert the peep rules into pcode.
1593 NOTE: this is only support in the PIC port (at the moment)
1594 and the PIC16 port (VR 030601)
1596 if (TARGET_IS_PIC16)
1597 pic16_peepRules2pCode(rootRules);