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))
707 op = IC_LEFT (cl->ic);
708 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
709 return !op->isvolatile;
710 op = IC_RIGHT (cl->ic);
711 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
712 return !op->isvolatile;
713 op = IC_RESULT (cl->ic);
714 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
715 return !op->isvolatile;
719 /* Couldn't find the symbol for some reason. Assume volatile. */
725 * This rule restriction has two different behaviours depending on
726 * the number of parameters given.
728 * if notVolatile (no parameters given)
729 * The rule is applied only if none of the iCodes originating
730 * the matched pattern reference a volatile operand.
732 * if notVolatile %1 ... (one or more parameters given)
733 * The rule is applied if the parameters are not expressions
734 * containing volatile symbols and are not pointer accesses.
737 FBYNAME (notVolatile)
748 /* If no parameters given, just scan the iCodes for volatile operands */
749 for (cl = currPl; cl!=endPl->next; cl = cl->next)
753 op = IC_LEFT (cl->ic);
754 if (IS_SYMOP (op) && op->isvolatile)
756 op = IC_RIGHT (cl->ic);
757 if (IS_SYMOP (op) && op->isvolatile)
759 op = IC_RESULT (cl->ic);
760 if (IS_SYMOP (op) && op->isvolatile)
767 /* There were parameters; check the volatility of each */
768 while (*cmdLine && isspace(*cmdLine))
775 if (!isdigit(*cmdLine))
777 varNumber = strtol(cmdLine, &digitend, 10);
779 while (*cmdLine && isspace(*cmdLine))
782 var = hTabItemWithKey (vars, varNumber);
786 notvol = notVolatileVariable (var, currPl, endPl);
792 fprintf (stderr, "*** internal error: var %d not bound"
793 " in peephole notVolatile rule.\n",
804 "*** internal error: notVolatile peephole restriction"
805 " malformed: %s\n", cmdLine);
810 /*-----------------------------------------------------------------*/
811 /* callFuncByName - calls a function as defined in the table */
812 /*-----------------------------------------------------------------*/
814 callFuncByName (char *fname,
823 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
828 "labelInRange", labelInRange
832 "operandsNotSame", operandsNotSame
836 "operandsNotSame3", operandsNotSame3
840 "operandsNotSame4", operandsNotSame4
844 "operandsNotSame5", operandsNotSame5
848 "operandsNotSame6", operandsNotSame6
852 "operandsNotSame7", operandsNotSame7
856 "operandsNotSame8", operandsNotSame8
860 "24bitMode", flat24bitMode
864 "xramMovcOption", xramMovcOption
868 "labelRefCount", labelRefCount
872 "portIsDS390", portIsDS390
875 "labelIsReturnOnly", labelIsReturnOnly
878 "okToRemoveSLOC", okToRemoveSLOC
881 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
884 "notVolatile", notVolatile
888 char *cmdCopy, *funcName, *funcArgs;
891 /* Isolate the function name part (we are passed the full condition
892 * string including arguments)
894 cmdCopy = Safe_strdup(fname);
895 funcName = strtok(cmdCopy, " \t");
896 funcArgs = strtok(NULL, "");
898 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
900 if (strcmp (ftab[i].fname, funcName) == 0)
902 rc = (*ftab[i].func) (vars, currPl, endPl, head,
910 "could not find named function \"%s\" in "
911 "peephole function table\n",
913 // If the function couldn't be found, let's assume it's
914 // a bad rule and refuse it.
923 /*-----------------------------------------------------------------*/
924 /* printLine - prints a line chain into a given file */
925 /*-----------------------------------------------------------------*/
927 printLine (lineNode * head, FILE * of)
929 iCode *last_ic = NULL;
930 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
937 if (head->ic!=last_ic)
940 if (debug_iCode_tracking)
943 fprintf (of, "; block = %d, seq = %d\n",
944 head->ic->block, head->ic->seq);
946 fprintf (of, "; iCode lost\n");
950 /* don't indent comments & labels */
952 (*head->line == ';' ||
953 head->line[strlen (head->line) - 1] == ':')) {
954 fprintf (of, "%s\n", head->line);
956 if (head->isInline && *head->line=='#') {
957 // comment out preprocessor directives in inline asm
960 fprintf (of, "\t%s\n", head->line);
966 /*-----------------------------------------------------------------*/
967 /* newPeepRule - creates a new peeprule and attach it to the root */
968 /*-----------------------------------------------------------------*/
970 newPeepRule (lineNode * match,
977 pr = Safe_alloc ( sizeof (peepRule));
979 pr->replace = replace;
980 pr->restart = restart;
984 pr->cond = Safe_strdup (cond);
989 pr->vars = newHashTable (100);
991 /* if root is empty */
993 rootRules = currRule = pr;
995 currRule = currRule->next = pr;
1000 /*-----------------------------------------------------------------*/
1001 /* newLineNode - creates a new peep line */
1002 /*-----------------------------------------------------------------*/
1004 newLineNode (char *line)
1008 pl = Safe_alloc ( sizeof (lineNode));
1009 pl->line = Safe_strdup (line);
1014 /*-----------------------------------------------------------------*/
1015 /* connectLine - connects two lines */
1016 /*-----------------------------------------------------------------*/
1018 connectLine (lineNode * pl1, lineNode * pl2)
1022 fprintf (stderr, "trying to connect null line\n");
1032 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1033 if (!*x) { fprintf(stderr,y); return ; } }
1035 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1036 if (!*x) { fprintf(stderr,z); return ; } }
1037 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1038 if (!*x) { fprintf(stderr,z); return ; } }
1040 /*-----------------------------------------------------------------*/
1041 /* getPeepLine - parses the peep lines */
1042 /*-----------------------------------------------------------------*/
1044 getPeepLine (lineNode ** head, char **bpp)
1046 char lines[MAX_PATTERN_LEN];
1049 lineNode *currL = NULL;
1056 fprintf (stderr, "unexpected end of match pattern\n");
1063 while (isspace (*bp) ||
1074 /* read till end of line */
1076 while ((*bp != '\n' && *bp != '}') && *bp)
1081 *head = currL = newLineNode (lines);
1083 currL = connectLine (currL, newLineNode (lines));
1086 while (*lp && isspace(*lp))
1089 currL->isComment = 1;
1095 /*-----------------------------------------------------------------*/
1096 /* readRules - reads the rules from a string buffer */
1097 /*-----------------------------------------------------------------*/
1099 readRules (char *bp)
1102 char lines[MAX_PATTERN_LEN];
1106 lineNode *currL = NULL;
1112 /* look for the token "replace" that is the
1114 while (*bp && strncmp (bp, "replace", 7))
1121 /* then look for either "restart" or '{' */
1122 while (strncmp (bp, "restart", 7) &&
1129 fprintf (stderr, "expected 'restart' or '{'\n");
1137 { /* must be restart */
1139 bp += strlen ("restart");
1141 EXPECT_CHR (bp, '{', "expected '{'\n");
1145 /* skip thru all the blank space */
1146 SKIP_SPACE (bp, "unexpected end of rule\n");
1148 match = replace = currL = NULL;
1149 /* we are the start of a rule */
1150 getPeepLine (&match, &bp);
1152 /* now look for by */
1153 EXPECT_STR (bp, "by", "expected 'by'\n");
1155 /* then look for a '{' */
1156 EXPECT_CHR (bp, '{', "expected '{'\n");
1159 SKIP_SPACE (bp, "unexpected end of rule\n");
1160 getPeepLine (&replace, &bp);
1162 /* look for a 'if' */
1163 while ((isspace (*bp) || *bp == '\n') && *bp)
1166 if (strncmp (bp, "if", 2) == 0)
1169 while ((isspace (*bp) || *bp == '\n') && *bp)
1173 fprintf (stderr, "expected condition name\n");
1177 /* look for the condition */
1179 while (*bp && (*bp != '\n'))
1185 newPeepRule (match, replace, lines, restart);
1188 newPeepRule (match, replace, NULL, restart);
1193 /*-----------------------------------------------------------------*/
1194 /* keyForVar - returns the numeric key for a var */
1195 /*-----------------------------------------------------------------*/
1201 while (isdigit (*d))
1210 /*-----------------------------------------------------------------*/
1211 /* bindVar - binds a value to a variable in the given hashtable */
1212 /*-----------------------------------------------------------------*/
1214 bindVar (int key, char **s, hTab ** vtab)
1216 char vval[MAX_PATTERN_LEN];
1220 /* first get the value of the variable */
1222 /* the value is ended by a ',' or space or newline or null or ) */
1231 /* if we find a '(' then we need to balance it */
1243 // include the trailing ')'
1252 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1254 hTabAddItem (vtab, key, vvx);
1257 /*-----------------------------------------------------------------*/
1258 /* matchLine - matches one line */
1259 /*-----------------------------------------------------------------*/
1261 matchLine (char *s, char *d, hTab ** vars)
1270 /* skip white space in both */
1271 while (isspace (*s))
1273 while (isspace (*d))
1276 /* if the destination is a var */
1277 if (*d == '%' && isdigit (*(d + 1)) && vars)
1279 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1280 /* if the variable is already bound
1281 then it MUST match with dest */
1289 /* variable not bound we need to
1291 bindVar (keyForVar (d + 1), &s, vars);
1293 /* in either case go past the variable */
1295 while (isdigit (*d))
1298 while (isspace (*s))
1300 while (isspace (*d))
1304 /* they should be an exact match other wise */
1313 /* get rid of the trailing spaces
1314 in both source & destination */
1316 while (isspace (*s))
1320 while (isspace (*d))
1323 /* after all this if only one of them
1324 has something left over then no match */
1331 /*-----------------------------------------------------------------*/
1332 /* matchRule - matches a all the rule lines */
1333 /*-----------------------------------------------------------------*/
1335 matchRule (lineNode * pl,
1340 lineNode *spl; /* source pl */
1341 lineNode *rpl; /* rule peep line */
1343 /* setToNull((void **) &pr->vars); */
1344 /* pr->vars = newHashTable(100); */
1346 /* for all the lines defined in the rule */
1352 /* if the source line starts with a ';' then
1353 comment line don't process or the source line
1354 contains == . debugger information skip it */
1356 (*spl->line == ';' || spl->isDebug))
1362 if (!matchLine (spl->line, rpl->line, &pr->vars))
1370 /* if rules ended */
1373 /* if this rule has additional conditions */
1376 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1395 reassociate_ic_down (lineNode *shead, lineNode *stail,
1396 lineNode *rhead, lineNode *rtail)
1398 lineNode *csl; /* current source line */
1399 lineNode *crl; /* current replacement line */
1405 /* skip over any comments */
1406 while (csl!=stail->next && csl->isComment)
1408 while (crl!=rtail->next && crl->isComment)
1411 /* quit if we reach the end */
1412 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1415 if (matchLine(csl->line,crl->line,NULL))
1427 reassociate_ic_up (lineNode *shead, lineNode *stail,
1428 lineNode *rhead, lineNode *rtail)
1430 lineNode *csl; /* current source line */
1431 lineNode *crl; /* current replacement line */
1437 /* skip over any comments */
1438 while (csl!=shead->prev && csl->isComment)
1440 while (crl!=rhead->prev && crl->isComment)
1443 /* quit if we reach the end */
1444 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1447 if (matchLine(csl->line,crl->line,NULL))
1458 /*------------------------------------------------------------------*/
1459 /* reassociate_ic - reassociate replacement lines with origin iCode */
1460 /*------------------------------------------------------------------*/
1462 reassociate_ic (lineNode *shead, lineNode *stail,
1463 lineNode *rhead, lineNode *rtail)
1465 lineNode *csl; /* current source line */
1466 lineNode *crl; /* current replacement line */
1470 /* Check to see if all the source lines (excluding comments) came
1471 ** for the same iCode
1474 for (csl=shead;csl!=stail->next;csl=csl->next)
1475 if (csl->ic && !csl->isComment)
1480 single_iCode = (ic!=NULL);
1481 for (csl=shead;csl!=stail->next;csl=csl->next)
1482 if ((csl->ic != ic) && !csl->isComment)
1484 /* More than one iCode was found. However, if it's just the
1485 ** last line with the different iCode and it was not changed
1486 ** in the replacement, everything else must be the first iCode.
1488 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1490 rtail->ic = stail->ic;
1491 for (crl=rhead;crl!=rtail;crl=crl->next)
1496 single_iCode = FALSE;
1500 /* If all of the source lines came from the same iCode, then so have
1501 ** all of the replacement lines too.
1505 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1510 /* The source lines span iCodes, so we may end up with replacement
1511 ** lines that we don't know which iCode(s) to associate with. Do the
1512 ** best we can by using the following strategies:
1513 ** 1) Start at the top and scan down. As long as the source line
1514 ** matches the replacement line, they have the same iCode.
1515 ** 2) Start at the bottom and scan up. As long as the source line
1516 ** matches the replacement line, they have the same iCode.
1517 ** 3) For any label in the source, look for a matching label in
1518 ** the replacment. If found, they have the same iCode. From
1519 ** these matching labels, scan down for additional matching
1520 ** lines; if found, they also have the same iCode.
1523 /* Strategy #1: Start at the top and scan down for matches
1525 reassociate_ic_down(shead,stail,rhead,rtail);
1527 /* Strategy #2: Start at the bottom and scan up for matches
1529 reassociate_ic_up(shead,stail,rhead,rtail);
1531 /* Strategy #3: Try to match labels
1536 const char *labelStart;
1539 /* skip over any comments */
1540 while (csl!=stail->next && csl->isComment)
1542 if (csl==stail->next)
1545 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1547 /* found a source line label; look for it in the replacment lines */
1551 while (crl!=rtail->next && crl->isComment)
1553 if (crl==rtail->next)
1555 if (matchLine(csl->line, crl->line, NULL))
1557 reassociate_ic_down(csl,stail,crl,rtail);
1567 /* Try to assign a meaningful iCode to any comment that is missing
1568 one. Since they are comments, it's ok to make mistakes; we are just
1569 trying to improve continuity to simplify other tests.
1572 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1574 if (!crl->ic && ic && crl->isComment)
1581 /*-----------------------------------------------------------------*/
1582 /* replaceRule - does replacement of a matching pattern */
1583 /*-----------------------------------------------------------------*/
1585 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1587 lineNode *cl = NULL;
1588 lineNode *pl = NULL, *lhead = NULL;
1589 /* a long function name and long variable name can evaluate to
1590 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1591 char lb[MAX_PATTERN_LEN*4];
1593 lineNode *comment = NULL;
1595 /* collect all the comment lines in the source */
1596 for (cl = *shead; cl != stail; cl = cl->next)
1598 if (cl->line && (*cl->line == ';' || cl->isDebug))
1600 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1601 (comment = newLineNode (cl->line)));
1602 pl->isDebug = cl->isDebug;
1603 pl->isComment = cl->isComment || (*cl->line == ';');
1608 /* for all the lines in the replacement pattern do */
1609 for (pl = pr->replace; pl; pl = pl->next)
1619 /* if the line contains a variable */
1620 if (*l == '%' && isdigit (*(l + 1)))
1622 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1625 fprintf (stderr, "used unbound variable in replacement\n");
1633 while (isdigit (*l)) {
1643 cl = connectLine (cl, newLineNode (lb));
1645 lhead = cl = newLineNode (lb);
1646 cl->isComment = pl->isComment;
1649 /* add the comments if any to the head of list */
1652 lineNode *lc = comment;
1661 /* determine which iCodes the replacment lines relate to */
1662 reassociate_ic(*shead,stail,lhead,cl);
1664 /* now we need to connect / replace the original chain */
1665 /* if there is a prev then change it */
1668 (*shead)->prev->next = lhead;
1669 lhead->prev = (*shead)->prev;
1672 /* now for the tail */
1673 if (stail && stail->next)
1675 stail->next->prev = cl;
1677 cl->next = stail->next;
1681 /* Returns TRUE if this line is a label definition.
1683 * If so, start will point to the start of the label name,
1684 * and len will be it's length.
1687 isLabelDefinition (const char *line, const char **start, int *len)
1689 const char *cp = line;
1691 /* This line is a label if if consists of:
1692 * [optional whitespace] followed by identifier chars
1693 * (alnum | $ | _ ) followed by a colon.
1696 while (*cp && isspace (*cp))
1708 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1713 if ((cp == *start) || (*cp != ':'))
1718 *len = (cp - (*start));
1722 /* Quick & dirty string hash function. */
1724 hashSymbolName (const char *name)
1730 hash = (hash << 6) ^ *name;
1739 return hash % HTAB_SIZE;
1742 /* Build a hash of all labels in the passed set of lines
1743 * and how many times they are referenced.
1746 buildLabelRefCountHash (lineNode * head)
1753 assert (labelHash == NULL);
1754 labelHash = newHashTable (HTAB_SIZE);
1756 /* First pass: locate all the labels. */
1761 if (isLabelDefinition (line->line, &label, &labelLen)
1762 && labelLen <= SDCC_NAME_MAX)
1764 labelHashEntry *entry;
1766 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1768 memcpy (entry->name, label, labelLen);
1769 entry->name[labelLen] = 0;
1770 entry->refCount = -1;
1772 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1778 /* Second pass: for each line, note all the referenced labels. */
1779 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1783 for (i = 0; i < HTAB_SIZE; i++)
1785 labelHashEntry *thisEntry;
1787 thisEntry = hTabFirstItemWK (labelHash, i);
1791 if (strstr (line->line, thisEntry->name))
1793 thisEntry->refCount++;
1795 thisEntry = hTabNextItemWK (labelHash);
1802 /* Spew the contents of the table. Debugging fun only. */
1803 for (i = 0; i < HTAB_SIZE; i++)
1805 labelHashEntry *thisEntry;
1807 thisEntry = hTabFirstItemWK (labelHash, i);
1811 fprintf (stderr, "label: %s ref %d\n",
1812 thisEntry->name, thisEntry->refCount);
1813 thisEntry = hTabNextItemWK (labelHash);
1819 /* How does this work?
1825 replace and restart.
1830 Where is stuff allocated?
1834 /*-----------------------------------------------------------------*/
1835 /* peepHole - matches & substitutes rules */
1836 /*-----------------------------------------------------------------*/
1838 peepHole (lineNode ** pls)
1842 lineNode *mtail = NULL;
1845 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1846 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1847 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1851 assert(labelHash == NULL);
1858 for (pr = rootRules; pr; pr = pr->next)
1860 for (spl = *pls; spl; spl = spl->next)
1862 /* if inline assembler then no peep hole */
1866 /* don't waste time starting a match on debug symbol
1868 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1873 /* Tidy up any data stored in the hTab */
1876 if (matchRule (spl, &mtail, pr, *pls))
1881 replaceRule (pls, mtail, pr);
1883 replaceRule (&spl, mtail, pr);
1885 /* if restart rule type then
1886 start at the top again */
1895 hTabDeleteAll (pr->vars);
1896 Safe_free (pr->vars);
1900 freeTrace (&_G.values);
1903 } while (restart == TRUE);
1907 hTabDeleteAll (labelHash);
1908 freeTrace (&_G.labels);
1914 /*-----------------------------------------------------------------*/
1915 /* readFileIntoBuffer - reads a file into a string buffer */
1916 /*-----------------------------------------------------------------*/
1918 readFileIntoBuffer (char *fname)
1924 char lb[MAX_PATTERN_LEN];
1926 if (!(f = fopen (fname, "r")))
1928 fprintf (stderr, "cannot open peep rule file\n");
1932 while ((ch = fgetc (f)) != EOF)
1936 /* if we maxed out our local buffer */
1937 if (nch >= (MAX_PATTERN_LEN - 2))
1940 /* copy it into allocated buffer */
1943 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1944 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1948 rs = Safe_strdup (lb);
1954 /* if some charaters left over */
1958 /* copy it into allocated buffer */
1961 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1962 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1966 rs = Safe_strdup (lb);
1972 /*-----------------------------------------------------------------*/
1973 /* initPeepHole - initialises the peep hole optimizer stuff */
1974 /*-----------------------------------------------------------------*/
1980 /* read in the default rules */
1981 readRules (port->peep.default_rules);
1983 /* if we have any additional file read it too */
1984 if (options.peep_file)
1986 readRules (s = readFileIntoBuffer (options.peep_file));
1987 setToNull ((void **) &s);
1991 #if !OPT_DISABLE_PIC
1992 /* Convert the peep rules into pcode.
1993 NOTE: this is only support in the PIC port (at the moment)
1996 peepRules2pCode(rootRules);
1999 #if !OPT_DISABLE_PIC16
2000 /* Convert the peep rules into pcode.
2001 NOTE: this is only support in the PIC port (at the moment)
2002 and the PIC16 port (VR 030601)
2004 if (TARGET_IS_PIC16)
2005 pic16_peepRules2pCode(rootRules);