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 **);
51 bool isLabelDefinition (const char *line, const char **start, int *len);
53 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
54 lineNode *head, const char *cmdLine)
57 void peepRules2pCode(peepRule *);
60 #if !OPT_DISABLE_PIC16
61 void pic16_peepRules2pCode(peepRule *);
64 /*-----------------------------------------------------------------*/
65 /* pcDistance - afinds a label back ward or forward */
66 /*-----------------------------------------------------------------*/
68 mcs51_instruction_size(const char *inst)
70 char *op, op1[256], op2[256];
74 while (*inst && isspace(*inst)) inst++;
76 #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
78 /* Based on the current (2003-08-22) code generation for the
79 small library, the top instruction probability is:
90 /* mov, push, & pop are the 69% of the cases. Check them first! */
93 if (*(inst+3)=='x') return 1; /* movx */
94 if (*(inst+3)=='c') return 1; /* movc */
95 goto checkoperands; /* mov */
97 if (ISINST("push")) return 2;
98 if (ISINST("pop")) return 2;
100 if (ISINST("lcall")) return 3;
101 if (ISINST("ret")) return 1;
102 if (ISINST("ljmp")) return 3;
103 if (ISINST("sjmp")) return 2;
104 if (ISINST("rlc")) return 1;
105 if (ISINST("rrc")) return 1;
106 if (ISINST("rl")) return 1;
107 if (ISINST("rr")) return 1;
108 if (ISINST("swap")) return 1;
109 if (ISINST("jc")) return 2;
110 if (ISINST("jnc")) return 2;
111 if (ISINST("jb")) return 3;
112 if (ISINST("jnb")) return 3;
113 if (ISINST("jbc")) return 3;
114 if (ISINST("jmp")) return 1; // always jmp @a+dptr
115 if (ISINST("jz")) return 2;
116 if (ISINST("jnz")) return 2;
117 if (ISINST("cjne")) return 3;
118 if (ISINST("mul")) return 1;
119 if (ISINST("div")) return 1;
120 if (ISINST("da")) return 1;
121 if (ISINST("xchd")) return 1;
122 if (ISINST("reti")) return 1;
123 if (ISINST("nop")) return 1;
124 if (ISINST("acall")) return 1;
125 if (ISINST("ajmp")) return 2;
129 while (*p && isalnum(*p)) p++;
130 for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
131 if (!isspace(*p)) *op++ = *p, opsize++;
135 for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
136 if (!isspace(*p)) *op++ = *p, opsize++;
140 #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
141 #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
142 #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
143 #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
146 if (IS_C(op1) || IS_C(op2)) return 2;
148 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
151 if (IS_Rn(op1) || IS_atRi(op1)) {
152 if (IS_A(op2)) return 1;
155 if (strcmp(op1, "dptr") == 0) return 3;
156 if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
159 if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
160 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
163 if (ISINST("inc") || ISINST("dec")) {
164 if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
165 if (strcmp(op1, "dptr") == 0) return 1;
168 if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
169 if (IS_C(op1)) return 2;
171 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
174 if (IS_A(op2)) return 2;
178 if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
179 if (IS_A(op1) || IS_C(op1)) return 1;
182 if (ISINST("djnz")) {
183 if (IS_Rn(op1)) return 2;
187 if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
188 /* ignore ar0 = 0x00 type definitions */
192 fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
197 pcDistance (lineNode * cpos, char *lbl, bool back)
200 char buff[MAX_PATTERN_LEN];
203 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
209 pl->line[strlen (pl->line) - 1] != ':' &&
211 if (TARGET_IS_MCS51) {
212 dist += mcs51_instruction_size(pl->line);
218 if (strncmp (pl->line, buff, strlen (buff)) == 0)
230 /*-----------------------------------------------------------------*/
231 /* flat24bitModeAndPortDS390 - */
232 /*-----------------------------------------------------------------*/
233 FBYNAME (flat24bitModeAndPortDS390)
235 return (((strcmp(port->target,"ds390") == 0) ||
236 (strcmp(port->target,"ds400") == 0)) &&
237 (options.model == MODEL_FLAT24));
240 /*-----------------------------------------------------------------*/
241 /* portIsDS390 - return true if port is DS390 */
242 /*-----------------------------------------------------------------*/
243 FBYNAME (portIsDS390)
245 return ((strcmp(port->target,"ds390") == 0) ||
246 (strcmp(port->target,"ds400") == 0));
249 /*-----------------------------------------------------------------*/
250 /* flat24bitMode - will check to see if we are in flat24 mode */
251 /*-----------------------------------------------------------------*/
252 FBYNAME (flat24bitMode)
254 return (options.model == MODEL_FLAT24);
257 /*-----------------------------------------------------------------*/
258 /* xramMovcOption - check if using movc to read xram */
259 /*-----------------------------------------------------------------*/
260 FBYNAME (xramMovcOption)
262 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
270 /*-----------------------------------------------------------------*/
271 /* labelInRange - will check to see if label %5 is within range */
272 /*-----------------------------------------------------------------*/
273 FBYNAME (labelInRange)
275 /* assumes that %5 pattern variable has the label name */
276 char *lbl = hTabItemWithKey (vars, 5);
282 /* Don't optimize jumps in a jump table; a more generic test */
283 if (currPl->ic && currPl->ic->op == JUMPTABLE)
286 /* if the previous two instructions are "ljmp"s then don't
287 do it since it can be part of a jump table */
288 if (currPl->prev && currPl->prev->prev &&
289 strstr (currPl->prev->line, "ljmp") &&
290 strstr (currPl->prev->prev->line, "ljmp"))
293 /* calculate the label distance : the jump for reladdr can be
294 +/- 127 bytes, here Iam assuming that an average 8051
295 instruction is 2 bytes long, so if the label is more than
296 63 intructions away, the label is considered out of range
297 for a relative jump. we could get more precise this will
298 suffice for now since it catches > 90% cases */
299 dist = (pcDistance (currPl, lbl, TRUE) +
300 pcDistance (currPl, lbl, FALSE));
302 /* changed to 127, now that pcDistance return actual number of bytes */
303 if (!dist || dist > 127)
309 /*-----------------------------------------------------------------*/
310 /* labelIsReturnOnly - Check if label %5 is followed by RET */
311 /*-----------------------------------------------------------------*/
312 FBYNAME (labelIsReturnOnly)
314 /* assumes that %5 pattern variable has the label name */
315 const char *label, *p;
319 label = hTabItemWithKey (vars, 5);
320 if (!label) return FALSE;
323 for(pl = currPl; pl; pl = pl->next) {
324 if (pl->line && !pl->isDebug &&
325 pl->line[strlen(pl->line)-1] == ':') {
326 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
327 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
328 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
329 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
330 *(pl->line+5) != '$') {
331 return FALSE; /* non-local label encountered */
335 if (!pl) return FALSE; /* did not find the label */
337 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
339 for (p = pl->line; *p && isspace(*p); p++)
341 if (strcmp(p, "ret") == 0) return TRUE;
346 /*-----------------------------------------------------------------*/
347 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
348 /* usage of it in the code depends on a value from this section */
349 /*-----------------------------------------------------------------*/
350 FBYNAME (okToRemoveSLOC)
353 const char *sloc, *p;
354 int dummy1, dummy2, dummy3;
356 /* assumes that %1 as the SLOC name */
357 sloc = hTabItemWithKey (vars, 1);
358 if (sloc == NULL) return FALSE;
359 p = strstr(sloc, "sloc");
360 if (p == NULL) return FALSE;
362 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
363 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
364 /* the sloc name begins with that. Probably not really necessary */
366 /* Look for any occurance of this SLOC before the peephole match */
367 for (pl = currPl->prev; pl; pl = pl->prev) {
368 if (pl->line && !pl->isDebug && !pl->isComment
369 && *pl->line != ';' && strstr(pl->line, sloc))
372 /* Look for any occurance of this SLOC after the peephole match */
373 for (pl = endPl->next; pl; pl = pl->next) {
374 if (pl->line && !pl->isDebug && !pl->isComment
375 && *pl->line != ';' && strstr(pl->line, sloc))
378 return TRUE; /* safe for a peephole to remove it :) */
382 /*-----------------------------------------------------------------*/
383 /* operandsNotSame - check if %1 & %2 are the same */
384 /*-----------------------------------------------------------------*/
385 FBYNAME (operandsNotSame)
387 char *op1 = hTabItemWithKey (vars, 1);
388 char *op2 = hTabItemWithKey (vars, 2);
390 if (strcmp (op1, op2) == 0)
396 /*-----------------------------------------------------------------*/
397 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
398 /*-----------------------------------------------------------------*/
399 FBYNAME (operandsNotSame3)
401 char *op1 = hTabItemWithKey (vars, 1);
402 char *op2 = hTabItemWithKey (vars, 2);
403 char *op3 = hTabItemWithKey (vars, 3);
405 if ( (strcmp (op1, op2) == 0) ||
406 (strcmp (op1, op3) == 0) ||
407 (strcmp (op2, op3) == 0) )
413 /*-----------------------------------------------------------------*/
414 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
415 /*-----------------------------------------------------------------*/
416 FBYNAME (operandsNotSame4)
418 char *op1 = hTabItemWithKey (vars, 1);
419 char *op2 = hTabItemWithKey (vars, 2);
420 char *op3 = hTabItemWithKey (vars, 3);
421 char *op4 = hTabItemWithKey (vars, 4);
423 if ( (strcmp (op1, op2) == 0) ||
424 (strcmp (op1, op3) == 0) ||
425 (strcmp (op1, op4) == 0) ||
426 (strcmp (op2, op3) == 0) ||
427 (strcmp (op2, op4) == 0) ||
428 (strcmp (op3, op4) == 0) )
434 /*-----------------------------------------------------------------*/
435 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
436 /*-----------------------------------------------------------------*/
437 FBYNAME (operandsNotSame5)
439 char *op1 = hTabItemWithKey (vars, 1);
440 char *op2 = hTabItemWithKey (vars, 2);
441 char *op3 = hTabItemWithKey (vars, 3);
442 char *op4 = hTabItemWithKey (vars, 4);
443 char *op5 = hTabItemWithKey (vars, 5);
445 if ( (strcmp (op1, op2) == 0) ||
446 (strcmp (op1, op3) == 0) ||
447 (strcmp (op1, op4) == 0) ||
448 (strcmp (op1, op5) == 0) ||
449 (strcmp (op2, op3) == 0) ||
450 (strcmp (op2, op4) == 0) ||
451 (strcmp (op2, op5) == 0) ||
452 (strcmp (op3, op4) == 0) ||
453 (strcmp (op3, op5) == 0) ||
454 (strcmp (op4, op5) == 0) )
460 /*-----------------------------------------------------------------*/
461 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
462 /*-----------------------------------------------------------------*/
463 FBYNAME (operandsNotSame6)
465 char *op1 = hTabItemWithKey (vars, 1);
466 char *op2 = hTabItemWithKey (vars, 2);
467 char *op3 = hTabItemWithKey (vars, 3);
468 char *op4 = hTabItemWithKey (vars, 4);
469 char *op5 = hTabItemWithKey (vars, 5);
470 char *op6 = hTabItemWithKey (vars, 6);
472 if ( (strcmp (op1, op2) == 0) ||
473 (strcmp (op1, op3) == 0) ||
474 (strcmp (op1, op4) == 0) ||
475 (strcmp (op1, op5) == 0) ||
476 (strcmp (op1, op6) == 0) ||
477 (strcmp (op2, op3) == 0) ||
478 (strcmp (op2, op4) == 0) ||
479 (strcmp (op2, op5) == 0) ||
480 (strcmp (op2, op6) == 0) ||
481 (strcmp (op3, op4) == 0) ||
482 (strcmp (op3, op5) == 0) ||
483 (strcmp (op3, op6) == 0) ||
484 (strcmp (op4, op5) == 0) ||
485 (strcmp (op4, op6) == 0) ||
486 (strcmp (op5, op6) == 0) )
493 /*-----------------------------------------------------------------*/
494 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
495 /*-----------------------------------------------------------------*/
496 FBYNAME (operandsNotSame7)
498 char *op1 = hTabItemWithKey (vars, 1);
499 char *op2 = hTabItemWithKey (vars, 2);
500 char *op3 = hTabItemWithKey (vars, 3);
501 char *op4 = hTabItemWithKey (vars, 4);
502 char *op5 = hTabItemWithKey (vars, 5);
503 char *op6 = hTabItemWithKey (vars, 6);
504 char *op7 = hTabItemWithKey (vars, 7);
506 if ( (strcmp (op1, op2) == 0) ||
507 (strcmp (op1, op3) == 0) ||
508 (strcmp (op1, op4) == 0) ||
509 (strcmp (op1, op5) == 0) ||
510 (strcmp (op1, op6) == 0) ||
511 (strcmp (op1, op7) == 0) ||
512 (strcmp (op2, op3) == 0) ||
513 (strcmp (op2, op4) == 0) ||
514 (strcmp (op2, op5) == 0) ||
515 (strcmp (op2, op6) == 0) ||
516 (strcmp (op2, op7) == 0) ||
517 (strcmp (op3, op4) == 0) ||
518 (strcmp (op3, op5) == 0) ||
519 (strcmp (op3, op6) == 0) ||
520 (strcmp (op3, op7) == 0) ||
521 (strcmp (op4, op5) == 0) ||
522 (strcmp (op4, op6) == 0) ||
523 (strcmp (op4, op7) == 0) ||
524 (strcmp (op5, op6) == 0) ||
525 (strcmp (op5, op7) == 0) ||
526 (strcmp (op6, op7) == 0) )
532 /*-----------------------------------------------------------------*/
533 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
534 /*-----------------------------------------------------------------*/
535 FBYNAME (operandsNotSame8)
537 char *op1 = hTabItemWithKey (vars, 1);
538 char *op2 = hTabItemWithKey (vars, 2);
539 char *op3 = hTabItemWithKey (vars, 3);
540 char *op4 = hTabItemWithKey (vars, 4);
541 char *op5 = hTabItemWithKey (vars, 5);
542 char *op6 = hTabItemWithKey (vars, 6);
543 char *op7 = hTabItemWithKey (vars, 7);
544 char *op8 = hTabItemWithKey (vars, 8);
546 if ( (strcmp (op1, op2) == 0) ||
547 (strcmp (op1, op3) == 0) ||
548 (strcmp (op1, op4) == 0) ||
549 (strcmp (op1, op5) == 0) ||
550 (strcmp (op1, op6) == 0) ||
551 (strcmp (op1, op7) == 0) ||
552 (strcmp (op1, op8) == 0) ||
553 (strcmp (op2, op3) == 0) ||
554 (strcmp (op2, op4) == 0) ||
555 (strcmp (op2, op5) == 0) ||
556 (strcmp (op2, op6) == 0) ||
557 (strcmp (op2, op7) == 0) ||
558 (strcmp (op2, op8) == 0) ||
559 (strcmp (op3, op4) == 0) ||
560 (strcmp (op3, op5) == 0) ||
561 (strcmp (op3, op6) == 0) ||
562 (strcmp (op3, op7) == 0) ||
563 (strcmp (op3, op8) == 0) ||
564 (strcmp (op4, op5) == 0) ||
565 (strcmp (op4, op6) == 0) ||
566 (strcmp (op4, op7) == 0) ||
567 (strcmp (op4, op8) == 0) ||
568 (strcmp (op5, op6) == 0) ||
569 (strcmp (op5, op7) == 0) ||
570 (strcmp (op5, op8) == 0) ||
571 (strcmp (op6, op7) == 0) ||
572 (strcmp (op6, op8) == 0) ||
573 (strcmp (op7, op8) == 0) )
582 * takes two parameters: a variable (bound to a label name)
583 * and an expected reference count.
585 * Returns TRUE if that label is defined and referenced exactly
586 * the given number of times.
588 FBYNAME (labelRefCount)
590 int varNumber, expectedRefCount;
593 /* If we don't have the label hash table yet, build it. */
596 buildLabelRefCountHash (head);
599 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
601 char *label = hTabItemWithKey (vars, varNumber);
605 labelHashEntry *entry;
607 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
611 if (!strcmp (label, entry->name))
615 entry = hTabNextItemWK (labelHash);
621 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
622 label, entry->refCount, expectedRefCount);
625 rc = (expectedRefCount == entry->refCount);
629 fprintf (stderr, "*** internal error: no label has entry for"
630 " %s in labelRefCount peephole.\n",
636 fprintf (stderr, "*** internal error: var %d not bound"
637 " in peephole labelRefCount rule.\n",
645 "*** internal error: labelRefCount peephole restriction"
646 " malformed: %s\n", cmdLine);
651 /* Within the context of the lines currPl through endPl, determine
652 ** if the variable var contains a symbol that is volatile. Returns
653 ** TRUE only if it is certain that this was not volatile (the symbol
654 ** was found and not volatile, or var was a constant or CPU register).
655 ** Returns FALSE if the symbol was found and volatile, the symbol was
656 ** not found, or var was a indirect/pointer addressing mode.
659 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
661 char symname[SDCC_NAME_MAX + 1];
668 /* Can't tell if indirect accesses are volatile or not, so
669 ** assume they are, just to be safe.
671 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
676 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
678 if (strstr(var,"(bc)"))
680 if (strstr(var,"(de)"))
682 if (strstr(var,"(hl)"))
684 if (strstr(var,"(ix"))
686 if (strstr(var,"(iy"))
690 /* Extract a symbol name from the variable */
691 while (*vp && (*vp!='_'))
693 while (*vp && (isalnum(*vp) || *vp=='_'))
699 /* Nothing resembling a symbol name was found, so it can't
706 for (cl = currPl; cl!=endPl->next; cl = cl->next)
708 if (cl->ic && (cl->ic!=last_ic))
714 op = IC_COND (cl->ic);
715 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
716 return !op->isvolatile;
718 op = IC_JTCOND (cl->ic);
719 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
720 return !op->isvolatile;
722 op = IC_LEFT (cl->ic);
723 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
724 return !op->isvolatile;
725 op = IC_RIGHT (cl->ic);
726 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
727 return !op->isvolatile;
728 op = IC_RESULT (cl->ic);
729 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
730 return !op->isvolatile;
735 /* Couldn't find the symbol for some reason. Assume volatile. */
741 * This rule restriction has two different behaviours depending on
742 * the number of parameters given.
744 * if notVolatile (no parameters given)
745 * The rule is applied only if none of the iCodes originating
746 * the matched pattern reference a volatile operand.
748 * if notVolatile %1 ... (one or more parameters given)
749 * The rule is applied if the parameters are not expressions
750 * containing volatile symbols and are not pointer accesses.
753 FBYNAME (notVolatile)
764 /* If no parameters given, just scan the iCodes for volatile operands */
765 for (cl = currPl; cl!=endPl->next; cl = cl->next)
772 op = IC_COND (cl->ic);
773 if (IS_SYMOP (op) && op->isvolatile)
776 op = IC_JTCOND (cl->ic);
777 if (IS_SYMOP (op) && op->isvolatile)
780 op = IC_LEFT (cl->ic);
781 if (IS_SYMOP (op) && op->isvolatile)
783 op = IC_RIGHT (cl->ic);
784 if (IS_SYMOP (op) && op->isvolatile)
786 op = IC_RESULT (cl->ic);
787 if (IS_SYMOP (op) && op->isvolatile)
795 /* There were parameters; check the volatility of each */
796 while (*cmdLine && isspace(*cmdLine))
803 if (!isdigit(*cmdLine))
805 varNumber = strtol(cmdLine, &digitend, 10);
807 while (*cmdLine && isspace(*cmdLine))
810 var = hTabItemWithKey (vars, varNumber);
814 notvol = notVolatileVariable (var, currPl, endPl);
820 fprintf (stderr, "*** internal error: var %d not bound"
821 " in peephole notVolatile rule.\n",
832 "*** internal error: notVolatile peephole restriction"
833 " malformed: %s\n", cmdLine);
838 /*-----------------------------------------------------------------*/
839 /* callFuncByName - calls a function as defined in the table */
840 /*-----------------------------------------------------------------*/
842 callFuncByName (char *fname,
851 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
856 "labelInRange", labelInRange
860 "operandsNotSame", operandsNotSame
864 "operandsNotSame3", operandsNotSame3
868 "operandsNotSame4", operandsNotSame4
872 "operandsNotSame5", operandsNotSame5
876 "operandsNotSame6", operandsNotSame6
880 "operandsNotSame7", operandsNotSame7
884 "operandsNotSame8", operandsNotSame8
888 "24bitMode", flat24bitMode
892 "xramMovcOption", xramMovcOption
896 "labelRefCount", labelRefCount
900 "portIsDS390", portIsDS390
903 "labelIsReturnOnly", labelIsReturnOnly
906 "okToRemoveSLOC", okToRemoveSLOC
909 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
912 "notVolatile", notVolatile
916 char *cmdCopy, *funcName, *funcArgs;
919 /* Isolate the function name part (we are passed the full condition
920 * string including arguments)
922 cmdCopy = Safe_strdup(fname);
923 funcName = strtok(cmdCopy, " \t");
924 funcArgs = strtok(NULL, "");
926 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
928 if (strcmp (ftab[i].fname, funcName) == 0)
930 rc = (*ftab[i].func) (vars, currPl, endPl, head,
938 "could not find named function \"%s\" in "
939 "peephole function table\n",
941 // If the function couldn't be found, let's assume it's
942 // a bad rule and refuse it.
951 /*-----------------------------------------------------------------*/
952 /* printLine - prints a line chain into a given file */
953 /*-----------------------------------------------------------------*/
955 printLine (lineNode * head, FILE * of)
957 iCode *last_ic = NULL;
958 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
965 if (head->ic!=last_ic)
968 if (debug_iCode_tracking)
971 fprintf (of, "; block = %d, seq = %d\n",
972 head->ic->block, head->ic->seq);
974 fprintf (of, "; iCode lost\n");
978 /* don't indent comments & labels */
980 (*head->line == ';' ||
981 head->line[strlen (head->line) - 1] == ':')) {
982 fprintf (of, "%s\n", head->line);
984 if (head->isInline && *head->line=='#') {
985 // comment out preprocessor directives in inline asm
988 fprintf (of, "\t%s\n", head->line);
994 /*-----------------------------------------------------------------*/
995 /* newPeepRule - creates a new peeprule and attach it to the root */
996 /*-----------------------------------------------------------------*/
998 newPeepRule (lineNode * match,
1005 pr = Safe_alloc ( sizeof (peepRule));
1007 pr->replace = replace;
1008 pr->restart = restart;
1012 pr->cond = Safe_strdup (cond);
1017 pr->vars = newHashTable (100);
1019 /* if root is empty */
1021 rootRules = currRule = pr;
1023 currRule = currRule->next = pr;
1028 /*-----------------------------------------------------------------*/
1029 /* newLineNode - creates a new peep line */
1030 /*-----------------------------------------------------------------*/
1032 newLineNode (char *line)
1036 pl = Safe_alloc ( sizeof (lineNode));
1037 pl->line = Safe_strdup (line);
1042 /*-----------------------------------------------------------------*/
1043 /* connectLine - connects two lines */
1044 /*-----------------------------------------------------------------*/
1046 connectLine (lineNode * pl1, lineNode * pl2)
1050 fprintf (stderr, "trying to connect null line\n");
1060 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1061 if (!*x) { fprintf(stderr,y); return ; } }
1063 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1064 if (!*x) { fprintf(stderr,z); return ; } }
1065 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1066 if (!*x) { fprintf(stderr,z); return ; } }
1068 /*-----------------------------------------------------------------*/
1069 /* getPeepLine - parses the peep lines */
1070 /*-----------------------------------------------------------------*/
1072 getPeepLine (lineNode ** head, char **bpp)
1074 char lines[MAX_PATTERN_LEN];
1077 lineNode *currL = NULL;
1084 fprintf (stderr, "unexpected end of match pattern\n");
1091 while (isspace (*bp) ||
1102 /* read till end of line */
1104 while ((*bp != '\n' && *bp != '}') && *bp)
1109 *head = currL = newLineNode (lines);
1111 currL = connectLine (currL, newLineNode (lines));
1114 while (*lp && isspace(*lp))
1117 currL->isComment = 1;
1123 /*-----------------------------------------------------------------*/
1124 /* readRules - reads the rules from a string buffer */
1125 /*-----------------------------------------------------------------*/
1127 readRules (char *bp)
1130 char lines[MAX_PATTERN_LEN];
1134 lineNode *currL = NULL;
1140 /* look for the token "replace" that is the
1142 while (*bp && strncmp (bp, "replace", 7))
1149 /* then look for either "restart" or '{' */
1150 while (strncmp (bp, "restart", 7) &&
1157 fprintf (stderr, "expected 'restart' or '{'\n");
1165 { /* must be restart */
1167 bp += strlen ("restart");
1169 EXPECT_CHR (bp, '{', "expected '{'\n");
1173 /* skip thru all the blank space */
1174 SKIP_SPACE (bp, "unexpected end of rule\n");
1176 match = replace = currL = NULL;
1177 /* we are the start of a rule */
1178 getPeepLine (&match, &bp);
1180 /* now look for by */
1181 EXPECT_STR (bp, "by", "expected 'by'\n");
1183 /* then look for a '{' */
1184 EXPECT_CHR (bp, '{', "expected '{'\n");
1187 SKIP_SPACE (bp, "unexpected end of rule\n");
1188 getPeepLine (&replace, &bp);
1190 /* look for a 'if' */
1191 while ((isspace (*bp) || *bp == '\n') && *bp)
1194 if (strncmp (bp, "if", 2) == 0)
1197 while ((isspace (*bp) || *bp == '\n') && *bp)
1201 fprintf (stderr, "expected condition name\n");
1205 /* look for the condition */
1207 while (*bp && (*bp != '\n'))
1213 newPeepRule (match, replace, lines, restart);
1216 newPeepRule (match, replace, NULL, restart);
1221 /*-----------------------------------------------------------------*/
1222 /* keyForVar - returns the numeric key for a var */
1223 /*-----------------------------------------------------------------*/
1229 while (isdigit (*d))
1238 /*-----------------------------------------------------------------*/
1239 /* bindVar - binds a value to a variable in the given hashtable */
1240 /*-----------------------------------------------------------------*/
1242 bindVar (int key, char **s, hTab ** vtab)
1244 char vval[MAX_PATTERN_LEN];
1248 /* first get the value of the variable */
1250 /* the value is ended by a ',' or space or newline or null or ) */
1259 /* if we find a '(' then we need to balance it */
1271 // include the trailing ')'
1280 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1282 hTabAddItem (vtab, key, vvx);
1285 /*-----------------------------------------------------------------*/
1286 /* matchLine - matches one line */
1287 /*-----------------------------------------------------------------*/
1289 matchLine (char *s, char *d, hTab ** vars)
1298 /* skip white space in both */
1299 while (isspace (*s))
1301 while (isspace (*d))
1304 /* if the destination is a var */
1305 if (*d == '%' && isdigit (*(d + 1)) && vars)
1307 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1308 /* if the variable is already bound
1309 then it MUST match with dest */
1317 /* variable not bound we need to
1319 bindVar (keyForVar (d + 1), &s, vars);
1321 /* in either case go past the variable */
1323 while (isdigit (*d))
1326 while (isspace (*s))
1328 while (isspace (*d))
1332 /* they should be an exact match other wise */
1341 /* get rid of the trailing spaces
1342 in both source & destination */
1344 while (isspace (*s))
1348 while (isspace (*d))
1351 /* after all this if only one of them
1352 has something left over then no match */
1359 /*-----------------------------------------------------------------*/
1360 /* matchRule - matches a all the rule lines */
1361 /*-----------------------------------------------------------------*/
1363 matchRule (lineNode * pl,
1368 lineNode *spl; /* source pl */
1369 lineNode *rpl; /* rule peep line */
1371 /* setToNull((void *) &pr->vars); */
1372 /* pr->vars = newHashTable(100); */
1374 /* for all the lines defined in the rule */
1380 /* if the source line starts with a ';' then
1381 comment line don't process or the source line
1382 contains == . debugger information skip it */
1384 (*spl->line == ';' || spl->isDebug))
1390 if (!matchLine (spl->line, rpl->line, &pr->vars))
1398 /* if rules ended */
1401 /* if this rule has additional conditions */
1404 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1423 reassociate_ic_down (lineNode *shead, lineNode *stail,
1424 lineNode *rhead, lineNode *rtail)
1426 lineNode *csl; /* current source line */
1427 lineNode *crl; /* current replacement line */
1433 /* skip over any comments */
1434 while (csl!=stail->next && csl->isComment)
1436 while (crl!=rtail->next && crl->isComment)
1439 /* quit if we reach the end */
1440 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1443 if (matchLine(csl->line,crl->line,NULL))
1455 reassociate_ic_up (lineNode *shead, lineNode *stail,
1456 lineNode *rhead, lineNode *rtail)
1458 lineNode *csl; /* current source line */
1459 lineNode *crl; /* current replacement line */
1465 /* skip over any comments */
1466 while (csl!=shead->prev && csl->isComment)
1468 while (crl!=rhead->prev && crl->isComment)
1471 /* quit if we reach the end */
1472 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1475 if (matchLine(csl->line,crl->line,NULL))
1486 /*------------------------------------------------------------------*/
1487 /* reassociate_ic - reassociate replacement lines with origin iCode */
1488 /*------------------------------------------------------------------*/
1490 reassociate_ic (lineNode *shead, lineNode *stail,
1491 lineNode *rhead, lineNode *rtail)
1493 lineNode *csl; /* current source line */
1494 lineNode *crl; /* current replacement line */
1498 /* Check to see if all the source lines (excluding comments) came
1499 ** for the same iCode
1502 for (csl=shead;csl!=stail->next;csl=csl->next)
1503 if (csl->ic && !csl->isComment)
1508 single_iCode = (ic!=NULL);
1509 for (csl=shead;csl!=stail->next;csl=csl->next)
1510 if ((csl->ic != ic) && !csl->isComment)
1512 /* More than one iCode was found. However, if it's just the
1513 ** last line with the different iCode and it was not changed
1514 ** in the replacement, everything else must be the first iCode.
1516 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1518 rtail->ic = stail->ic;
1519 for (crl=rhead;crl!=rtail;crl=crl->next)
1524 single_iCode = FALSE;
1528 /* If all of the source lines came from the same iCode, then so have
1529 ** all of the replacement lines too.
1533 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1538 /* The source lines span iCodes, so we may end up with replacement
1539 ** lines that we don't know which iCode(s) to associate with. Do the
1540 ** best we can by using the following strategies:
1541 ** 1) Start at the top and scan down. As long as the source line
1542 ** matches the replacement line, they have the same iCode.
1543 ** 2) Start at the bottom and scan up. As long as the source line
1544 ** matches the replacement line, they have the same iCode.
1545 ** 3) For any label in the source, look for a matching label in
1546 ** the replacment. If found, they have the same iCode. From
1547 ** these matching labels, scan down for additional matching
1548 ** lines; if found, they also have the same iCode.
1551 /* Strategy #1: Start at the top and scan down for matches
1553 reassociate_ic_down(shead,stail,rhead,rtail);
1555 /* Strategy #2: Start at the bottom and scan up for matches
1557 reassociate_ic_up(shead,stail,rhead,rtail);
1559 /* Strategy #3: Try to match labels
1564 const char *labelStart;
1567 /* skip over any comments */
1568 while (csl!=stail->next && csl->isComment)
1570 if (csl==stail->next)
1573 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1575 /* found a source line label; look for it in the replacment lines */
1579 while (crl!=rtail->next && crl->isComment)
1581 if (crl==rtail->next)
1583 if (matchLine(csl->line, crl->line, NULL))
1585 reassociate_ic_down(csl,stail,crl,rtail);
1595 /* Try to assign a meaningful iCode to any comment that is missing
1596 one. Since they are comments, it's ok to make mistakes; we are just
1597 trying to improve continuity to simplify other tests.
1600 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1602 if (!crl->ic && ic && crl->isComment)
1609 /*-----------------------------------------------------------------*/
1610 /* replaceRule - does replacement of a matching pattern */
1611 /*-----------------------------------------------------------------*/
1613 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1615 lineNode *cl = NULL;
1616 lineNode *pl = NULL, *lhead = NULL;
1617 /* a long function name and long variable name can evaluate to
1618 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1619 char lb[MAX_PATTERN_LEN*4];
1621 lineNode *comment = NULL;
1623 /* collect all the comment lines in the source */
1624 for (cl = *shead; cl != stail; cl = cl->next)
1626 if (cl->line && (*cl->line == ';' || cl->isDebug))
1628 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1629 (comment = newLineNode (cl->line)));
1630 pl->isDebug = cl->isDebug;
1631 pl->isComment = cl->isComment || (*cl->line == ';');
1636 /* for all the lines in the replacement pattern do */
1637 for (pl = pr->replace; pl; pl = pl->next)
1647 /* if the line contains a variable */
1648 if (*l == '%' && isdigit (*(l + 1)))
1650 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1653 fprintf (stderr, "used unbound variable in replacement\n");
1661 while (isdigit (*l)) {
1671 cl = connectLine (cl, newLineNode (lb));
1673 lhead = cl = newLineNode (lb);
1674 cl->isComment = pl->isComment;
1677 /* add the comments if any to the head of list */
1680 lineNode *lc = comment;
1689 /* determine which iCodes the replacment lines relate to */
1690 reassociate_ic(*shead,stail,lhead,cl);
1692 /* now we need to connect / replace the original chain */
1693 /* if there is a prev then change it */
1696 (*shead)->prev->next = lhead;
1697 lhead->prev = (*shead)->prev;
1700 /* now for the tail */
1701 if (stail && stail->next)
1703 stail->next->prev = cl;
1705 cl->next = stail->next;
1709 /* Returns TRUE if this line is a label definition.
1711 * If so, start will point to the start of the label name,
1712 * and len will be it's length.
1715 isLabelDefinition (const char *line, const char **start, int *len)
1717 const char *cp = line;
1719 /* This line is a label if if consists of:
1720 * [optional whitespace] followed by identifier chars
1721 * (alnum | $ | _ ) followed by a colon.
1724 while (*cp && isspace (*cp))
1736 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1741 if ((cp == *start) || (*cp != ':'))
1746 *len = (cp - (*start));
1750 /* Quick & dirty string hash function. */
1752 hashSymbolName (const char *name)
1758 hash = (hash << 6) ^ *name;
1767 return hash % HTAB_SIZE;
1770 /* Build a hash of all labels in the passed set of lines
1771 * and how many times they are referenced.
1774 buildLabelRefCountHash (lineNode * head)
1781 assert (labelHash == NULL);
1782 labelHash = newHashTable (HTAB_SIZE);
1784 /* First pass: locate all the labels. */
1789 if (isLabelDefinition (line->line, &label, &labelLen)
1790 && labelLen <= SDCC_NAME_MAX)
1792 labelHashEntry *entry;
1794 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1796 memcpy (entry->name, label, labelLen);
1797 entry->name[labelLen] = 0;
1798 entry->refCount = -1;
1800 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1806 /* Second pass: for each line, note all the referenced labels. */
1807 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1811 for (i = 0; i < HTAB_SIZE; i++)
1813 labelHashEntry *thisEntry;
1815 thisEntry = hTabFirstItemWK (labelHash, i);
1819 if (strstr (line->line, thisEntry->name))
1821 thisEntry->refCount++;
1823 thisEntry = hTabNextItemWK (labelHash);
1830 /* Spew the contents of the table. Debugging fun only. */
1831 for (i = 0; i < HTAB_SIZE; i++)
1833 labelHashEntry *thisEntry;
1835 thisEntry = hTabFirstItemWK (labelHash, i);
1839 fprintf (stderr, "label: %s ref %d\n",
1840 thisEntry->name, thisEntry->refCount);
1841 thisEntry = hTabNextItemWK (labelHash);
1847 /* How does this work?
1853 replace and restart.
1858 Where is stuff allocated?
1862 /*-----------------------------------------------------------------*/
1863 /* peepHole - matches & substitutes rules */
1864 /*-----------------------------------------------------------------*/
1866 peepHole (lineNode ** pls)
1870 lineNode *mtail = NULL;
1873 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1874 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1875 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1879 assert(labelHash == NULL);
1886 for (pr = rootRules; pr; pr = pr->next)
1888 for (spl = *pls; spl; spl = spl->next)
1890 /* if inline assembler then no peep hole */
1894 /* don't waste time starting a match on debug symbol
1896 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1901 /* Tidy up any data stored in the hTab */
1904 if (matchRule (spl, &mtail, pr, *pls))
1909 replaceRule (pls, mtail, pr);
1911 replaceRule (&spl, mtail, pr);
1913 /* if restart rule type then
1914 start at the top again */
1923 hTabDeleteAll (pr->vars);
1924 Safe_free (pr->vars);
1928 freeTrace (&_G.values);
1931 } while (restart == TRUE);
1935 hTabDeleteAll (labelHash);
1936 freeTrace (&_G.labels);
1942 /*-----------------------------------------------------------------*/
1943 /* readFileIntoBuffer - reads a file into a string buffer */
1944 /*-----------------------------------------------------------------*/
1946 readFileIntoBuffer (char *fname)
1952 char lb[MAX_PATTERN_LEN];
1954 if (!(f = fopen (fname, "r")))
1956 fprintf (stderr, "cannot open peep rule file\n");
1960 while ((ch = fgetc (f)) != EOF)
1964 /* if we maxed out our local buffer */
1965 if (nch >= (MAX_PATTERN_LEN - 2))
1968 /* copy it into allocated buffer */
1971 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1972 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1976 rs = Safe_strdup (lb);
1982 /* if some charaters left over */
1986 /* copy it into allocated buffer */
1989 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1990 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1994 rs = Safe_strdup (lb);
2000 /*-----------------------------------------------------------------*/
2001 /* initPeepHole - initialises the peep hole optimizer stuff */
2002 /*-----------------------------------------------------------------*/
2008 /* read in the default rules */
2009 readRules (port->peep.default_rules);
2011 /* if we have any additional file read it too */
2012 if (options.peep_file)
2014 readRules (s = readFileIntoBuffer (options.peep_file));
2015 setToNull ((void *) &s);
2019 #if !OPT_DISABLE_PIC
2020 /* Convert the peep rules into pcode.
2021 NOTE: this is only support in the PIC port (at the moment)
2024 peepRules2pCode(rootRules);
2027 #if !OPT_DISABLE_PIC16
2028 /* Convert the peep rules into pcode.
2029 NOTE: this is only support in the PIC port (at the moment)
2030 and the PIC16 port (VR 030601)
2032 if (TARGET_IS_PIC16)
2033 pic16_peepRules2pCode(rootRules);