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)
77 if (ISINST("lcall")) return 3;
78 if (ISINST("ret")) return 1;
79 if (ISINST("ljmp")) return 3;
80 if (ISINST("sjmp")) return 2;
81 if (ISINST("rlc")) return 1;
82 if (ISINST("rrc")) return 1;
83 if (ISINST("rl")) return 1;
84 if (ISINST("rr")) return 1;
85 if (ISINST("swap")) return 1;
86 if (ISINST("movx")) return 1;
87 if (ISINST("movc")) return 1;
88 if (ISINST("push")) return 2;
89 if (ISINST("pop")) return 2;
90 if (ISINST("jc")) return 2;
91 if (ISINST("jnc")) return 2;
92 if (ISINST("jb")) return 3;
93 if (ISINST("jnb")) return 3;
94 if (ISINST("jbc")) return 3;
95 if (ISINST("jmp")) return 1; // always jmp @a+dptr
96 if (ISINST("jz")) return 2;
97 if (ISINST("jnz")) return 2;
98 if (ISINST("cjne")) return 3;
99 if (ISINST("mul")) return 1;
100 if (ISINST("div")) return 1;
101 if (ISINST("da")) return 1;
102 if (ISINST("xchd")) return 1;
103 if (ISINST("reti")) return 1;
104 if (ISINST("nop")) return 1;
105 if (ISINST("acall")) return 1;
106 if (ISINST("ajmp")) return 2;
109 while (*p && isalnum(*p)) p++;
110 for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
111 if (!isspace(*p)) *op++ = *p, opsize++;
115 for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
116 if (!isspace(*p)) *op++ = *p, opsize++;
120 #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
121 #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
122 #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
123 #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
126 if (IS_C(op1) || IS_C(op2)) return 2;
128 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
131 if (IS_Rn(op1) || IS_atRi(op1)) {
132 if (IS_A(op2)) return 1;
135 if (strcmp(op1, "dptr") == 0) return 3;
136 if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
139 if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
140 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
143 if (ISINST("inc") || ISINST("dec")) {
144 if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
145 if (strcmp(op1, "dptr") == 0) return 1;
148 if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
149 if (IS_C(op1)) return 2;
151 if (IS_Rn(op2) || IS_atRi(op2)) return 1;
154 if (IS_A(op2)) return 2;
158 if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
159 if (IS_A(op1) || IS_C(op1)) return 1;
162 if (ISINST("djnz")) {
163 if (IS_Rn(op1)) return 2;
167 if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
168 /* ignore ar0 = 0x00 type definitions */
172 fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
177 pcDistance (lineNode * cpos, char *lbl, bool back)
180 char buff[MAX_PATTERN_LEN];
183 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
189 pl->line[strlen (pl->line) - 1] != ':' &&
191 if (strcmp(port->target,"mcs51") == 0) {
192 dist += mcs51_instruction_size(pl->line);
198 if (strncmp (pl->line, buff, strlen (buff)) == 0)
210 /*-----------------------------------------------------------------*/
211 /* flat24bitModeAndPortDS390 - */
212 /*-----------------------------------------------------------------*/
213 FBYNAME (flat24bitModeAndPortDS390)
215 return (((strcmp(port->target,"ds390") == 0) ||
216 (strcmp(port->target,"ds400") == 0)) &&
217 (options.model == MODEL_FLAT24));
220 /*-----------------------------------------------------------------*/
221 /* portIsDS390 - return true if port is DS390 */
222 /*-----------------------------------------------------------------*/
223 FBYNAME (portIsDS390)
225 return ((strcmp(port->target,"ds390") == 0) ||
226 (strcmp(port->target,"ds400") == 0));
229 /*-----------------------------------------------------------------*/
230 /* flat24bitMode - will check to see if we are in flat24 mode */
231 /*-----------------------------------------------------------------*/
232 FBYNAME (flat24bitMode)
234 return (options.model == MODEL_FLAT24);
237 /*-----------------------------------------------------------------*/
238 /* xramMovcOption - check if using movc to read xram */
239 /*-----------------------------------------------------------------*/
240 FBYNAME (xramMovcOption)
242 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
250 /*-----------------------------------------------------------------*/
251 /* labelInRange - will check to see if label %5 is within range */
252 /*-----------------------------------------------------------------*/
253 FBYNAME (labelInRange)
255 /* assumes that %5 pattern variable has the label name */
256 char *lbl = hTabItemWithKey (vars, 5);
262 /* if the previous two instructions are "ljmp"s then don't
263 do it since it can be part of a jump table */
264 if (currPl->prev && currPl->prev->prev &&
265 strstr (currPl->prev->line, "ljmp") &&
266 strstr (currPl->prev->prev->line, "ljmp"))
269 /* calculate the label distance : the jump for reladdr can be
270 +/- 127 bytes, here Iam assuming that an average 8051
271 instruction is 2 bytes long, so if the label is more than
272 63 intructions away, the label is considered out of range
273 for a relative jump. we could get more precise this will
274 suffice for now since it catches > 90% cases */
275 dist = (pcDistance (currPl, lbl, TRUE) +
276 pcDistance (currPl, lbl, FALSE));
278 /* changed to 127, now that pcDistance return actual number of bytes */
279 if (!dist || dist > 127)
285 /*-----------------------------------------------------------------*/
286 /* labelIsReturnOnly - Check if label %5 is followed by RET */
287 /*-----------------------------------------------------------------*/
288 FBYNAME (labelIsReturnOnly)
290 /* assumes that %5 pattern variable has the label name */
291 const char *label, *p;
295 label = hTabItemWithKey (vars, 5);
296 if (!label) return FALSE;
299 for(pl = currPl; pl; pl = pl->next) {
300 if (pl->line && !pl->isDebug &&
301 pl->line[strlen(pl->line)-1] == ':') {
302 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
303 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
304 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
305 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
306 *(pl->line+5) != '$') {
307 return FALSE; /* non-local label encountered */
311 if (!pl) return FALSE; /* did not find the label */
313 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
315 for (p = pl->line; *p && isspace(*p); p++)
317 if (strcmp(p, "ret") == 0) return TRUE;
322 /*-----------------------------------------------------------------*/
323 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
324 /* usage of it in the code depends on a value from this section */
325 /*-----------------------------------------------------------------*/
326 FBYNAME (okToRemoveSLOC)
329 const char *sloc, *p;
330 int dummy1, dummy2, dummy3;
332 /* assumes that %1 as the SLOC name */
333 sloc = hTabItemWithKey (vars, 1);
334 if (sloc == NULL) return FALSE;
335 p = strstr(sloc, "sloc");
336 if (p == NULL) return FALSE;
338 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
339 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
340 /* the sloc name begins with that. Probably not really necessary */
342 /* Look for any occurance of this SLOC before the peephole match */
343 for (pl = currPl->prev; pl; pl = pl->prev) {
344 if (pl->line && !pl->isDebug && !pl->isComment
345 && *pl->line != ';' && strstr(pl->line, sloc))
348 /* Look for any occurance of this SLOC after the peephole match */
349 for (pl = endPl->next; pl; pl = pl->next) {
350 if (pl->line && !pl->isDebug && !pl->isComment
351 && *pl->line != ';' && strstr(pl->line, sloc))
354 return TRUE; /* safe for a peephole to remove it :) */
358 /*-----------------------------------------------------------------*/
359 /* operandsNotSame - check if %1 & %2 are the same */
360 /*-----------------------------------------------------------------*/
361 FBYNAME (operandsNotSame)
363 char *op1 = hTabItemWithKey (vars, 1);
364 char *op2 = hTabItemWithKey (vars, 2);
366 if (strcmp (op1, op2) == 0)
372 /*-----------------------------------------------------------------*/
373 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
374 /*-----------------------------------------------------------------*/
375 FBYNAME (operandsNotSame3)
377 char *op1 = hTabItemWithKey (vars, 1);
378 char *op2 = hTabItemWithKey (vars, 2);
379 char *op3 = hTabItemWithKey (vars, 3);
381 if ( (strcmp (op1, op2) == 0) ||
382 (strcmp (op1, op3) == 0) ||
383 (strcmp (op2, op3) == 0) )
389 /*-----------------------------------------------------------------*/
390 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
391 /*-----------------------------------------------------------------*/
392 FBYNAME (operandsNotSame4)
394 char *op1 = hTabItemWithKey (vars, 1);
395 char *op2 = hTabItemWithKey (vars, 2);
396 char *op3 = hTabItemWithKey (vars, 3);
397 char *op4 = hTabItemWithKey (vars, 4);
399 if ( (strcmp (op1, op2) == 0) ||
400 (strcmp (op1, op3) == 0) ||
401 (strcmp (op1, op4) == 0) ||
402 (strcmp (op2, op3) == 0) ||
403 (strcmp (op2, op4) == 0) ||
404 (strcmp (op3, op4) == 0) )
410 /*-----------------------------------------------------------------*/
411 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
412 /*-----------------------------------------------------------------*/
413 FBYNAME (operandsNotSame5)
415 char *op1 = hTabItemWithKey (vars, 1);
416 char *op2 = hTabItemWithKey (vars, 2);
417 char *op3 = hTabItemWithKey (vars, 3);
418 char *op4 = hTabItemWithKey (vars, 4);
419 char *op5 = hTabItemWithKey (vars, 5);
421 if ( (strcmp (op1, op2) == 0) ||
422 (strcmp (op1, op3) == 0) ||
423 (strcmp (op1, op4) == 0) ||
424 (strcmp (op1, op5) == 0) ||
425 (strcmp (op2, op3) == 0) ||
426 (strcmp (op2, op4) == 0) ||
427 (strcmp (op2, op5) == 0) ||
428 (strcmp (op3, op4) == 0) ||
429 (strcmp (op3, op5) == 0) ||
430 (strcmp (op4, op5) == 0) )
436 /*-----------------------------------------------------------------*/
437 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
438 /*-----------------------------------------------------------------*/
439 FBYNAME (operandsNotSame6)
441 char *op1 = hTabItemWithKey (vars, 1);
442 char *op2 = hTabItemWithKey (vars, 2);
443 char *op3 = hTabItemWithKey (vars, 3);
444 char *op4 = hTabItemWithKey (vars, 4);
445 char *op5 = hTabItemWithKey (vars, 5);
446 char *op6 = hTabItemWithKey (vars, 6);
448 if ( (strcmp (op1, op2) == 0) ||
449 (strcmp (op1, op3) == 0) ||
450 (strcmp (op1, op4) == 0) ||
451 (strcmp (op1, op5) == 0) ||
452 (strcmp (op1, op6) == 0) ||
453 (strcmp (op2, op3) == 0) ||
454 (strcmp (op2, op4) == 0) ||
455 (strcmp (op2, op5) == 0) ||
456 (strcmp (op2, op6) == 0) ||
457 (strcmp (op3, op4) == 0) ||
458 (strcmp (op3, op5) == 0) ||
459 (strcmp (op3, op6) == 0) ||
460 (strcmp (op4, op5) == 0) ||
461 (strcmp (op4, op6) == 0) ||
462 (strcmp (op5, op6) == 0) )
469 /*-----------------------------------------------------------------*/
470 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
471 /*-----------------------------------------------------------------*/
472 FBYNAME (operandsNotSame7)
474 char *op1 = hTabItemWithKey (vars, 1);
475 char *op2 = hTabItemWithKey (vars, 2);
476 char *op3 = hTabItemWithKey (vars, 3);
477 char *op4 = hTabItemWithKey (vars, 4);
478 char *op5 = hTabItemWithKey (vars, 5);
479 char *op6 = hTabItemWithKey (vars, 6);
480 char *op7 = hTabItemWithKey (vars, 7);
482 if ( (strcmp (op1, op2) == 0) ||
483 (strcmp (op1, op3) == 0) ||
484 (strcmp (op1, op4) == 0) ||
485 (strcmp (op1, op5) == 0) ||
486 (strcmp (op1, op6) == 0) ||
487 (strcmp (op1, op7) == 0) ||
488 (strcmp (op2, op3) == 0) ||
489 (strcmp (op2, op4) == 0) ||
490 (strcmp (op2, op5) == 0) ||
491 (strcmp (op2, op6) == 0) ||
492 (strcmp (op2, op7) == 0) ||
493 (strcmp (op3, op4) == 0) ||
494 (strcmp (op3, op5) == 0) ||
495 (strcmp (op3, op6) == 0) ||
496 (strcmp (op3, op7) == 0) ||
497 (strcmp (op4, op5) == 0) ||
498 (strcmp (op4, op6) == 0) ||
499 (strcmp (op4, op7) == 0) ||
500 (strcmp (op5, op6) == 0) ||
501 (strcmp (op5, op7) == 0) ||
502 (strcmp (op6, op7) == 0) )
508 /*-----------------------------------------------------------------*/
509 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
510 /*-----------------------------------------------------------------*/
511 FBYNAME (operandsNotSame8)
513 char *op1 = hTabItemWithKey (vars, 1);
514 char *op2 = hTabItemWithKey (vars, 2);
515 char *op3 = hTabItemWithKey (vars, 3);
516 char *op4 = hTabItemWithKey (vars, 4);
517 char *op5 = hTabItemWithKey (vars, 5);
518 char *op6 = hTabItemWithKey (vars, 6);
519 char *op7 = hTabItemWithKey (vars, 7);
520 char *op8 = hTabItemWithKey (vars, 8);
522 if ( (strcmp (op1, op2) == 0) ||
523 (strcmp (op1, op3) == 0) ||
524 (strcmp (op1, op4) == 0) ||
525 (strcmp (op1, op5) == 0) ||
526 (strcmp (op1, op6) == 0) ||
527 (strcmp (op1, op7) == 0) ||
528 (strcmp (op1, op8) == 0) ||
529 (strcmp (op2, op3) == 0) ||
530 (strcmp (op2, op4) == 0) ||
531 (strcmp (op2, op5) == 0) ||
532 (strcmp (op2, op6) == 0) ||
533 (strcmp (op2, op7) == 0) ||
534 (strcmp (op2, op8) == 0) ||
535 (strcmp (op3, op4) == 0) ||
536 (strcmp (op3, op5) == 0) ||
537 (strcmp (op3, op6) == 0) ||
538 (strcmp (op3, op7) == 0) ||
539 (strcmp (op3, op8) == 0) ||
540 (strcmp (op4, op5) == 0) ||
541 (strcmp (op4, op6) == 0) ||
542 (strcmp (op4, op7) == 0) ||
543 (strcmp (op4, op8) == 0) ||
544 (strcmp (op5, op6) == 0) ||
545 (strcmp (op5, op7) == 0) ||
546 (strcmp (op5, op8) == 0) ||
547 (strcmp (op6, op7) == 0) ||
548 (strcmp (op6, op8) == 0) ||
549 (strcmp (op7, op8) == 0) )
558 * takes two parameters: a variable (bound to a label name)
559 * and an expected reference count.
561 * Returns TRUE if that label is defined and referenced exactly
562 * the given number of times.
564 FBYNAME (labelRefCount)
566 int varNumber, expectedRefCount;
569 /* If we don't have the label hash table yet, build it. */
572 buildLabelRefCountHash (head);
575 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
577 char *label = hTabItemWithKey (vars, varNumber);
581 labelHashEntry *entry;
583 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
587 if (!strcmp (label, entry->name))
591 entry = hTabNextItemWK (labelHash);
597 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
598 label, entry->refCount, expectedRefCount);
601 rc = (expectedRefCount == entry->refCount);
605 fprintf (stderr, "*** internal error: no label has entry for"
606 " %s in labelRefCount peephole.\n",
612 fprintf (stderr, "*** internal error: var %d not bound"
613 " in peephole labelRefCount rule.\n",
621 "*** internal error: labelRefCount peephole restriction"
622 " malformed: %s\n", cmdLine);
627 /* Within the context of the lines currPl through endPl, determine
628 ** if the variable var contains a symbol that is volatile. Returns
629 ** TRUE only if it is certain that this was not volatile (the symbol
630 ** was found and not volatile, or var was a constant or CPU register).
631 ** Returns FALSE if the symbol was found and volatile, the symbol was
632 ** not found, or var was a indirect/pointer addressing mode.
635 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
637 char symname[SDCC_NAME_MAX + 1];
644 /* Can't tell if indirect accesses are volatile or not, so
645 ** assume they are, just to be safe.
647 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
652 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
654 if (strstr(var,"(bc)"))
656 if (strstr(var,"(de)"))
658 if (strstr(var,"(hl)"))
660 if (strstr(var,"(ix"))
662 if (strstr(var,"(iy"))
666 /* Extract a symbol name from the variable */
667 while (*vp && (*vp!='_'))
669 while (*vp && (isalnum(*vp) || *vp=='_'))
675 /* Nothing resembling a symbol name was found, so it can't
682 for (cl = currPl; cl!=endPl->next; cl = cl->next)
684 if (cl->ic && (cl->ic!=last_ic))
687 op = IC_LEFT (cl->ic);
688 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
689 return !op->isvolatile;
690 op = IC_RIGHT (cl->ic);
691 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
692 return !op->isvolatile;
693 op = IC_RESULT (cl->ic);
694 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
695 return !op->isvolatile;
699 /* Couldn't find the symbol for some reason. Assume volatile. */
705 * This rule restriction has two different behaviours depending on
706 * the number of parameters given.
708 * if notVolatile (no parameters given)
709 * The rule is applied only if none of the iCodes originating
710 * the matched pattern reference a volatile operand.
712 * if notVolatile %1 ... (one or more parameters given)
713 * The rule is applied if the parameters are not expressions
714 * containing volatile symbols and are not pointer accesses.
717 FBYNAME (notVolatile)
728 /* If no parameters given, just scan the iCodes for volatile operands */
729 for (cl = currPl; cl!=endPl->next; cl = cl->next)
733 op = IC_LEFT (cl->ic);
734 if (IS_SYMOP (op) && op->isvolatile)
736 op = IC_RIGHT (cl->ic);
737 if (IS_SYMOP (op) && op->isvolatile)
739 op = IC_RESULT (cl->ic);
740 if (IS_SYMOP (op) && op->isvolatile)
747 /* There were parameters; check the volatility of each */
748 while (*cmdLine && isspace(*cmdLine))
755 if (!isdigit(*cmdLine))
757 varNumber = strtol(cmdLine, &digitend, 10);
759 while (*cmdLine && isspace(*cmdLine))
762 var = hTabItemWithKey (vars, varNumber);
766 notvol = notVolatileVariable (var, currPl, endPl);
772 fprintf (stderr, "*** internal error: var %d not bound"
773 " in peephole notVolatile rule.\n",
784 "*** internal error: notVolatile peephole restriction"
785 " malformed: %s\n", cmdLine);
790 /*-----------------------------------------------------------------*/
791 /* callFuncByName - calls a function as defined in the table */
792 /*-----------------------------------------------------------------*/
794 callFuncByName (char *fname,
803 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
808 "labelInRange", labelInRange
812 "operandsNotSame", operandsNotSame
816 "operandsNotSame3", operandsNotSame3
820 "operandsNotSame4", operandsNotSame4
824 "operandsNotSame5", operandsNotSame5
828 "operandsNotSame6", operandsNotSame6
832 "operandsNotSame7", operandsNotSame7
836 "operandsNotSame8", operandsNotSame8
840 "24bitMode", flat24bitMode
844 "xramMovcOption", xramMovcOption
848 "labelRefCount", labelRefCount
852 "portIsDS390", portIsDS390
855 "labelIsReturnOnly", labelIsReturnOnly
858 "okToRemoveSLOC", okToRemoveSLOC
861 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
864 "notVolatile", notVolatile
868 char *cmdCopy, *funcName, *funcArgs;
871 /* Isolate the function name part (we are passed the full condition
872 * string including arguments)
874 cmdCopy = Safe_strdup(fname);
875 funcName = strtok(cmdCopy, " \t");
876 funcArgs = strtok(NULL, "");
878 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
880 if (strcmp (ftab[i].fname, funcName) == 0)
882 rc = (*ftab[i].func) (vars, currPl, endPl, head,
890 "could not find named function \"%s\" in "
891 "peephole function table\n",
893 // If the function couldn't be found, let's assume it's
894 // a bad rule and refuse it.
903 /*-----------------------------------------------------------------*/
904 /* printLine - prints a line chain into a given file */
905 /*-----------------------------------------------------------------*/
907 printLine (lineNode * head, FILE * of)
909 iCode *last_ic = NULL;
910 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
917 if (head->ic!=last_ic)
920 if (debug_iCode_tracking)
923 fprintf (of, "; block = %d, seq = %d\n",
924 head->ic->block, head->ic->seq);
926 fprintf (of, "; iCode lost\n");
930 /* don't indent comments & labels */
932 (*head->line == ';' ||
933 head->line[strlen (head->line) - 1] == ':')) {
934 fprintf (of, "%s\n", head->line);
936 if (head->isInline && *head->line=='#') {
937 // comment out preprocessor directives in inline asm
940 fprintf (of, "\t%s\n", head->line);
946 /*-----------------------------------------------------------------*/
947 /* newPeepRule - creates a new peeprule and attach it to the root */
948 /*-----------------------------------------------------------------*/
950 newPeepRule (lineNode * match,
957 pr = Safe_alloc ( sizeof (peepRule));
959 pr->replace = replace;
960 pr->restart = restart;
964 pr->cond = Safe_strdup (cond);
969 pr->vars = newHashTable (100);
971 /* if root is empty */
973 rootRules = currRule = pr;
975 currRule = currRule->next = pr;
980 /*-----------------------------------------------------------------*/
981 /* newLineNode - creates a new peep line */
982 /*-----------------------------------------------------------------*/
984 newLineNode (char *line)
988 pl = Safe_alloc ( sizeof (lineNode));
989 pl->line = Safe_strdup (line);
994 /*-----------------------------------------------------------------*/
995 /* connectLine - connects two lines */
996 /*-----------------------------------------------------------------*/
998 connectLine (lineNode * pl1, lineNode * pl2)
1002 fprintf (stderr, "trying to connect null line\n");
1012 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
1013 if (!*x) { fprintf(stderr,y); return ; } }
1015 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
1016 if (!*x) { fprintf(stderr,z); return ; } }
1017 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
1018 if (!*x) { fprintf(stderr,z); return ; } }
1020 /*-----------------------------------------------------------------*/
1021 /* getPeepLine - parses the peep lines */
1022 /*-----------------------------------------------------------------*/
1024 getPeepLine (lineNode ** head, char **bpp)
1026 char lines[MAX_PATTERN_LEN];
1029 lineNode *currL = NULL;
1036 fprintf (stderr, "unexpected end of match pattern\n");
1043 while (isspace (*bp) ||
1054 /* read till end of line */
1056 while ((*bp != '\n' && *bp != '}') && *bp)
1061 *head = currL = newLineNode (lines);
1063 currL = connectLine (currL, newLineNode (lines));
1066 while (*lp && isspace(*lp))
1069 currL->isComment = 1;
1075 /*-----------------------------------------------------------------*/
1076 /* readRules - reads the rules from a string buffer */
1077 /*-----------------------------------------------------------------*/
1079 readRules (char *bp)
1082 char lines[MAX_PATTERN_LEN];
1086 lineNode *currL = NULL;
1092 /* look for the token "replace" that is the
1094 while (*bp && strncmp (bp, "replace", 7))
1101 /* then look for either "restart" or '{' */
1102 while (strncmp (bp, "restart", 7) &&
1109 fprintf (stderr, "expected 'restart' or '{'\n");
1117 { /* must be restart */
1119 bp += strlen ("restart");
1121 EXPECT_CHR (bp, '{', "expected '{'\n");
1125 /* skip thru all the blank space */
1126 SKIP_SPACE (bp, "unexpected end of rule\n");
1128 match = replace = currL = NULL;
1129 /* we are the start of a rule */
1130 getPeepLine (&match, &bp);
1132 /* now look for by */
1133 EXPECT_STR (bp, "by", "expected 'by'\n");
1135 /* then look for a '{' */
1136 EXPECT_CHR (bp, '{', "expected '{'\n");
1139 SKIP_SPACE (bp, "unexpected end of rule\n");
1140 getPeepLine (&replace, &bp);
1142 /* look for a 'if' */
1143 while ((isspace (*bp) || *bp == '\n') && *bp)
1146 if (strncmp (bp, "if", 2) == 0)
1149 while ((isspace (*bp) || *bp == '\n') && *bp)
1153 fprintf (stderr, "expected condition name\n");
1157 /* look for the condition */
1159 while (*bp && (*bp != '\n'))
1165 newPeepRule (match, replace, lines, restart);
1168 newPeepRule (match, replace, NULL, restart);
1173 /*-----------------------------------------------------------------*/
1174 /* keyForVar - returns the numeric key for a var */
1175 /*-----------------------------------------------------------------*/
1181 while (isdigit (*d))
1190 /*-----------------------------------------------------------------*/
1191 /* bindVar - binds a value to a variable in the given hashtable */
1192 /*-----------------------------------------------------------------*/
1194 bindVar (int key, char **s, hTab ** vtab)
1196 char vval[MAX_PATTERN_LEN];
1200 /* first get the value of the variable */
1202 /* the value is ended by a ',' or space or newline or null or ) */
1211 /* if we find a '(' then we need to balance it */
1223 // include the trailing ')'
1232 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1234 hTabAddItem (vtab, key, vvx);
1237 /*-----------------------------------------------------------------*/
1238 /* matchLine - matches one line */
1239 /*-----------------------------------------------------------------*/
1241 matchLine (char *s, char *d, hTab ** vars)
1250 /* skip white space in both */
1251 while (isspace (*s))
1253 while (isspace (*d))
1256 /* if the destination is a var */
1257 if (*d == '%' && isdigit (*(d + 1)) && vars)
1259 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1260 /* if the variable is already bound
1261 then it MUST match with dest */
1269 /* variable not bound we need to
1271 bindVar (keyForVar (d + 1), &s, vars);
1273 /* in either case go past the variable */
1275 while (isdigit (*d))
1279 /* they should be an exact match other wise */
1282 while (isspace (*s))
1284 while (isspace (*d))
1292 /* get rid of the trailing spaces
1293 in both source & destination */
1295 while (isspace (*s))
1299 while (isspace (*d))
1302 /* after all this if only one of them
1303 has something left over then no match */
1310 /*-----------------------------------------------------------------*/
1311 /* matchRule - matches a all the rule lines */
1312 /*-----------------------------------------------------------------*/
1314 matchRule (lineNode * pl,
1319 lineNode *spl; /* source pl */
1320 lineNode *rpl; /* rule peep line */
1322 /* setToNull((void **) &pr->vars); */
1323 /* pr->vars = newHashTable(100); */
1325 /* for all the lines defined in the rule */
1331 /* if the source line starts with a ';' then
1332 comment line don't process or the source line
1333 contains == . debugger information skip it */
1335 (*spl->line == ';' || spl->isDebug))
1341 if (!matchLine (spl->line, rpl->line, &pr->vars))
1349 /* if rules ended */
1352 /* if this rule has additional conditions */
1355 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1374 reassociate_ic_down (lineNode *shead, lineNode *stail,
1375 lineNode *rhead, lineNode *rtail)
1377 lineNode *csl; /* current source line */
1378 lineNode *crl; /* current replacement line */
1384 /* skip over any comments */
1385 while (csl!=stail->next && csl->isComment)
1387 while (crl!=rtail->next && crl->isComment)
1390 /* quit if we reach the end */
1391 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1394 if (matchLine(csl->line,crl->line,NULL))
1406 reassociate_ic_up (lineNode *shead, lineNode *stail,
1407 lineNode *rhead, lineNode *rtail)
1409 lineNode *csl; /* current source line */
1410 lineNode *crl; /* current replacement line */
1416 /* skip over any comments */
1417 while (csl!=shead->prev && csl->isComment)
1419 while (crl!=rhead->prev && crl->isComment)
1422 /* quit if we reach the end */
1423 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1426 if (matchLine(csl->line,crl->line,NULL))
1437 /*------------------------------------------------------------------*/
1438 /* reassociate_ic - reassociate replacement lines with origin iCode */
1439 /*------------------------------------------------------------------*/
1441 reassociate_ic (lineNode *shead, lineNode *stail,
1442 lineNode *rhead, lineNode *rtail)
1444 lineNode *csl; /* current source line */
1445 lineNode *crl; /* current replacement line */
1449 /* Check to see if all the source lines (excluding comments) came
1450 ** for the same iCode
1453 for (csl=shead;csl!=stail->next;csl=csl->next)
1454 if (csl->ic && !csl->isComment)
1459 single_iCode = (ic!=NULL);
1460 for (csl=shead;csl!=stail->next;csl=csl->next)
1461 if ((csl->ic != ic) && !csl->isComment)
1463 /* More than one iCode was found. However, if it's just the
1464 ** last line with the different iCode and it was not changed
1465 ** in the replacement, everything else must be the first iCode.
1467 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1469 rtail->ic = stail->ic;
1470 for (crl=rhead;crl!=rtail;crl=crl->next)
1475 single_iCode = FALSE;
1479 /* If all of the source lines came from the same iCode, then so have
1480 ** all of the replacement lines too.
1484 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1489 /* The source lines span iCodes, so we may end up with replacement
1490 ** lines that we don't know which iCode(s) to associate with. Do the
1491 ** best we can by using the following strategies:
1492 ** 1) Start at the top and scan down. As long as the source line
1493 ** matches the replacement line, they have the same iCode.
1494 ** 2) Start at the bottom and scan up. As long as the source line
1495 ** matches the replacement line, they have the same iCode.
1496 ** 3) For any label in the source, look for a matching label in
1497 ** the replacment. If found, they have the same iCode. From
1498 ** these matching labels, scan down for additional matching
1499 ** lines; if found, they also have the same iCode.
1502 /* Strategy #1: Start at the top and scan down for matches
1504 reassociate_ic_down(shead,stail,rhead,rtail);
1506 /* Strategy #2: Start at the bottom and scan up for matches
1508 reassociate_ic_up(shead,stail,rhead,rtail);
1510 /* Strategy #3: Try to match labels
1515 const char *labelStart;
1518 /* skip over any comments */
1519 while (csl!=stail->next && csl->isComment)
1521 if (csl==stail->next)
1524 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1526 /* found a source line label; look for it in the replacment lines */
1530 while (crl!=rtail->next && crl->isComment)
1532 if (crl==rtail->next)
1534 if (matchLine(csl->line, crl->line, NULL))
1536 reassociate_ic_down(csl,stail,crl,rtail);
1546 /* Try to assign a meaningful iCode to any comment that is missing
1547 one. Since they are comments, it's ok to make mistakes; we are just
1548 trying to improve continuity to simplify other tests.
1551 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1553 if (!crl->ic && ic && crl->isComment)
1560 /*-----------------------------------------------------------------*/
1561 /* replaceRule - does replacement of a matching pattern */
1562 /*-----------------------------------------------------------------*/
1564 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1566 lineNode *cl = NULL;
1567 lineNode *pl = NULL, *lhead = NULL;
1568 /* a long function name and long variable name can evaluate to
1569 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1570 char lb[MAX_PATTERN_LEN*4];
1572 lineNode *comment = NULL;
1574 /* collect all the comment lines in the source */
1575 for (cl = *shead; cl != stail; cl = cl->next)
1577 if (cl->line && (*cl->line == ';' || cl->isDebug))
1579 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1580 (comment = newLineNode (cl->line)));
1581 pl->isDebug = cl->isDebug;
1582 pl->isComment = cl->isComment || (*cl->line == ';');
1587 /* for all the lines in the replacement pattern do */
1588 for (pl = pr->replace; pl; pl = pl->next)
1598 /* if the line contains a variable */
1599 if (*l == '%' && isdigit (*(l + 1)))
1601 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1604 fprintf (stderr, "used unbound variable in replacement\n");
1612 while (isdigit (*l)) {
1622 cl = connectLine (cl, newLineNode (lb));
1624 lhead = cl = newLineNode (lb);
1625 cl->isComment = pl->isComment;
1628 /* add the comments if any to the head of list */
1631 lineNode *lc = comment;
1640 /* determine which iCodes the replacment lines relate to */
1641 reassociate_ic(*shead,stail,lhead,cl);
1643 /* now we need to connect / replace the original chain */
1644 /* if there is a prev then change it */
1647 (*shead)->prev->next = lhead;
1648 lhead->prev = (*shead)->prev;
1651 /* now for the tail */
1652 if (stail && stail->next)
1654 stail->next->prev = cl;
1656 cl->next = stail->next;
1660 /* Returns TRUE if this line is a label definition.
1662 * If so, start will point to the start of the label name,
1663 * and len will be it's length.
1666 isLabelDefinition (const char *line, const char **start, int *len)
1668 const char *cp = line;
1670 /* This line is a label if if consists of:
1671 * [optional whitespace] followed by identifier chars
1672 * (alnum | $ | _ ) followed by a colon.
1675 while (*cp && isspace (*cp))
1687 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1692 if ((cp == *start) || (*cp != ':'))
1697 *len = (cp - (*start));
1701 /* Quick & dirty string hash function. */
1703 hashSymbolName (const char *name)
1709 hash = (hash << 6) ^ *name;
1718 return hash % HTAB_SIZE;
1721 /* Build a hash of all labels in the passed set of lines
1722 * and how many times they are referenced.
1725 buildLabelRefCountHash (lineNode * head)
1732 assert (labelHash == NULL);
1733 labelHash = newHashTable (HTAB_SIZE);
1735 /* First pass: locate all the labels. */
1740 if (isLabelDefinition (line->line, &label, &labelLen)
1741 && labelLen <= SDCC_NAME_MAX)
1743 labelHashEntry *entry;
1745 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1747 memcpy (entry->name, label, labelLen);
1748 entry->name[labelLen] = 0;
1749 entry->refCount = -1;
1751 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1757 /* Second pass: for each line, note all the referenced labels. */
1758 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1762 for (i = 0; i < HTAB_SIZE; i++)
1764 labelHashEntry *thisEntry;
1766 thisEntry = hTabFirstItemWK (labelHash, i);
1770 if (strstr (line->line, thisEntry->name))
1772 thisEntry->refCount++;
1774 thisEntry = hTabNextItemWK (labelHash);
1781 /* Spew the contents of the table. Debugging fun only. */
1782 for (i = 0; i < HTAB_SIZE; i++)
1784 labelHashEntry *thisEntry;
1786 thisEntry = hTabFirstItemWK (labelHash, i);
1790 fprintf (stderr, "label: %s ref %d\n",
1791 thisEntry->name, thisEntry->refCount);
1792 thisEntry = hTabNextItemWK (labelHash);
1798 /* How does this work?
1804 replace and restart.
1809 Where is stuff allocated?
1813 /*-----------------------------------------------------------------*/
1814 /* peepHole - matches & substitutes rules */
1815 /*-----------------------------------------------------------------*/
1817 peepHole (lineNode ** pls)
1821 lineNode *mtail = NULL;
1824 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1825 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1826 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1830 assert(labelHash == NULL);
1837 for (pr = rootRules; pr; pr = pr->next)
1839 for (spl = *pls; spl; spl = spl->next)
1841 /* if inline assembler then no peep hole */
1847 /* Tidy up any data stored in the hTab */
1850 if (matchRule (spl, &mtail, pr, *pls))
1855 replaceRule (pls, mtail, pr);
1857 replaceRule (&spl, mtail, pr);
1859 /* if restart rule type then
1860 start at the top again */
1869 hTabDeleteAll (pr->vars);
1870 Safe_free (pr->vars);
1874 freeTrace (&_G.values);
1877 } while (restart == TRUE);
1881 hTabDeleteAll (labelHash);
1882 freeTrace (&_G.labels);
1888 /*-----------------------------------------------------------------*/
1889 /* readFileIntoBuffer - reads a file into a string buffer */
1890 /*-----------------------------------------------------------------*/
1892 readFileIntoBuffer (char *fname)
1898 char lb[MAX_PATTERN_LEN];
1900 if (!(f = fopen (fname, "r")))
1902 fprintf (stderr, "cannot open peep rule file\n");
1906 while ((ch = fgetc (f)) != EOF)
1910 /* if we maxed out our local buffer */
1911 if (nch >= (MAX_PATTERN_LEN - 2))
1914 /* copy it into allocated buffer */
1917 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1918 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1922 rs = Safe_strdup (lb);
1928 /* if some charaters left over */
1932 /* copy it into allocated buffer */
1935 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1936 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1940 rs = Safe_strdup (lb);
1946 /*-----------------------------------------------------------------*/
1947 /* initPeepHole - initialises the peep hole optimizer stuff */
1948 /*-----------------------------------------------------------------*/
1954 /* read in the default rules */
1955 readRules (port->peep.default_rules);
1957 /* if we have any additional file read it too */
1958 if (options.peep_file)
1960 readRules (s = readFileIntoBuffer (options.peep_file));
1961 setToNull ((void **) &s);
1965 #if !OPT_DISABLE_PIC
1966 /* Convert the peep rules into pcode.
1967 NOTE: this is only support in the PIC port (at the moment)
1970 peepRules2pCode(rootRules);
1973 #if !OPT_DISABLE_PIC16
1974 /* Convert the peep rules into pcode.
1975 NOTE: this is only support in the PIC port (at the moment)
1976 and the PIC16 port (VR 030601)
1978 if (TARGET_IS_PIC16)
1979 pic16_peepRules2pCode(rootRules);