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 /* if the previous two instructions are "ljmp"s then don't
283 do it since it can be part of a jump table */
284 if (currPl->prev && currPl->prev->prev &&
285 strstr (currPl->prev->line, "ljmp") &&
286 strstr (currPl->prev->prev->line, "ljmp"))
289 /* calculate the label distance : the jump for reladdr can be
290 +/- 127 bytes, here Iam assuming that an average 8051
291 instruction is 2 bytes long, so if the label is more than
292 63 intructions away, the label is considered out of range
293 for a relative jump. we could get more precise this will
294 suffice for now since it catches > 90% cases */
295 dist = (pcDistance (currPl, lbl, TRUE) +
296 pcDistance (currPl, lbl, FALSE));
298 /* changed to 127, now that pcDistance return actual number of bytes */
299 if (!dist || dist > 127)
305 /*-----------------------------------------------------------------*/
306 /* labelIsReturnOnly - Check if label %5 is followed by RET */
307 /*-----------------------------------------------------------------*/
308 FBYNAME (labelIsReturnOnly)
310 /* assumes that %5 pattern variable has the label name */
311 const char *label, *p;
315 label = hTabItemWithKey (vars, 5);
316 if (!label) return FALSE;
319 for(pl = currPl; pl; pl = pl->next) {
320 if (pl->line && !pl->isDebug &&
321 pl->line[strlen(pl->line)-1] == ':') {
322 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
323 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
324 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
325 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
326 *(pl->line+5) != '$') {
327 return FALSE; /* non-local label encountered */
331 if (!pl) return FALSE; /* did not find the label */
333 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
335 for (p = pl->line; *p && isspace(*p); p++)
337 if (strcmp(p, "ret") == 0) return TRUE;
342 /*-----------------------------------------------------------------*/
343 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
344 /* usage of it in the code depends on a value from this section */
345 /*-----------------------------------------------------------------*/
346 FBYNAME (okToRemoveSLOC)
349 const char *sloc, *p;
350 int dummy1, dummy2, dummy3;
352 /* assumes that %1 as the SLOC name */
353 sloc = hTabItemWithKey (vars, 1);
354 if (sloc == NULL) return FALSE;
355 p = strstr(sloc, "sloc");
356 if (p == NULL) return FALSE;
358 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
359 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
360 /* the sloc name begins with that. Probably not really necessary */
362 /* Look for any occurance of this SLOC before the peephole match */
363 for (pl = currPl->prev; pl; pl = pl->prev) {
364 if (pl->line && !pl->isDebug && !pl->isComment
365 && *pl->line != ';' && strstr(pl->line, sloc))
368 /* Look for any occurance of this SLOC after the peephole match */
369 for (pl = endPl->next; pl; pl = pl->next) {
370 if (pl->line && !pl->isDebug && !pl->isComment
371 && *pl->line != ';' && strstr(pl->line, sloc))
374 return TRUE; /* safe for a peephole to remove it :) */
378 /*-----------------------------------------------------------------*/
379 /* operandsNotSame - check if %1 & %2 are the same */
380 /*-----------------------------------------------------------------*/
381 FBYNAME (operandsNotSame)
383 char *op1 = hTabItemWithKey (vars, 1);
384 char *op2 = hTabItemWithKey (vars, 2);
386 if (strcmp (op1, op2) == 0)
392 /*-----------------------------------------------------------------*/
393 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
394 /*-----------------------------------------------------------------*/
395 FBYNAME (operandsNotSame3)
397 char *op1 = hTabItemWithKey (vars, 1);
398 char *op2 = hTabItemWithKey (vars, 2);
399 char *op3 = hTabItemWithKey (vars, 3);
401 if ( (strcmp (op1, op2) == 0) ||
402 (strcmp (op1, op3) == 0) ||
403 (strcmp (op2, op3) == 0) )
409 /*-----------------------------------------------------------------*/
410 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
411 /*-----------------------------------------------------------------*/
412 FBYNAME (operandsNotSame4)
414 char *op1 = hTabItemWithKey (vars, 1);
415 char *op2 = hTabItemWithKey (vars, 2);
416 char *op3 = hTabItemWithKey (vars, 3);
417 char *op4 = hTabItemWithKey (vars, 4);
419 if ( (strcmp (op1, op2) == 0) ||
420 (strcmp (op1, op3) == 0) ||
421 (strcmp (op1, op4) == 0) ||
422 (strcmp (op2, op3) == 0) ||
423 (strcmp (op2, op4) == 0) ||
424 (strcmp (op3, op4) == 0) )
430 /*-----------------------------------------------------------------*/
431 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
432 /*-----------------------------------------------------------------*/
433 FBYNAME (operandsNotSame5)
435 char *op1 = hTabItemWithKey (vars, 1);
436 char *op2 = hTabItemWithKey (vars, 2);
437 char *op3 = hTabItemWithKey (vars, 3);
438 char *op4 = hTabItemWithKey (vars, 4);
439 char *op5 = hTabItemWithKey (vars, 5);
441 if ( (strcmp (op1, op2) == 0) ||
442 (strcmp (op1, op3) == 0) ||
443 (strcmp (op1, op4) == 0) ||
444 (strcmp (op1, op5) == 0) ||
445 (strcmp (op2, op3) == 0) ||
446 (strcmp (op2, op4) == 0) ||
447 (strcmp (op2, op5) == 0) ||
448 (strcmp (op3, op4) == 0) ||
449 (strcmp (op3, op5) == 0) ||
450 (strcmp (op4, op5) == 0) )
456 /*-----------------------------------------------------------------*/
457 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
458 /*-----------------------------------------------------------------*/
459 FBYNAME (operandsNotSame6)
461 char *op1 = hTabItemWithKey (vars, 1);
462 char *op2 = hTabItemWithKey (vars, 2);
463 char *op3 = hTabItemWithKey (vars, 3);
464 char *op4 = hTabItemWithKey (vars, 4);
465 char *op5 = hTabItemWithKey (vars, 5);
466 char *op6 = hTabItemWithKey (vars, 6);
468 if ( (strcmp (op1, op2) == 0) ||
469 (strcmp (op1, op3) == 0) ||
470 (strcmp (op1, op4) == 0) ||
471 (strcmp (op1, op5) == 0) ||
472 (strcmp (op1, op6) == 0) ||
473 (strcmp (op2, op3) == 0) ||
474 (strcmp (op2, op4) == 0) ||
475 (strcmp (op2, op5) == 0) ||
476 (strcmp (op2, op6) == 0) ||
477 (strcmp (op3, op4) == 0) ||
478 (strcmp (op3, op5) == 0) ||
479 (strcmp (op3, op6) == 0) ||
480 (strcmp (op4, op5) == 0) ||
481 (strcmp (op4, op6) == 0) ||
482 (strcmp (op5, op6) == 0) )
489 /*-----------------------------------------------------------------*/
490 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
491 /*-----------------------------------------------------------------*/
492 FBYNAME (operandsNotSame7)
494 char *op1 = hTabItemWithKey (vars, 1);
495 char *op2 = hTabItemWithKey (vars, 2);
496 char *op3 = hTabItemWithKey (vars, 3);
497 char *op4 = hTabItemWithKey (vars, 4);
498 char *op5 = hTabItemWithKey (vars, 5);
499 char *op6 = hTabItemWithKey (vars, 6);
500 char *op7 = hTabItemWithKey (vars, 7);
502 if ( (strcmp (op1, op2) == 0) ||
503 (strcmp (op1, op3) == 0) ||
504 (strcmp (op1, op4) == 0) ||
505 (strcmp (op1, op5) == 0) ||
506 (strcmp (op1, op6) == 0) ||
507 (strcmp (op1, op7) == 0) ||
508 (strcmp (op2, op3) == 0) ||
509 (strcmp (op2, op4) == 0) ||
510 (strcmp (op2, op5) == 0) ||
511 (strcmp (op2, op6) == 0) ||
512 (strcmp (op2, op7) == 0) ||
513 (strcmp (op3, op4) == 0) ||
514 (strcmp (op3, op5) == 0) ||
515 (strcmp (op3, op6) == 0) ||
516 (strcmp (op3, op7) == 0) ||
517 (strcmp (op4, op5) == 0) ||
518 (strcmp (op4, op6) == 0) ||
519 (strcmp (op4, op7) == 0) ||
520 (strcmp (op5, op6) == 0) ||
521 (strcmp (op5, op7) == 0) ||
522 (strcmp (op6, op7) == 0) )
528 /*-----------------------------------------------------------------*/
529 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
530 /*-----------------------------------------------------------------*/
531 FBYNAME (operandsNotSame8)
533 char *op1 = hTabItemWithKey (vars, 1);
534 char *op2 = hTabItemWithKey (vars, 2);
535 char *op3 = hTabItemWithKey (vars, 3);
536 char *op4 = hTabItemWithKey (vars, 4);
537 char *op5 = hTabItemWithKey (vars, 5);
538 char *op6 = hTabItemWithKey (vars, 6);
539 char *op7 = hTabItemWithKey (vars, 7);
540 char *op8 = hTabItemWithKey (vars, 8);
542 if ( (strcmp (op1, op2) == 0) ||
543 (strcmp (op1, op3) == 0) ||
544 (strcmp (op1, op4) == 0) ||
545 (strcmp (op1, op5) == 0) ||
546 (strcmp (op1, op6) == 0) ||
547 (strcmp (op1, op7) == 0) ||
548 (strcmp (op1, op8) == 0) ||
549 (strcmp (op2, op3) == 0) ||
550 (strcmp (op2, op4) == 0) ||
551 (strcmp (op2, op5) == 0) ||
552 (strcmp (op2, op6) == 0) ||
553 (strcmp (op2, op7) == 0) ||
554 (strcmp (op2, op8) == 0) ||
555 (strcmp (op3, op4) == 0) ||
556 (strcmp (op3, op5) == 0) ||
557 (strcmp (op3, op6) == 0) ||
558 (strcmp (op3, op7) == 0) ||
559 (strcmp (op3, op8) == 0) ||
560 (strcmp (op4, op5) == 0) ||
561 (strcmp (op4, op6) == 0) ||
562 (strcmp (op4, op7) == 0) ||
563 (strcmp (op4, op8) == 0) ||
564 (strcmp (op5, op6) == 0) ||
565 (strcmp (op5, op7) == 0) ||
566 (strcmp (op5, op8) == 0) ||
567 (strcmp (op6, op7) == 0) ||
568 (strcmp (op6, op8) == 0) ||
569 (strcmp (op7, op8) == 0) )
578 * takes two parameters: a variable (bound to a label name)
579 * and an expected reference count.
581 * Returns TRUE if that label is defined and referenced exactly
582 * the given number of times.
584 FBYNAME (labelRefCount)
586 int varNumber, expectedRefCount;
589 /* If we don't have the label hash table yet, build it. */
592 buildLabelRefCountHash (head);
595 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
597 char *label = hTabItemWithKey (vars, varNumber);
601 labelHashEntry *entry;
603 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
607 if (!strcmp (label, entry->name))
611 entry = hTabNextItemWK (labelHash);
617 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
618 label, entry->refCount, expectedRefCount);
621 rc = (expectedRefCount == entry->refCount);
625 fprintf (stderr, "*** internal error: no label has entry for"
626 " %s in labelRefCount peephole.\n",
632 fprintf (stderr, "*** internal error: var %d not bound"
633 " in peephole labelRefCount rule.\n",
641 "*** internal error: labelRefCount peephole restriction"
642 " malformed: %s\n", cmdLine);
647 /* Within the context of the lines currPl through endPl, determine
648 ** if the variable var contains a symbol that is volatile. Returns
649 ** TRUE only if it is certain that this was not volatile (the symbol
650 ** was found and not volatile, or var was a constant or CPU register).
651 ** Returns FALSE if the symbol was found and volatile, the symbol was
652 ** not found, or var was a indirect/pointer addressing mode.
655 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
657 char symname[SDCC_NAME_MAX + 1];
664 /* Can't tell if indirect accesses are volatile or not, so
665 ** assume they are, just to be safe.
667 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
672 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
674 if (strstr(var,"(bc)"))
676 if (strstr(var,"(de)"))
678 if (strstr(var,"(hl)"))
680 if (strstr(var,"(ix"))
682 if (strstr(var,"(iy"))
686 /* Extract a symbol name from the variable */
687 while (*vp && (*vp!='_'))
689 while (*vp && (isalnum(*vp) || *vp=='_'))
695 /* Nothing resembling a symbol name was found, so it can't
702 for (cl = currPl; cl!=endPl->next; cl = cl->next)
704 if (cl->ic && (cl->ic!=last_ic))
710 op = IC_COND (cl->ic);
711 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
712 return !op->isvolatile;
714 op = IC_JTCOND (cl->ic);
715 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
716 return !op->isvolatile;
718 op = IC_LEFT (cl->ic);
719 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
720 return !op->isvolatile;
721 op = IC_RIGHT (cl->ic);
722 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
723 return !op->isvolatile;
724 op = IC_RESULT (cl->ic);
725 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
726 return !op->isvolatile;
731 /* Couldn't find the symbol for some reason. Assume volatile. */
737 * This rule restriction has two different behaviours depending on
738 * the number of parameters given.
740 * if notVolatile (no parameters given)
741 * The rule is applied only if none of the iCodes originating
742 * the matched pattern reference a volatile operand.
744 * if notVolatile %1 ... (one or more parameters given)
745 * The rule is applied if the parameters are not expressions
746 * containing volatile symbols and are not pointer accesses.
749 FBYNAME (notVolatile)
760 /* If no parameters given, just scan the iCodes for volatile operands */
761 for (cl = currPl; cl!=endPl->next; cl = cl->next)
768 op = IC_COND (cl->ic);
769 if (IS_SYMOP (op) && op->isvolatile)
772 op = IC_JTCOND (cl->ic);
773 if (IS_SYMOP (op) && op->isvolatile)
776 op = IC_LEFT (cl->ic);
777 if (IS_SYMOP (op) && op->isvolatile)
779 op = IC_RIGHT (cl->ic);
780 if (IS_SYMOP (op) && op->isvolatile)
782 op = IC_RESULT (cl->ic);
783 if (IS_SYMOP (op) && op->isvolatile)
791 /* There were parameters; check the volatility of each */
792 while (*cmdLine && isspace(*cmdLine))
799 if (!isdigit(*cmdLine))
801 varNumber = strtol(cmdLine, &digitend, 10);
803 while (*cmdLine && isspace(*cmdLine))
806 var = hTabItemWithKey (vars, varNumber);
810 notvol = notVolatileVariable (var, currPl, endPl);
816 fprintf (stderr, "*** internal error: var %d not bound"
817 " in peephole notVolatile rule.\n",
828 "*** internal error: notVolatile peephole restriction"
829 " malformed: %s\n", cmdLine);
834 /*-----------------------------------------------------------------*/
835 /* callFuncByName - calls a function as defined in the table */
836 /*-----------------------------------------------------------------*/
838 callFuncByName (char *fname,
847 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
852 "labelInRange", labelInRange
856 "operandsNotSame", operandsNotSame
860 "operandsNotSame3", operandsNotSame3
864 "operandsNotSame4", operandsNotSame4
868 "operandsNotSame5", operandsNotSame5
872 "operandsNotSame6", operandsNotSame6
876 "operandsNotSame7", operandsNotSame7
880 "operandsNotSame8", operandsNotSame8
884 "24bitMode", flat24bitMode
888 "xramMovcOption", xramMovcOption
892 "labelRefCount", labelRefCount
896 "portIsDS390", portIsDS390
899 "labelIsReturnOnly", labelIsReturnOnly
902 "okToRemoveSLOC", okToRemoveSLOC
905 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
908 "notVolatile", notVolatile
912 char *cmdCopy, *funcName, *funcArgs;
915 /* Isolate the function name part (we are passed the full condition
916 * string including arguments)
918 cmdCopy = Safe_strdup(fname);
919 funcName = strtok(cmdCopy, " \t");
920 funcArgs = strtok(NULL, "");
922 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
924 if (strcmp (ftab[i].fname, funcName) == 0)
926 rc = (*ftab[i].func) (vars, currPl, endPl, head,
934 "could not find named function \"%s\" in "
935 "peephole function table\n",
937 // If the function couldn't be found, let's assume it's
938 // a bad rule and refuse it.
947 /*-----------------------------------------------------------------*/
948 /* printLine - prints a line chain into a given file */
949 /*-----------------------------------------------------------------*/
951 printLine (lineNode * head, FILE * of)
953 iCode *last_ic = NULL;
954 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
961 if (head->ic!=last_ic)
964 if (debug_iCode_tracking)
967 fprintf (of, "; block = %d, seq = %d\n",
968 head->ic->block, head->ic->seq);
970 fprintf (of, "; iCode lost\n");
974 /* don't indent comments & labels */
976 (*head->line == ';' ||
977 head->line[strlen (head->line) - 1] == ':')) {
978 fprintf (of, "%s\n", head->line);
980 if (head->isInline && *head->line=='#') {
981 // comment out preprocessor directives in inline asm
984 fprintf (of, "\t%s\n", head->line);
990 /*-----------------------------------------------------------------*/
991 /* newPeepRule - creates a new peeprule and attach it to the root */
992 /*-----------------------------------------------------------------*/
994 newPeepRule (lineNode * match,
1001 pr = Safe_alloc ( sizeof (peepRule));
1003 pr->replace = replace;
1004 pr->restart = restart;
1008 pr->cond = Safe_strdup (cond);
1013 pr->vars = newHashTable (100);
1015 /* if root is empty */
1017 rootRules = currRule = pr;
1019 currRule = currRule->next = pr;
1024 /*-----------------------------------------------------------------*/
1025 /* newLineNode - creates a new peep line */
1026 /*-----------------------------------------------------------------*/
1028 newLineNode (char *line)
1032 pl = Safe_alloc ( sizeof (lineNode));
1033 pl->line = Safe_strdup (line);
1038 /*-----------------------------------------------------------------*/
1039 /* connectLine - connects two lines */
1040 /*-----------------------------------------------------------------*/
1042 connectLine (lineNode * pl1, lineNode * pl2)
1046 fprintf (stderr, "trying to connect null line\n");
1056 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1057 if (!*x) { fprintf(stderr,y); return ; } }
1059 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1060 if (!*x) { fprintf(stderr,z); return ; } }
1061 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1062 if (!*x) { fprintf(stderr,z); return ; } }
1064 /*-----------------------------------------------------------------*/
1065 /* getPeepLine - parses the peep lines */
1066 /*-----------------------------------------------------------------*/
1068 getPeepLine (lineNode ** head, char **bpp)
1070 char lines[MAX_PATTERN_LEN];
1073 lineNode *currL = NULL;
1080 fprintf (stderr, "unexpected end of match pattern\n");
1087 while (isspace (*bp) ||
1098 /* read till end of line */
1100 while ((*bp != '\n' && *bp != '}') && *bp)
1105 *head = currL = newLineNode (lines);
1107 currL = connectLine (currL, newLineNode (lines));
1110 while (*lp && isspace(*lp))
1113 currL->isComment = 1;
1119 /*-----------------------------------------------------------------*/
1120 /* readRules - reads the rules from a string buffer */
1121 /*-----------------------------------------------------------------*/
1123 readRules (char *bp)
1126 char lines[MAX_PATTERN_LEN];
1130 lineNode *currL = NULL;
1136 /* look for the token "replace" that is the
1138 while (*bp && strncmp (bp, "replace", 7))
1145 /* then look for either "restart" or '{' */
1146 while (strncmp (bp, "restart", 7) &&
1153 fprintf (stderr, "expected 'restart' or '{'\n");
1161 { /* must be restart */
1163 bp += strlen ("restart");
1165 EXPECT_CHR (bp, '{', "expected '{'\n");
1169 /* skip thru all the blank space */
1170 SKIP_SPACE (bp, "unexpected end of rule\n");
1172 match = replace = currL = NULL;
1173 /* we are the start of a rule */
1174 getPeepLine (&match, &bp);
1176 /* now look for by */
1177 EXPECT_STR (bp, "by", "expected 'by'\n");
1179 /* then look for a '{' */
1180 EXPECT_CHR (bp, '{', "expected '{'\n");
1183 SKIP_SPACE (bp, "unexpected end of rule\n");
1184 getPeepLine (&replace, &bp);
1186 /* look for a 'if' */
1187 while ((isspace (*bp) || *bp == '\n') && *bp)
1190 if (strncmp (bp, "if", 2) == 0)
1193 while ((isspace (*bp) || *bp == '\n') && *bp)
1197 fprintf (stderr, "expected condition name\n");
1201 /* look for the condition */
1203 while (*bp && (*bp != '\n'))
1209 newPeepRule (match, replace, lines, restart);
1212 newPeepRule (match, replace, NULL, restart);
1217 /*-----------------------------------------------------------------*/
1218 /* keyForVar - returns the numeric key for a var */
1219 /*-----------------------------------------------------------------*/
1225 while (isdigit (*d))
1234 /*-----------------------------------------------------------------*/
1235 /* bindVar - binds a value to a variable in the given hashtable */
1236 /*-----------------------------------------------------------------*/
1238 bindVar (int key, char **s, hTab ** vtab)
1240 char vval[MAX_PATTERN_LEN];
1244 /* first get the value of the variable */
1246 /* the value is ended by a ',' or space or newline or null or ) */
1255 /* if we find a '(' then we need to balance it */
1267 // include the trailing ')'
1276 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1278 hTabAddItem (vtab, key, vvx);
1281 /*-----------------------------------------------------------------*/
1282 /* matchLine - matches one line */
1283 /*-----------------------------------------------------------------*/
1285 matchLine (char *s, char *d, hTab ** vars)
1294 /* skip white space in both */
1295 while (isspace (*s))
1297 while (isspace (*d))
1300 /* if the destination is a var */
1301 if (*d == '%' && isdigit (*(d + 1)) && vars)
1303 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1304 /* if the variable is already bound
1305 then it MUST match with dest */
1313 /* variable not bound we need to
1315 bindVar (keyForVar (d + 1), &s, vars);
1317 /* in either case go past the variable */
1319 while (isdigit (*d))
1322 while (isspace (*s))
1324 while (isspace (*d))
1328 /* they should be an exact match other wise */
1337 /* get rid of the trailing spaces
1338 in both source & destination */
1340 while (isspace (*s))
1344 while (isspace (*d))
1347 /* after all this if only one of them
1348 has something left over then no match */
1355 /*-----------------------------------------------------------------*/
1356 /* matchRule - matches a all the rule lines */
1357 /*-----------------------------------------------------------------*/
1359 matchRule (lineNode * pl,
1364 lineNode *spl; /* source pl */
1365 lineNode *rpl; /* rule peep line */
1367 /* setToNull((void **) &pr->vars); */
1368 /* pr->vars = newHashTable(100); */
1370 /* for all the lines defined in the rule */
1376 /* if the source line starts with a ';' then
1377 comment line don't process or the source line
1378 contains == . debugger information skip it */
1380 (*spl->line == ';' || spl->isDebug))
1386 if (!matchLine (spl->line, rpl->line, &pr->vars))
1394 /* if rules ended */
1397 /* if this rule has additional conditions */
1400 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1419 reassociate_ic_down (lineNode *shead, lineNode *stail,
1420 lineNode *rhead, lineNode *rtail)
1422 lineNode *csl; /* current source line */
1423 lineNode *crl; /* current replacement line */
1429 /* skip over any comments */
1430 while (csl!=stail->next && csl->isComment)
1432 while (crl!=rtail->next && crl->isComment)
1435 /* quit if we reach the end */
1436 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1439 if (matchLine(csl->line,crl->line,NULL))
1451 reassociate_ic_up (lineNode *shead, lineNode *stail,
1452 lineNode *rhead, lineNode *rtail)
1454 lineNode *csl; /* current source line */
1455 lineNode *crl; /* current replacement line */
1461 /* skip over any comments */
1462 while (csl!=shead->prev && csl->isComment)
1464 while (crl!=rhead->prev && crl->isComment)
1467 /* quit if we reach the end */
1468 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1471 if (matchLine(csl->line,crl->line,NULL))
1482 /*------------------------------------------------------------------*/
1483 /* reassociate_ic - reassociate replacement lines with origin iCode */
1484 /*------------------------------------------------------------------*/
1486 reassociate_ic (lineNode *shead, lineNode *stail,
1487 lineNode *rhead, lineNode *rtail)
1489 lineNode *csl; /* current source line */
1490 lineNode *crl; /* current replacement line */
1494 /* Check to see if all the source lines (excluding comments) came
1495 ** for the same iCode
1498 for (csl=shead;csl!=stail->next;csl=csl->next)
1499 if (csl->ic && !csl->isComment)
1504 single_iCode = (ic!=NULL);
1505 for (csl=shead;csl!=stail->next;csl=csl->next)
1506 if ((csl->ic != ic) && !csl->isComment)
1508 /* More than one iCode was found. However, if it's just the
1509 ** last line with the different iCode and it was not changed
1510 ** in the replacement, everything else must be the first iCode.
1512 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1514 rtail->ic = stail->ic;
1515 for (crl=rhead;crl!=rtail;crl=crl->next)
1520 single_iCode = FALSE;
1524 /* If all of the source lines came from the same iCode, then so have
1525 ** all of the replacement lines too.
1529 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1534 /* The source lines span iCodes, so we may end up with replacement
1535 ** lines that we don't know which iCode(s) to associate with. Do the
1536 ** best we can by using the following strategies:
1537 ** 1) Start at the top and scan down. As long as the source line
1538 ** matches the replacement line, they have the same iCode.
1539 ** 2) Start at the bottom and scan up. As long as the source line
1540 ** matches the replacement line, they have the same iCode.
1541 ** 3) For any label in the source, look for a matching label in
1542 ** the replacment. If found, they have the same iCode. From
1543 ** these matching labels, scan down for additional matching
1544 ** lines; if found, they also have the same iCode.
1547 /* Strategy #1: Start at the top and scan down for matches
1549 reassociate_ic_down(shead,stail,rhead,rtail);
1551 /* Strategy #2: Start at the bottom and scan up for matches
1553 reassociate_ic_up(shead,stail,rhead,rtail);
1555 /* Strategy #3: Try to match labels
1560 const char *labelStart;
1563 /* skip over any comments */
1564 while (csl!=stail->next && csl->isComment)
1566 if (csl==stail->next)
1569 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1571 /* found a source line label; look for it in the replacment lines */
1575 while (crl!=rtail->next && crl->isComment)
1577 if (crl==rtail->next)
1579 if (matchLine(csl->line, crl->line, NULL))
1581 reassociate_ic_down(csl,stail,crl,rtail);
1591 /* Try to assign a meaningful iCode to any comment that is missing
1592 one. Since they are comments, it's ok to make mistakes; we are just
1593 trying to improve continuity to simplify other tests.
1596 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1598 if (!crl->ic && ic && crl->isComment)
1605 /*-----------------------------------------------------------------*/
1606 /* replaceRule - does replacement of a matching pattern */
1607 /*-----------------------------------------------------------------*/
1609 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1611 lineNode *cl = NULL;
1612 lineNode *pl = NULL, *lhead = NULL;
1613 /* a long function name and long variable name can evaluate to
1614 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1615 char lb[MAX_PATTERN_LEN*4];
1617 lineNode *comment = NULL;
1619 /* collect all the comment lines in the source */
1620 for (cl = *shead; cl != stail; cl = cl->next)
1622 if (cl->line && (*cl->line == ';' || cl->isDebug))
1624 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1625 (comment = newLineNode (cl->line)));
1626 pl->isDebug = cl->isDebug;
1627 pl->isComment = cl->isComment || (*cl->line == ';');
1632 /* for all the lines in the replacement pattern do */
1633 for (pl = pr->replace; pl; pl = pl->next)
1643 /* if the line contains a variable */
1644 if (*l == '%' && isdigit (*(l + 1)))
1646 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1649 fprintf (stderr, "used unbound variable in replacement\n");
1657 while (isdigit (*l)) {
1667 cl = connectLine (cl, newLineNode (lb));
1669 lhead = cl = newLineNode (lb);
1670 cl->isComment = pl->isComment;
1673 /* add the comments if any to the head of list */
1676 lineNode *lc = comment;
1685 /* determine which iCodes the replacment lines relate to */
1686 reassociate_ic(*shead,stail,lhead,cl);
1688 /* now we need to connect / replace the original chain */
1689 /* if there is a prev then change it */
1692 (*shead)->prev->next = lhead;
1693 lhead->prev = (*shead)->prev;
1696 /* now for the tail */
1697 if (stail && stail->next)
1699 stail->next->prev = cl;
1701 cl->next = stail->next;
1705 /* Returns TRUE if this line is a label definition.
1707 * If so, start will point to the start of the label name,
1708 * and len will be it's length.
1711 isLabelDefinition (const char *line, const char **start, int *len)
1713 const char *cp = line;
1715 /* This line is a label if if consists of:
1716 * [optional whitespace] followed by identifier chars
1717 * (alnum | $ | _ ) followed by a colon.
1720 while (*cp && isspace (*cp))
1732 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1737 if ((cp == *start) || (*cp != ':'))
1742 *len = (cp - (*start));
1746 /* Quick & dirty string hash function. */
1748 hashSymbolName (const char *name)
1754 hash = (hash << 6) ^ *name;
1763 return hash % HTAB_SIZE;
1766 /* Build a hash of all labels in the passed set of lines
1767 * and how many times they are referenced.
1770 buildLabelRefCountHash (lineNode * head)
1777 assert (labelHash == NULL);
1778 labelHash = newHashTable (HTAB_SIZE);
1780 /* First pass: locate all the labels. */
1785 if (isLabelDefinition (line->line, &label, &labelLen)
1786 && labelLen <= SDCC_NAME_MAX)
1788 labelHashEntry *entry;
1790 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1792 memcpy (entry->name, label, labelLen);
1793 entry->name[labelLen] = 0;
1794 entry->refCount = -1;
1796 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1802 /* Second pass: for each line, note all the referenced labels. */
1803 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1807 for (i = 0; i < HTAB_SIZE; i++)
1809 labelHashEntry *thisEntry;
1811 thisEntry = hTabFirstItemWK (labelHash, i);
1815 if (strstr (line->line, thisEntry->name))
1817 thisEntry->refCount++;
1819 thisEntry = hTabNextItemWK (labelHash);
1826 /* Spew the contents of the table. Debugging fun only. */
1827 for (i = 0; i < HTAB_SIZE; i++)
1829 labelHashEntry *thisEntry;
1831 thisEntry = hTabFirstItemWK (labelHash, i);
1835 fprintf (stderr, "label: %s ref %d\n",
1836 thisEntry->name, thisEntry->refCount);
1837 thisEntry = hTabNextItemWK (labelHash);
1843 /* How does this work?
1849 replace and restart.
1854 Where is stuff allocated?
1858 /*-----------------------------------------------------------------*/
1859 /* peepHole - matches & substitutes rules */
1860 /*-----------------------------------------------------------------*/
1862 peepHole (lineNode ** pls)
1866 lineNode *mtail = NULL;
1869 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1870 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1871 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1875 assert(labelHash == NULL);
1882 for (pr = rootRules; pr; pr = pr->next)
1884 for (spl = *pls; spl; spl = spl->next)
1886 /* if inline assembler then no peep hole */
1890 /* don't waste time starting a match on debug symbol
1892 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1897 /* Tidy up any data stored in the hTab */
1900 if (matchRule (spl, &mtail, pr, *pls))
1905 replaceRule (pls, mtail, pr);
1907 replaceRule (&spl, mtail, pr);
1909 /* if restart rule type then
1910 start at the top again */
1919 hTabDeleteAll (pr->vars);
1920 Safe_free (pr->vars);
1924 freeTrace (&_G.values);
1927 } while (restart == TRUE);
1931 hTabDeleteAll (labelHash);
1932 freeTrace (&_G.labels);
1938 /*-----------------------------------------------------------------*/
1939 /* readFileIntoBuffer - reads a file into a string buffer */
1940 /*-----------------------------------------------------------------*/
1942 readFileIntoBuffer (char *fname)
1948 char lb[MAX_PATTERN_LEN];
1950 if (!(f = fopen (fname, "r")))
1952 fprintf (stderr, "cannot open peep rule file\n");
1956 while ((ch = fgetc (f)) != EOF)
1960 /* if we maxed out our local buffer */
1961 if (nch >= (MAX_PATTERN_LEN - 2))
1964 /* copy it into allocated buffer */
1967 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1968 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1972 rs = Safe_strdup (lb);
1978 /* if some charaters left over */
1982 /* copy it into allocated buffer */
1985 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1986 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1990 rs = Safe_strdup (lb);
1996 /*-----------------------------------------------------------------*/
1997 /* initPeepHole - initialises the peep hole optimizer stuff */
1998 /*-----------------------------------------------------------------*/
2004 /* read in the default rules */
2005 readRules (port->peep.default_rules);
2007 /* if we have any additional file read it too */
2008 if (options.peep_file)
2010 readRules (s = readFileIntoBuffer (options.peep_file));
2011 setToNull ((void **) &s);
2015 #if !OPT_DISABLE_PIC
2016 /* Convert the peep rules into pcode.
2017 NOTE: this is only support in the PIC port (at the moment)
2020 peepRules2pCode(rootRules);
2023 #if !OPT_DISABLE_PIC16
2024 /* Convert the peep rules into pcode.
2025 NOTE: this is only support in the PIC port (at the moment)
2026 and the PIC16 port (VR 030601)
2028 if (TARGET_IS_PIC16)
2029 pic16_peepRules2pCode(rootRules);