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 *head, \
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;
316 /*-----------------------------------------------------------------*/
317 /* operandsNotSame - check if %1 & %2 are the same */
318 /*-----------------------------------------------------------------*/
319 FBYNAME (operandsNotSame)
321 char *op1 = hTabItemWithKey (vars, 1);
322 char *op2 = hTabItemWithKey (vars, 2);
324 if (strcmp (op1, op2) == 0)
330 /*-----------------------------------------------------------------*/
331 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
332 /*-----------------------------------------------------------------*/
333 FBYNAME (operandsNotSame3)
335 char *op1 = hTabItemWithKey (vars, 1);
336 char *op2 = hTabItemWithKey (vars, 2);
337 char *op3 = hTabItemWithKey (vars, 3);
339 if ( (strcmp (op1, op2) == 0) ||
340 (strcmp (op1, op3) == 0) ||
341 (strcmp (op2, op3) == 0) )
347 /*-----------------------------------------------------------------*/
348 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
349 /*-----------------------------------------------------------------*/
350 FBYNAME (operandsNotSame4)
352 char *op1 = hTabItemWithKey (vars, 1);
353 char *op2 = hTabItemWithKey (vars, 2);
354 char *op3 = hTabItemWithKey (vars, 3);
355 char *op4 = hTabItemWithKey (vars, 4);
357 if ( (strcmp (op1, op2) == 0) ||
358 (strcmp (op1, op3) == 0) ||
359 (strcmp (op1, op4) == 0) ||
360 (strcmp (op2, op3) == 0) ||
361 (strcmp (op2, op4) == 0) ||
362 (strcmp (op3, op4) == 0) )
368 /*-----------------------------------------------------------------*/
369 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
370 /*-----------------------------------------------------------------*/
371 FBYNAME (operandsNotSame5)
373 char *op1 = hTabItemWithKey (vars, 1);
374 char *op2 = hTabItemWithKey (vars, 2);
375 char *op3 = hTabItemWithKey (vars, 3);
376 char *op4 = hTabItemWithKey (vars, 4);
377 char *op5 = hTabItemWithKey (vars, 5);
379 if ( (strcmp (op1, op2) == 0) ||
380 (strcmp (op1, op3) == 0) ||
381 (strcmp (op1, op4) == 0) ||
382 (strcmp (op1, op5) == 0) ||
383 (strcmp (op2, op3) == 0) ||
384 (strcmp (op2, op4) == 0) ||
385 (strcmp (op2, op5) == 0) ||
386 (strcmp (op3, op4) == 0) ||
387 (strcmp (op3, op5) == 0) ||
388 (strcmp (op4, op5) == 0) )
394 /*-----------------------------------------------------------------*/
395 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
396 /*-----------------------------------------------------------------*/
397 FBYNAME (operandsNotSame6)
399 char *op1 = hTabItemWithKey (vars, 1);
400 char *op2 = hTabItemWithKey (vars, 2);
401 char *op3 = hTabItemWithKey (vars, 3);
402 char *op4 = hTabItemWithKey (vars, 4);
403 char *op5 = hTabItemWithKey (vars, 5);
404 char *op6 = hTabItemWithKey (vars, 6);
406 if ( (strcmp (op1, op2) == 0) ||
407 (strcmp (op1, op3) == 0) ||
408 (strcmp (op1, op4) == 0) ||
409 (strcmp (op1, op5) == 0) ||
410 (strcmp (op1, op6) == 0) ||
411 (strcmp (op2, op3) == 0) ||
412 (strcmp (op2, op4) == 0) ||
413 (strcmp (op2, op5) == 0) ||
414 (strcmp (op2, op6) == 0) ||
415 (strcmp (op3, op4) == 0) ||
416 (strcmp (op3, op5) == 0) ||
417 (strcmp (op3, op6) == 0) ||
418 (strcmp (op4, op5) == 0) ||
419 (strcmp (op4, op6) == 0) ||
420 (strcmp (op5, op6) == 0) )
427 /*-----------------------------------------------------------------*/
428 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
429 /*-----------------------------------------------------------------*/
430 FBYNAME (operandsNotSame7)
432 char *op1 = hTabItemWithKey (vars, 1);
433 char *op2 = hTabItemWithKey (vars, 2);
434 char *op3 = hTabItemWithKey (vars, 3);
435 char *op4 = hTabItemWithKey (vars, 4);
436 char *op5 = hTabItemWithKey (vars, 5);
437 char *op6 = hTabItemWithKey (vars, 6);
438 char *op7 = hTabItemWithKey (vars, 7);
440 if ( (strcmp (op1, op2) == 0) ||
441 (strcmp (op1, op3) == 0) ||
442 (strcmp (op1, op4) == 0) ||
443 (strcmp (op1, op5) == 0) ||
444 (strcmp (op1, op6) == 0) ||
445 (strcmp (op1, op7) == 0) ||
446 (strcmp (op2, op3) == 0) ||
447 (strcmp (op2, op4) == 0) ||
448 (strcmp (op2, op5) == 0) ||
449 (strcmp (op2, op6) == 0) ||
450 (strcmp (op2, op7) == 0) ||
451 (strcmp (op3, op4) == 0) ||
452 (strcmp (op3, op5) == 0) ||
453 (strcmp (op3, op6) == 0) ||
454 (strcmp (op3, op7) == 0) ||
455 (strcmp (op4, op5) == 0) ||
456 (strcmp (op4, op6) == 0) ||
457 (strcmp (op4, op7) == 0) ||
458 (strcmp (op5, op6) == 0) ||
459 (strcmp (op5, op7) == 0) ||
460 (strcmp (op6, op7) == 0) )
466 /*-----------------------------------------------------------------*/
467 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
468 /*-----------------------------------------------------------------*/
469 FBYNAME (operandsNotSame8)
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);
478 char *op8 = hTabItemWithKey (vars, 8);
480 if ( (strcmp (op1, op2) == 0) ||
481 (strcmp (op1, op3) == 0) ||
482 (strcmp (op1, op4) == 0) ||
483 (strcmp (op1, op5) == 0) ||
484 (strcmp (op1, op6) == 0) ||
485 (strcmp (op1, op7) == 0) ||
486 (strcmp (op1, op8) == 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 (op2, op8) == 0) ||
493 (strcmp (op3, op4) == 0) ||
494 (strcmp (op3, op5) == 0) ||
495 (strcmp (op3, op6) == 0) ||
496 (strcmp (op3, op7) == 0) ||
497 (strcmp (op3, op8) == 0) ||
498 (strcmp (op4, op5) == 0) ||
499 (strcmp (op4, op6) == 0) ||
500 (strcmp (op4, op7) == 0) ||
501 (strcmp (op4, op8) == 0) ||
502 (strcmp (op5, op6) == 0) ||
503 (strcmp (op5, op7) == 0) ||
504 (strcmp (op5, op8) == 0) ||
505 (strcmp (op6, op7) == 0) ||
506 (strcmp (op6, op8) == 0) ||
507 (strcmp (op7, op8) == 0) )
516 * takes two parameters: a variable (bound to a label name)
517 * and an expected reference count.
519 * Returns TRUE if that label is defined and referenced exactly
520 * the given number of times.
522 FBYNAME (labelRefCount)
524 int varNumber, expectedRefCount;
527 /* If we don't have the label hash table yet, build it. */
530 buildLabelRefCountHash (head);
533 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
535 char *label = hTabItemWithKey (vars, varNumber);
539 labelHashEntry *entry;
541 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
545 if (!strcmp (label, entry->name))
549 entry = hTabNextItemWK (labelHash);
555 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
556 label, entry->refCount, expectedRefCount);
559 rc = (expectedRefCount == entry->refCount);
563 fprintf (stderr, "*** internal error: no label has entry for"
564 " %s in labelRefCount peephole.\n",
570 fprintf (stderr, "*** internal error: var %d not bound"
571 " in peephole labelRefCount rule.\n",
579 "*** internal error: labelRefCount peephole restriction"
580 " malformed: %s\n", cmdLine);
585 /*-----------------------------------------------------------------*/
586 /* callFuncByName - calls a function as defined in the table */
587 /*-----------------------------------------------------------------*/
589 callFuncByName (char *fname,
597 int (*func) (hTab *, lineNode *, lineNode *, const char *);
602 "labelInRange", labelInRange
606 "operandsNotSame", operandsNotSame
610 "operandsNotSame3", operandsNotSame3
614 "operandsNotSame4", operandsNotSame4
618 "operandsNotSame5", operandsNotSame5
622 "operandsNotSame6", operandsNotSame6
626 "operandsNotSame7", operandsNotSame7
630 "operandsNotSame8", operandsNotSame8
634 "24bitMode", flat24bitMode
638 "xramMovcOption", xramMovcOption
642 "labelRefCount", labelRefCount
646 "portIsDS390", portIsDS390
649 "labelIsReturnOnly", labelIsReturnOnly
652 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
656 char *cmdCopy, *funcName, *funcArgs;
659 /* Isolate the function name part (we are passed the full condition
660 * string including arguments)
662 cmdCopy = Safe_strdup(fname);
663 funcName = strtok(cmdCopy, " \t");
664 funcArgs = strtok(NULL, "");
666 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
668 if (strcmp (ftab[i].fname, funcName) == 0)
670 rc = (*ftab[i].func) (vars, currPl, head,
680 "could not find named function \"%s\" in "
681 "peephole function table\n",
683 // If the function couldn't be found, let's assume it's
684 // a bad rule and refuse it.
691 /*-----------------------------------------------------------------*/
692 /* printLine - prints a line chain into a given file */
693 /*-----------------------------------------------------------------*/
695 printLine (lineNode * head, FILE * of)
702 /* don't indent comments & labels */
704 (*head->line == ';' ||
705 head->line[strlen (head->line) - 1] == ':')) {
706 fprintf (of, "%s\n", head->line);
708 if (head->isInline && *head->line=='#') {
709 // comment out preprocessor directives in inline asm
712 fprintf (of, "\t%s\n", head->line);
718 /*-----------------------------------------------------------------*/
719 /* newPeepRule - creates a new peeprule and attach it to the root */
720 /*-----------------------------------------------------------------*/
722 newPeepRule (lineNode * match,
729 pr = Safe_alloc ( sizeof (peepRule));
731 pr->replace = replace;
732 pr->restart = restart;
736 pr->cond = Safe_strdup (cond);
741 pr->vars = newHashTable (100);
743 /* if root is empty */
745 rootRules = currRule = pr;
747 currRule = currRule->next = pr;
752 /*-----------------------------------------------------------------*/
753 /* newLineNode - creates a new peep line */
754 /*-----------------------------------------------------------------*/
756 newLineNode (char *line)
760 pl = Safe_alloc ( sizeof (lineNode));
761 pl->line = Safe_strdup (line);
765 /*-----------------------------------------------------------------*/
766 /* connectLine - connects two lines */
767 /*-----------------------------------------------------------------*/
769 connectLine (lineNode * pl1, lineNode * pl2)
773 fprintf (stderr, "trying to connect null line\n");
783 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
784 if (!*x) { fprintf(stderr,y); return ; } }
786 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
787 if (!*x) { fprintf(stderr,z); return ; } }
788 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
789 if (!*x) { fprintf(stderr,z); return ; } }
791 /*-----------------------------------------------------------------*/
792 /* getPeepLine - parses the peep lines */
793 /*-----------------------------------------------------------------*/
795 getPeepLine (lineNode ** head, char **bpp)
797 char lines[MAX_PATTERN_LEN];
800 lineNode *currL = NULL;
807 fprintf (stderr, "unexpected end of match pattern\n");
814 while (isspace (*bp) ||
825 /* read till end of line */
827 while ((*bp != '\n' && *bp != '}') && *bp)
832 *head = currL = newLineNode (lines);
834 currL = connectLine (currL, newLineNode (lines));
840 /*-----------------------------------------------------------------*/
841 /* readRules - reads the rules from a string buffer */
842 /*-----------------------------------------------------------------*/
847 char lines[MAX_PATTERN_LEN];
851 lineNode *currL = NULL;
857 /* look for the token "replace" that is the
859 while (*bp && strncmp (bp, "replace", 7))
866 /* then look for either "restart" or '{' */
867 while (strncmp (bp, "restart", 7) &&
874 fprintf (stderr, "expected 'restart' or '{'\n");
882 { /* must be restart */
884 bp += strlen ("restart");
886 EXPECT_CHR (bp, '{', "expected '{'\n");
890 /* skip thru all the blank space */
891 SKIP_SPACE (bp, "unexpected end of rule\n");
893 match = replace = currL = NULL;
894 /* we are the start of a rule */
895 getPeepLine (&match, &bp);
897 /* now look for by */
898 EXPECT_STR (bp, "by", "expected 'by'\n");
900 /* then look for a '{' */
901 EXPECT_CHR (bp, '{', "expected '{'\n");
904 SKIP_SPACE (bp, "unexpected end of rule\n");
905 getPeepLine (&replace, &bp);
907 /* look for a 'if' */
908 while ((isspace (*bp) || *bp == '\n') && *bp)
911 if (strncmp (bp, "if", 2) == 0)
914 while ((isspace (*bp) || *bp == '\n') && *bp)
918 fprintf (stderr, "expected condition name\n");
922 /* look for the condition */
924 while (*bp && (*bp != '\n'))
930 newPeepRule (match, replace, lines, restart);
933 newPeepRule (match, replace, NULL, restart);
938 /*-----------------------------------------------------------------*/
939 /* keyForVar - returns the numeric key for a var */
940 /*-----------------------------------------------------------------*/
955 /*-----------------------------------------------------------------*/
956 /* bindVar - binds a value to a variable in the given hashtable */
957 /*-----------------------------------------------------------------*/
959 bindVar (int key, char **s, hTab ** vtab)
961 char vval[MAX_PATTERN_LEN];
965 /* first get the value of the variable */
967 /* the value is ended by a ',' or space or newline or null or ) */
976 /* if we find a '(' then we need to balance it */
988 // include the trailing ')'
997 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
999 hTabAddItem (vtab, key, vvx);
1002 /*-----------------------------------------------------------------*/
1003 /* matchLine - matches one line */
1004 /*-----------------------------------------------------------------*/
1006 matchLine (char *s, char *d, hTab ** vars)
1015 /* skip white space in both */
1016 while (isspace (*s))
1018 while (isspace (*d))
1021 /* if the destination is a var */
1022 if (*d == '%' && isdigit (*(d + 1)))
1024 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1025 /* if the variable is already bound
1026 then it MUST match with dest */
1034 /* variable not bound we need to
1036 bindVar (keyForVar (d + 1), &s, vars);
1038 /* in either case go past the variable */
1040 while (isdigit (*d))
1044 /* they should be an exact match other wise */
1047 while (isspace (*s))
1049 while (isspace (*d))
1057 /* get rid of the trailing spaces
1058 in both source & destination */
1060 while (isspace (*s))
1064 while (isspace (*d))
1067 /* after all this if only one of them
1068 has something left over then no match */
1075 /*-----------------------------------------------------------------*/
1076 /* matchRule - matches a all the rule lines */
1077 /*-----------------------------------------------------------------*/
1079 matchRule (lineNode * pl,
1084 lineNode *spl; /* source pl */
1085 lineNode *rpl; /* rule peep line */
1087 /* setToNull((void **) &pr->vars); */
1088 /* pr->vars = newHashTable(100); */
1090 /* for all the lines defined in the rule */
1096 /* if the source line starts with a ';' then
1097 comment line don't process or the source line
1098 contains == . debugger information skip it */
1100 (*spl->line == ';' || spl->isDebug))
1106 if (!matchLine (spl->line, rpl->line, &pr->vars))
1114 /* if rules ended */
1117 /* if this rule has additional conditions */
1120 if (callFuncByName (pr->cond, pr->vars, pl, head))
1138 /*-----------------------------------------------------------------*/
1139 /* replaceRule - does replacement of a matching pattern */
1140 /*-----------------------------------------------------------------*/
1142 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1144 lineNode *cl = NULL;
1145 lineNode *pl = NULL, *lhead = NULL;
1146 /* a long function name and long variable name can evaluate to
1147 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1148 char lb[MAX_PATTERN_LEN*4];
1150 lineNode *comment = NULL;
1152 /* collect all the comment lines in the source */
1153 for (cl = *shead; cl != stail; cl = cl->next)
1155 if (cl->line && (*cl->line == ';' || cl->isDebug))
1157 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1158 (comment = newLineNode (cl->line)));
1159 pl->isDebug = cl->isDebug;
1164 /* for all the lines in the replacement pattern do */
1165 for (pl = pr->replace; pl; pl = pl->next)
1175 /* if the line contains a variable */
1176 if (*l == '%' && isdigit (*(l + 1)))
1178 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1181 fprintf (stderr, "used unbound variable in replacement\n");
1189 while (isdigit (*l)) {
1199 cl = connectLine (cl, newLineNode (lb));
1201 lhead = cl = newLineNode (lb);
1204 /* add the comments if any to the head of list */
1207 lineNode *lc = comment;
1216 /* now we need to connect / replace the original chain */
1217 /* if there is a prev then change it */
1220 (*shead)->prev->next = lhead;
1221 lhead->prev = (*shead)->prev;
1224 /* now for the tail */
1225 if (stail && stail->next)
1227 stail->next->prev = cl;
1229 cl->next = stail->next;
1233 /* Returns TRUE if this line is a label definition.
1235 * If so, start will point to the start of the label name,
1236 * and len will be it's length.
1239 isLabelDefinition (const char *line, const char **start, int *len)
1241 const char *cp = line;
1243 /* This line is a label if if consists of:
1244 * [optional whitespace] followed by identifier chars
1245 * (alnum | $ | _ ) followed by a colon.
1248 while (*cp && isspace (*cp))
1260 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1265 if ((cp == *start) || (*cp != ':'))
1270 *len = (cp - (*start));
1274 /* Quick & dirty string hash function. */
1276 hashSymbolName (const char *name)
1282 hash = (hash << 6) ^ *name;
1291 return hash % HTAB_SIZE;
1294 /* Build a hash of all labels in the passed set of lines
1295 * and how many times they are referenced.
1298 buildLabelRefCountHash (lineNode * head)
1305 assert (labelHash == NULL);
1306 labelHash = newHashTable (HTAB_SIZE);
1308 /* First pass: locate all the labels. */
1313 if (isLabelDefinition (line->line, &label, &labelLen)
1314 && labelLen <= SDCC_NAME_MAX)
1316 labelHashEntry *entry;
1318 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1320 memcpy (entry->name, label, labelLen);
1321 entry->name[labelLen] = 0;
1322 entry->refCount = -1;
1324 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1330 /* Second pass: for each line, note all the referenced labels. */
1331 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1335 for (i = 0; i < HTAB_SIZE; i++)
1337 labelHashEntry *thisEntry;
1339 thisEntry = hTabFirstItemWK (labelHash, i);
1343 if (strstr (line->line, thisEntry->name))
1345 thisEntry->refCount++;
1347 thisEntry = hTabNextItemWK (labelHash);
1354 /* Spew the contents of the table. Debugging fun only. */
1355 for (i = 0; i < HTAB_SIZE; i++)
1357 labelHashEntry *thisEntry;
1359 thisEntry = hTabFirstItemWK (labelHash, i);
1363 fprintf (stderr, "label: %s ref %d\n",
1364 thisEntry->name, thisEntry->refCount);
1365 thisEntry = hTabNextItemWK (labelHash);
1371 /* How does this work?
1377 replace and restart.
1382 Where is stuff allocated?
1386 /*-----------------------------------------------------------------*/
1387 /* peepHole - matches & substitutes rules */
1388 /*-----------------------------------------------------------------*/
1390 peepHole (lineNode ** pls)
1394 lineNode *mtail = NULL;
1397 #if !OPT_DISABLE_PIC
1398 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1403 assert(labelHash == NULL);
1410 for (pr = rootRules; pr; pr = pr->next)
1412 for (spl = *pls; spl; spl = spl->next)
1414 /* if inline assembler then no peep hole */
1420 /* Tidy up any data stored in the hTab */
1423 if (matchRule (spl, &mtail, pr, *pls))
1428 replaceRule (pls, mtail, pr);
1430 replaceRule (&spl, mtail, pr);
1432 /* if restart rule type then
1433 start at the top again */
1442 hTabDeleteAll (pr->vars);
1443 Safe_free (pr->vars);
1447 freeTrace (&_G.values);
1450 } while (restart == TRUE);
1454 hTabDeleteAll (labelHash);
1455 freeTrace (&_G.labels);
1461 /*-----------------------------------------------------------------*/
1462 /* readFileIntoBuffer - reads a file into a string buffer */
1463 /*-----------------------------------------------------------------*/
1465 readFileIntoBuffer (char *fname)
1471 char lb[MAX_PATTERN_LEN];
1473 if (!(f = fopen (fname, "r")))
1475 fprintf (stderr, "cannot open peep rule file\n");
1479 while ((ch = fgetc (f)) != EOF)
1483 /* if we maxed out our local buffer */
1484 if (nch >= (MAX_PATTERN_LEN - 2))
1487 /* copy it into allocated buffer */
1490 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1491 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1495 rs = Safe_strdup (lb);
1501 /* if some charaters left over */
1505 /* copy it into allocated buffer */
1508 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1509 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1513 rs = Safe_strdup (lb);
1519 /*-----------------------------------------------------------------*/
1520 /* initPeepHole - initialises the peep hole optimizer stuff */
1521 /*-----------------------------------------------------------------*/
1527 /* read in the default rules */
1528 readRules (port->peep.default_rules);
1530 /* if we have any additional file read it too */
1531 if (options.peep_file)
1533 readRules (s = readFileIntoBuffer (options.peep_file));
1534 setToNull ((void **) &s);
1538 #if !OPT_DISABLE_PIC
1539 /* Convert the peep rules into pcode.
1540 NOTE: this is only support in the PIC port (at the moment)
1542 if (TARGET_IS_PIC) {
1543 peepRules2pCode(rootRules);