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 /* operandsNotSame - check if %1 & %2 are the same */
280 /*-----------------------------------------------------------------*/
281 FBYNAME (operandsNotSame)
283 char *op1 = hTabItemWithKey (vars, 1);
284 char *op2 = hTabItemWithKey (vars, 2);
286 if (strcmp (op1, op2) == 0)
292 /*-----------------------------------------------------------------*/
293 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
294 /*-----------------------------------------------------------------*/
295 FBYNAME (operandsNotSame3)
297 char *op1 = hTabItemWithKey (vars, 1);
298 char *op2 = hTabItemWithKey (vars, 2);
299 char *op3 = hTabItemWithKey (vars, 3);
301 if ( (strcmp (op1, op2) == 0) ||
302 (strcmp (op1, op3) == 0) ||
303 (strcmp (op2, op3) == 0) )
309 /*-----------------------------------------------------------------*/
310 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
311 /*-----------------------------------------------------------------*/
312 FBYNAME (operandsNotSame4)
314 char *op1 = hTabItemWithKey (vars, 1);
315 char *op2 = hTabItemWithKey (vars, 2);
316 char *op3 = hTabItemWithKey (vars, 3);
317 char *op4 = hTabItemWithKey (vars, 4);
319 if ( (strcmp (op1, op2) == 0) ||
320 (strcmp (op1, op3) == 0) ||
321 (strcmp (op1, op4) == 0) ||
322 (strcmp (op2, op3) == 0) ||
323 (strcmp (op2, op4) == 0) ||
324 (strcmp (op3, op4) == 0) )
330 /*-----------------------------------------------------------------*/
331 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
332 /*-----------------------------------------------------------------*/
333 FBYNAME (operandsNotSame5)
335 char *op1 = hTabItemWithKey (vars, 1);
336 char *op2 = hTabItemWithKey (vars, 2);
337 char *op3 = hTabItemWithKey (vars, 3);
338 char *op4 = hTabItemWithKey (vars, 4);
339 char *op5 = hTabItemWithKey (vars, 5);
341 if ( (strcmp (op1, op2) == 0) ||
342 (strcmp (op1, op3) == 0) ||
343 (strcmp (op1, op4) == 0) ||
344 (strcmp (op1, op5) == 0) ||
345 (strcmp (op2, op3) == 0) ||
346 (strcmp (op2, op4) == 0) ||
347 (strcmp (op2, op5) == 0) ||
348 (strcmp (op3, op4) == 0) ||
349 (strcmp (op3, op5) == 0) ||
350 (strcmp (op4, op5) == 0) )
356 /*-----------------------------------------------------------------*/
357 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
358 /*-----------------------------------------------------------------*/
359 FBYNAME (operandsNotSame6)
361 char *op1 = hTabItemWithKey (vars, 1);
362 char *op2 = hTabItemWithKey (vars, 2);
363 char *op3 = hTabItemWithKey (vars, 3);
364 char *op4 = hTabItemWithKey (vars, 4);
365 char *op5 = hTabItemWithKey (vars, 5);
366 char *op6 = hTabItemWithKey (vars, 6);
368 if ( (strcmp (op1, op2) == 0) ||
369 (strcmp (op1, op3) == 0) ||
370 (strcmp (op1, op4) == 0) ||
371 (strcmp (op1, op5) == 0) ||
372 (strcmp (op1, op6) == 0) ||
373 (strcmp (op2, op3) == 0) ||
374 (strcmp (op2, op4) == 0) ||
375 (strcmp (op2, op5) == 0) ||
376 (strcmp (op2, op6) == 0) ||
377 (strcmp (op3, op4) == 0) ||
378 (strcmp (op3, op5) == 0) ||
379 (strcmp (op3, op6) == 0) ||
380 (strcmp (op4, op5) == 0) ||
381 (strcmp (op4, op6) == 0) ||
382 (strcmp (op5, op6) == 0) )
389 /*-----------------------------------------------------------------*/
390 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
391 /*-----------------------------------------------------------------*/
392 FBYNAME (operandsNotSame7)
394 char *op1 = hTabItemWithKey (vars, 1);
395 char *op2 = hTabItemWithKey (vars, 2);
396 char *op3 = hTabItemWithKey (vars, 3);
397 char *op4 = hTabItemWithKey (vars, 4);
398 char *op5 = hTabItemWithKey (vars, 5);
399 char *op6 = hTabItemWithKey (vars, 6);
400 char *op7 = hTabItemWithKey (vars, 7);
402 if ( (strcmp (op1, op2) == 0) ||
403 (strcmp (op1, op3) == 0) ||
404 (strcmp (op1, op4) == 0) ||
405 (strcmp (op1, op5) == 0) ||
406 (strcmp (op1, op6) == 0) ||
407 (strcmp (op1, op7) == 0) ||
408 (strcmp (op2, op3) == 0) ||
409 (strcmp (op2, op4) == 0) ||
410 (strcmp (op2, op5) == 0) ||
411 (strcmp (op2, op6) == 0) ||
412 (strcmp (op2, op7) == 0) ||
413 (strcmp (op3, op4) == 0) ||
414 (strcmp (op3, op5) == 0) ||
415 (strcmp (op3, op6) == 0) ||
416 (strcmp (op3, op7) == 0) ||
417 (strcmp (op4, op5) == 0) ||
418 (strcmp (op4, op6) == 0) ||
419 (strcmp (op4, op7) == 0) ||
420 (strcmp (op5, op6) == 0) ||
421 (strcmp (op5, op7) == 0) ||
422 (strcmp (op6, op7) == 0) )
428 /*-----------------------------------------------------------------*/
429 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
430 /*-----------------------------------------------------------------*/
431 FBYNAME (operandsNotSame8)
433 char *op1 = hTabItemWithKey (vars, 1);
434 char *op2 = hTabItemWithKey (vars, 2);
435 char *op3 = hTabItemWithKey (vars, 3);
436 char *op4 = hTabItemWithKey (vars, 4);
437 char *op5 = hTabItemWithKey (vars, 5);
438 char *op6 = hTabItemWithKey (vars, 6);
439 char *op7 = hTabItemWithKey (vars, 7);
440 char *op8 = hTabItemWithKey (vars, 8);
442 if ( (strcmp (op1, op2) == 0) ||
443 (strcmp (op1, op3) == 0) ||
444 (strcmp (op1, op4) == 0) ||
445 (strcmp (op1, op5) == 0) ||
446 (strcmp (op1, op6) == 0) ||
447 (strcmp (op1, op7) == 0) ||
448 (strcmp (op1, op8) == 0) ||
449 (strcmp (op2, op3) == 0) ||
450 (strcmp (op2, op4) == 0) ||
451 (strcmp (op2, op5) == 0) ||
452 (strcmp (op2, op6) == 0) ||
453 (strcmp (op2, op7) == 0) ||
454 (strcmp (op2, op8) == 0) ||
455 (strcmp (op3, op4) == 0) ||
456 (strcmp (op3, op5) == 0) ||
457 (strcmp (op3, op6) == 0) ||
458 (strcmp (op3, op7) == 0) ||
459 (strcmp (op3, op8) == 0) ||
460 (strcmp (op4, op5) == 0) ||
461 (strcmp (op4, op6) == 0) ||
462 (strcmp (op4, op7) == 0) ||
463 (strcmp (op4, op8) == 0) ||
464 (strcmp (op5, op6) == 0) ||
465 (strcmp (op5, op7) == 0) ||
466 (strcmp (op5, op8) == 0) ||
467 (strcmp (op6, op7) == 0) ||
468 (strcmp (op6, op8) == 0) ||
469 (strcmp (op7, op8) == 0) )
478 * takes two parameters: a variable (bound to a label name)
479 * and an expected reference count.
481 * Returns TRUE if that label is defined and referenced exactly
482 * the given number of times.
484 FBYNAME (labelRefCount)
486 int varNumber, expectedRefCount;
489 /* If we don't have the label hash table yet, build it. */
492 buildLabelRefCountHash (head);
495 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
497 char *label = hTabItemWithKey (vars, varNumber);
501 labelHashEntry *entry;
503 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
507 if (!strcmp (label, entry->name))
511 entry = hTabNextItemWK (labelHash);
517 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
518 label, entry->refCount, expectedRefCount);
521 rc = (expectedRefCount == entry->refCount);
525 fprintf (stderr, "*** internal error: no label has entry for"
526 " %s in labelRefCount peephole.\n",
532 fprintf (stderr, "*** internal error: var %d not bound"
533 " in peephole labelRefCount rule.\n",
541 "*** internal error: labelRefCount peephole restriction"
542 " malformed: %s\n", cmdLine);
547 /*-----------------------------------------------------------------*/
548 /* callFuncByName - calls a function as defined in the table */
549 /*-----------------------------------------------------------------*/
551 callFuncByName (char *fname,
559 int (*func) (hTab *, lineNode *, lineNode *, const char *);
564 "labelInRange", labelInRange
568 "operandsNotSame", operandsNotSame
572 "operandsNotSame3", operandsNotSame3
576 "operandsNotSame4", operandsNotSame4
580 "operandsNotSame5", operandsNotSame5
584 "operandsNotSame6", operandsNotSame6
588 "operandsNotSame7", operandsNotSame7
592 "operandsNotSame8", operandsNotSame8
596 "24bitMode", flat24bitMode
600 "xramMovcOption", xramMovcOption
604 "labelRefCount", labelRefCount
608 "portIsDS390", portIsDS390
611 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
615 char *cmdCopy, *funcName, *funcArgs;
618 /* Isolate the function name part (we are passed the full condition
619 * string including arguments)
621 cmdCopy = Safe_strdup(fname);
622 funcName = strtok(cmdCopy, " \t");
623 funcArgs = strtok(NULL, "");
625 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
627 if (strcmp (ftab[i].fname, funcName) == 0)
629 rc = (*ftab[i].func) (vars, currPl, head,
639 "could not find named function \"%s\" in "
640 "peephole function table\n",
642 // If the function couldn't be found, let's assume it's
643 // a bad rule and refuse it.
650 /*-----------------------------------------------------------------*/
651 /* printLine - prints a line chain into a given file */
652 /*-----------------------------------------------------------------*/
654 printLine (lineNode * head, FILE * of)
661 /* don't indent comments & labels */
663 (*head->line == ';' ||
664 head->line[strlen (head->line) - 1] == ':')) {
665 fprintf (of, "%s\n", head->line);
667 if (head->isInline && *head->line=='#') {
668 // comment out preprocessor directives in inline asm
671 fprintf (of, "\t%s\n", head->line);
677 /*-----------------------------------------------------------------*/
678 /* newPeepRule - creates a new peeprule and attach it to the root */
679 /*-----------------------------------------------------------------*/
681 newPeepRule (lineNode * match,
688 pr = Safe_alloc ( sizeof (peepRule));
690 pr->replace = replace;
691 pr->restart = restart;
695 pr->cond = Safe_strdup (cond);
700 pr->vars = newHashTable (100);
702 /* if root is empty */
704 rootRules = currRule = pr;
706 currRule = currRule->next = pr;
711 /*-----------------------------------------------------------------*/
712 /* newLineNode - creates a new peep line */
713 /*-----------------------------------------------------------------*/
715 newLineNode (char *line)
719 pl = Safe_alloc ( sizeof (lineNode));
720 pl->line = Safe_strdup (line);
724 /*-----------------------------------------------------------------*/
725 /* connectLine - connects two lines */
726 /*-----------------------------------------------------------------*/
728 connectLine (lineNode * pl1, lineNode * pl2)
732 fprintf (stderr, "trying to connect null line\n");
742 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
743 if (!*x) { fprintf(stderr,y); return ; } }
745 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
746 if (!*x) { fprintf(stderr,z); return ; } }
747 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
748 if (!*x) { fprintf(stderr,z); return ; } }
750 /*-----------------------------------------------------------------*/
751 /* getPeepLine - parses the peep lines */
752 /*-----------------------------------------------------------------*/
754 getPeepLine (lineNode ** head, char **bpp)
756 char lines[MAX_PATTERN_LEN];
759 lineNode *currL = NULL;
766 fprintf (stderr, "unexpected end of match pattern\n");
773 while (isspace (*bp) ||
784 /* read till end of line */
786 while ((*bp != '\n' && *bp != '}') && *bp)
791 *head = currL = newLineNode (lines);
793 currL = connectLine (currL, newLineNode (lines));
799 /*-----------------------------------------------------------------*/
800 /* readRules - reads the rules from a string buffer */
801 /*-----------------------------------------------------------------*/
806 char lines[MAX_PATTERN_LEN];
810 lineNode *currL = NULL;
816 /* look for the token "replace" that is the
818 while (*bp && strncmp (bp, "replace", 7))
825 /* then look for either "restart" or '{' */
826 while (strncmp (bp, "restart", 7) &&
833 fprintf (stderr, "expected 'restart' or '{'\n");
841 { /* must be restart */
843 bp += strlen ("restart");
845 EXPECT_CHR (bp, '{', "expected '{'\n");
849 /* skip thru all the blank space */
850 SKIP_SPACE (bp, "unexpected end of rule\n");
852 match = replace = currL = NULL;
853 /* we are the start of a rule */
854 getPeepLine (&match, &bp);
856 /* now look for by */
857 EXPECT_STR (bp, "by", "expected 'by'\n");
859 /* then look for a '{' */
860 EXPECT_CHR (bp, '{', "expected '{'\n");
863 SKIP_SPACE (bp, "unexpected end of rule\n");
864 getPeepLine (&replace, &bp);
866 /* look for a 'if' */
867 while ((isspace (*bp) || *bp == '\n') && *bp)
870 if (strncmp (bp, "if", 2) == 0)
873 while ((isspace (*bp) || *bp == '\n') && *bp)
877 fprintf (stderr, "expected condition name\n");
881 /* look for the condition */
883 while (*bp && (*bp != '\n'))
889 newPeepRule (match, replace, lines, restart);
892 newPeepRule (match, replace, NULL, restart);
897 /*-----------------------------------------------------------------*/
898 /* keyForVar - returns the numeric key for a var */
899 /*-----------------------------------------------------------------*/
914 /*-----------------------------------------------------------------*/
915 /* bindVar - binds a value to a variable in the given hashtable */
916 /*-----------------------------------------------------------------*/
918 bindVar (int key, char **s, hTab ** vtab)
920 char vval[MAX_PATTERN_LEN];
924 /* first get the value of the variable */
926 /* the value is ended by a ',' or space or newline or null or ) */
935 /* if we find a '(' then we need to balance it */
947 // include the trailing ')'
956 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
958 hTabAddItem (vtab, key, vvx);
961 /*-----------------------------------------------------------------*/
962 /* matchLine - matches one line */
963 /*-----------------------------------------------------------------*/
965 matchLine (char *s, char *d, hTab ** vars)
974 /* skip white space in both */
980 /* if the destination is a var */
981 if (*d == '%' && isdigit (*(d + 1)))
983 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
984 /* if the variable is already bound
985 then it MUST match with dest */
993 /* variable not bound we need to
995 bindVar (keyForVar (d + 1), &s, vars);
997 /* in either case go past the variable */
1003 /* they should be an exact match other wise */
1006 while (isspace (*s))
1008 while (isspace (*d))
1016 /* get rid of the trailing spaces
1017 in both source & destination */
1019 while (isspace (*s))
1023 while (isspace (*d))
1026 /* after all this if only one of them
1027 has something left over then no match */
1034 /*-----------------------------------------------------------------*/
1035 /* matchRule - matches a all the rule lines */
1036 /*-----------------------------------------------------------------*/
1038 matchRule (lineNode * pl,
1043 lineNode *spl; /* source pl */
1044 lineNode *rpl; /* rule peep line */
1046 /* setToNull((void **) &pr->vars); */
1047 /* pr->vars = newHashTable(100); */
1049 /* for all the lines defined in the rule */
1055 /* if the source line starts with a ';' then
1056 comment line don't process or the source line
1057 contains == . debugger information skip it */
1059 (*spl->line == ';' || spl->isDebug))
1065 if (!matchLine (spl->line, rpl->line, &pr->vars))
1073 /* if rules ended */
1076 /* if this rule has additional conditions */
1079 if (callFuncByName (pr->cond, pr->vars, pl, head))
1097 /*-----------------------------------------------------------------*/
1098 /* replaceRule - does replacement of a matching pattern */
1099 /*-----------------------------------------------------------------*/
1101 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1103 lineNode *cl = NULL;
1104 lineNode *pl = NULL, *lhead = NULL;
1105 /* a long function name and long variable name can evaluate to
1106 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1107 char lb[MAX_PATTERN_LEN*4];
1109 lineNode *comment = NULL;
1111 /* collect all the comment lines in the source */
1112 for (cl = *shead; cl != stail; cl = cl->next)
1114 if (cl->line && (*cl->line == ';' || cl->isDebug))
1116 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1117 (comment = newLineNode (cl->line)));
1118 pl->isDebug = cl->isDebug;
1123 /* for all the lines in the replacement pattern do */
1124 for (pl = pr->replace; pl; pl = pl->next)
1134 /* if the line contains a variable */
1135 if (*l == '%' && isdigit (*(l + 1)))
1137 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1140 fprintf (stderr, "used unbound variable in replacement\n");
1148 while (isdigit (*l)) {
1158 cl = connectLine (cl, newLineNode (lb));
1160 lhead = cl = newLineNode (lb);
1163 /* add the comments if any to the head of list */
1166 lineNode *lc = comment;
1175 /* now we need to connect / replace the original chain */
1176 /* if there is a prev then change it */
1179 (*shead)->prev->next = lhead;
1180 lhead->prev = (*shead)->prev;
1183 /* now for the tail */
1184 if (stail && stail->next)
1186 stail->next->prev = cl;
1188 cl->next = stail->next;
1192 /* Returns TRUE if this line is a label definition.
1194 * If so, start will point to the start of the label name,
1195 * and len will be it's length.
1198 isLabelDefinition (const char *line, const char **start, int *len)
1200 const char *cp = line;
1202 /* This line is a label if if consists of:
1203 * [optional whitespace] followed by identifier chars
1204 * (alnum | $ | _ ) followed by a colon.
1207 while (*cp && isspace (*cp))
1219 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1224 if ((cp == *start) || (*cp != ':'))
1229 *len = (cp - (*start));
1233 /* Quick & dirty string hash function. */
1235 hashSymbolName (const char *name)
1241 hash = (hash << 6) ^ *name;
1250 return hash % HTAB_SIZE;
1253 /* Build a hash of all labels in the passed set of lines
1254 * and how many times they are referenced.
1257 buildLabelRefCountHash (lineNode * head)
1264 assert (labelHash == NULL);
1265 labelHash = newHashTable (HTAB_SIZE);
1267 /* First pass: locate all the labels. */
1272 if (isLabelDefinition (line->line, &label, &labelLen)
1273 && labelLen <= SDCC_NAME_MAX)
1275 labelHashEntry *entry;
1277 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1279 memcpy (entry->name, label, labelLen);
1280 entry->name[labelLen] = 0;
1281 entry->refCount = -1;
1283 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1289 /* Second pass: for each line, note all the referenced labels. */
1290 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1294 for (i = 0; i < HTAB_SIZE; i++)
1296 labelHashEntry *thisEntry;
1298 thisEntry = hTabFirstItemWK (labelHash, i);
1302 if (strstr (line->line, thisEntry->name))
1304 thisEntry->refCount++;
1306 thisEntry = hTabNextItemWK (labelHash);
1313 /* Spew the contents of the table. Debugging fun only. */
1314 for (i = 0; i < HTAB_SIZE; i++)
1316 labelHashEntry *thisEntry;
1318 thisEntry = hTabFirstItemWK (labelHash, i);
1322 fprintf (stderr, "label: %s ref %d\n",
1323 thisEntry->name, thisEntry->refCount);
1324 thisEntry = hTabNextItemWK (labelHash);
1330 /* How does this work?
1336 replace and restart.
1341 Where is stuff allocated?
1345 /*-----------------------------------------------------------------*/
1346 /* peepHole - matches & substitutes rules */
1347 /*-----------------------------------------------------------------*/
1349 peepHole (lineNode ** pls)
1353 lineNode *mtail = NULL;
1356 #if !OPT_DISABLE_PIC
1357 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1362 assert(labelHash == NULL);
1369 for (pr = rootRules; pr; pr = pr->next)
1371 for (spl = *pls; spl; spl = spl->next)
1373 /* if inline assembler then no peep hole */
1379 /* Tidy up any data stored in the hTab */
1382 if (matchRule (spl, &mtail, pr, *pls))
1387 replaceRule (pls, mtail, pr);
1389 replaceRule (&spl, mtail, pr);
1391 /* if restart rule type then
1392 start at the top again */
1401 hTabDeleteAll (pr->vars);
1402 Safe_free (pr->vars);
1406 freeTrace (&_G.values);
1409 } while (restart == TRUE);
1413 hTabDeleteAll (labelHash);
1414 freeTrace (&_G.labels);
1420 /*-----------------------------------------------------------------*/
1421 /* readFileIntoBuffer - reads a file into a string buffer */
1422 /*-----------------------------------------------------------------*/
1424 readFileIntoBuffer (char *fname)
1430 char lb[MAX_PATTERN_LEN];
1432 if (!(f = fopen (fname, "r")))
1434 fprintf (stderr, "cannot open peep rule file\n");
1438 while ((ch = fgetc (f)) != EOF)
1442 /* if we maxed out our local buffer */
1443 if (nch >= (MAX_PATTERN_LEN - 2))
1446 /* copy it into allocated buffer */
1449 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1450 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1454 rs = Safe_strdup (lb);
1460 /* if some charaters left over */
1464 /* copy it into allocated buffer */
1467 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1468 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1472 rs = Safe_strdup (lb);
1478 /*-----------------------------------------------------------------*/
1479 /* initPeepHole - initialises the peep hole optimizer stuff */
1480 /*-----------------------------------------------------------------*/
1486 /* read in the default rules */
1487 readRules (port->peep.default_rules);
1489 /* if we have any additional file read it too */
1490 if (options.peep_file)
1492 readRules (s = readFileIntoBuffer (options.peep_file));
1493 setToNull ((void **) &s);
1497 #if !OPT_DISABLE_PIC
1498 /* Convert the peep rules into pcode.
1499 NOTE: this is only support in the PIC port (at the moment)
1501 if (TARGET_IS_PIC) {
1502 peepRules2pCode(rootRules);