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 /*-----------------------------------------------------------------*/
69 pcDistance (lineNode * cpos, char *lbl, bool back)
72 char buff[MAX_PATTERN_LEN];
75 SNPRINTF (buff, sizeof(buff), "%s:", lbl);
81 pl->line[strlen (pl->line) - 1] != ':' &&
83 if (port->peep.getSize) {
84 dist += port->peep.getSize(pl);
90 if (strncmp (pl->line, buff, strlen (buff)) == 0)
102 /*-----------------------------------------------------------------*/
103 /* flat24bitModeAndPortDS390 - */
104 /*-----------------------------------------------------------------*/
105 FBYNAME (flat24bitModeAndPortDS390)
107 return (((strcmp(port->target,"ds390") == 0) ||
108 (strcmp(port->target,"ds400") == 0)) &&
109 (options.model == MODEL_FLAT24));
112 /*-----------------------------------------------------------------*/
113 /* portIsDS390 - return true if port is DS390 */
114 /*-----------------------------------------------------------------*/
115 FBYNAME (portIsDS390)
117 return ((strcmp(port->target,"ds390") == 0) ||
118 (strcmp(port->target,"ds400") == 0));
121 /*-----------------------------------------------------------------*/
122 /* flat24bitMode - will check to see if we are in flat24 mode */
123 /*-----------------------------------------------------------------*/
124 FBYNAME (flat24bitMode)
126 return (options.model == MODEL_FLAT24);
129 /*-----------------------------------------------------------------*/
130 /* xramMovcOption - check if using movc to read xram */
131 /*-----------------------------------------------------------------*/
132 FBYNAME (xramMovcOption)
134 return (options.xram_movc && (strcmp(port->target,"mcs51") == 0));
142 /*-----------------------------------------------------------------*/
143 /* labelInRange - will check to see if label %5 is within range */
144 /*-----------------------------------------------------------------*/
145 FBYNAME (labelInRange)
147 /* assumes that %5 pattern variable has the label name */
148 char *lbl = hTabItemWithKey (vars, 5);
154 /* Don't optimize jumps in a jump table; a more generic test */
155 if (currPl->ic && currPl->ic->op == JUMPTABLE)
158 /* if the previous two instructions are "ljmp"s then don't
159 do it since it can be part of a jump table */
160 if (currPl->prev && currPl->prev->prev &&
161 strstr (currPl->prev->line, "ljmp") &&
162 strstr (currPl->prev->prev->line, "ljmp"))
165 /* calculate the label distance : the jump for reladdr can be
166 +/- 127 bytes, here Iam assuming that an average 8051
167 instruction is 2 bytes long, so if the label is more than
168 63 intructions away, the label is considered out of range
169 for a relative jump. we could get more precise this will
170 suffice for now since it catches > 90% cases */
171 dist = (pcDistance (currPl, lbl, TRUE) +
172 pcDistance (currPl, lbl, FALSE));
174 /* changed to 127, now that pcDistance return actual number of bytes */
175 if (!dist || dist > 127)
182 /*-----------------------------------------------------------------*/
183 /* labelJTInRange - will check to see if label %5 and up are */
185 /* Specifically meant to optimize long (3-byte) jumps to short */
186 /* (2-byte) jumps in jumptables */
187 /*-----------------------------------------------------------------*/
188 FBYNAME (labelJTInRange)
193 if (!getenv("SDCC_SJMP_JUMPTABLE"))
196 /* Only optimize within a jump table */
197 if (currPl->ic && currPl->ic->op != JUMPTABLE)
200 count = elementsInSet( IC_JTLABELS (currPl->ic) );
202 /* check all labels (this is needed if the case statements are unsorted) */
203 for (i=0; i<count; i++)
205 /* assumes that the %5 pattern variable has the first ljmp label */
206 lbl = hTabItemWithKey (vars, 5+i);
210 dist = pcDistance (currPl, lbl, FALSE);
212 /* three terms used to calculate allowable distance */
213 // printf("\nlabel %s %i dist %i cdist 0x%02x 0x%02x\n", lbl, i, dist, dist -(count-i-1)-(7+3*i), 127+(count-i-1)+(7+3*i) - dist);
215 dist > 127+ /* range of sjmp */
216 (7+3*i)+ /* offset between this jump and currPl,
217 should use pcDistance instead? */
218 (count-i-1) /* if peephole applies distance is shortened */
226 /*-----------------------------------------------------------------*/
227 /* labelIsReturnOnly - Check if label %5 is followed by RET */
228 /*-----------------------------------------------------------------*/
229 FBYNAME (labelIsReturnOnly)
231 /* assumes that %5 pattern variable has the label name */
232 const char *label, *p;
237 label = hTabItemWithKey (vars, 5);
238 if (!label) return FALSE;
241 for(pl = currPl; pl; pl = pl->next) {
242 if (pl->line && !pl->isDebug && !pl->isComment &&
243 pl->line[strlen(pl->line)-1] == ':') {
244 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
245 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
246 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
247 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
248 *(pl->line+5) != '$') {
249 return FALSE; /* non-local label encountered */
253 if (!pl) return FALSE; /* did not find the label */
255 while (pl && (pl->isDebug || pl->isComment))
257 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
259 for (p = pl->line; *p && isspace(*p); p++)
265 if (strcmp(p, retInst) == 0) return TRUE;
270 /*-----------------------------------------------------------------*/
271 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
272 /* usage of it in the code depends on a value from this section */
273 /*-----------------------------------------------------------------*/
274 FBYNAME (okToRemoveSLOC)
277 const char *sloc, *p;
278 int dummy1, dummy2, dummy3;
280 /* assumes that %1 as the SLOC name */
281 sloc = hTabItemWithKey (vars, 1);
282 if (sloc == NULL) return FALSE;
283 p = strstr(sloc, "sloc");
284 if (p == NULL) return FALSE;
286 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
287 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
288 /* the sloc name begins with that. Probably not really necessary */
290 /* Look for any occurance of this SLOC before the peephole match */
291 for (pl = currPl->prev; pl; pl = pl->prev) {
292 if (pl->line && !pl->isDebug && !pl->isComment
293 && *pl->line != ';' && strstr(pl->line, sloc))
296 /* Look for any occurance of this SLOC after the peephole match */
297 for (pl = endPl->next; pl; pl = pl->next) {
298 if (pl->line && !pl->isDebug && !pl->isComment
299 && *pl->line != ';' && strstr(pl->line, sloc))
302 return TRUE; /* safe for a peephole to remove it :) */
306 /*-----------------------------------------------------------------*/
307 /* operandsNotSame - check if %1 & %2 are the same */
308 /*-----------------------------------------------------------------*/
309 FBYNAME (operandsNotSame)
311 char *op1 = hTabItemWithKey (vars, 1);
312 char *op2 = hTabItemWithKey (vars, 2);
314 if (strcmp (op1, op2) == 0)
320 /*-----------------------------------------------------------------*/
321 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
322 /*-----------------------------------------------------------------*/
323 FBYNAME (operandsNotSame3)
325 char *op1 = hTabItemWithKey (vars, 1);
326 char *op2 = hTabItemWithKey (vars, 2);
327 char *op3 = hTabItemWithKey (vars, 3);
329 if ( (strcmp (op1, op2) == 0) ||
330 (strcmp (op1, op3) == 0) ||
331 (strcmp (op2, op3) == 0) )
337 /*-----------------------------------------------------------------*/
338 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
339 /*-----------------------------------------------------------------*/
340 FBYNAME (operandsNotSame4)
342 char *op1 = hTabItemWithKey (vars, 1);
343 char *op2 = hTabItemWithKey (vars, 2);
344 char *op3 = hTabItemWithKey (vars, 3);
345 char *op4 = hTabItemWithKey (vars, 4);
347 if ( (strcmp (op1, op2) == 0) ||
348 (strcmp (op1, op3) == 0) ||
349 (strcmp (op1, op4) == 0) ||
350 (strcmp (op2, op3) == 0) ||
351 (strcmp (op2, op4) == 0) ||
352 (strcmp (op3, op4) == 0) )
358 /*-----------------------------------------------------------------*/
359 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
360 /*-----------------------------------------------------------------*/
361 FBYNAME (operandsNotSame5)
363 char *op1 = hTabItemWithKey (vars, 1);
364 char *op2 = hTabItemWithKey (vars, 2);
365 char *op3 = hTabItemWithKey (vars, 3);
366 char *op4 = hTabItemWithKey (vars, 4);
367 char *op5 = hTabItemWithKey (vars, 5);
369 if ( (strcmp (op1, op2) == 0) ||
370 (strcmp (op1, op3) == 0) ||
371 (strcmp (op1, op4) == 0) ||
372 (strcmp (op1, op5) == 0) ||
373 (strcmp (op2, op3) == 0) ||
374 (strcmp (op2, op4) == 0) ||
375 (strcmp (op2, op5) == 0) ||
376 (strcmp (op3, op4) == 0) ||
377 (strcmp (op3, op5) == 0) ||
378 (strcmp (op4, op5) == 0) )
384 /*-----------------------------------------------------------------*/
385 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
386 /*-----------------------------------------------------------------*/
387 FBYNAME (operandsNotSame6)
389 char *op1 = hTabItemWithKey (vars, 1);
390 char *op2 = hTabItemWithKey (vars, 2);
391 char *op3 = hTabItemWithKey (vars, 3);
392 char *op4 = hTabItemWithKey (vars, 4);
393 char *op5 = hTabItemWithKey (vars, 5);
394 char *op6 = hTabItemWithKey (vars, 6);
396 if ( (strcmp (op1, op2) == 0) ||
397 (strcmp (op1, op3) == 0) ||
398 (strcmp (op1, op4) == 0) ||
399 (strcmp (op1, op5) == 0) ||
400 (strcmp (op1, op6) == 0) ||
401 (strcmp (op2, op3) == 0) ||
402 (strcmp (op2, op4) == 0) ||
403 (strcmp (op2, op5) == 0) ||
404 (strcmp (op2, op6) == 0) ||
405 (strcmp (op3, op4) == 0) ||
406 (strcmp (op3, op5) == 0) ||
407 (strcmp (op3, op6) == 0) ||
408 (strcmp (op4, op5) == 0) ||
409 (strcmp (op4, op6) == 0) ||
410 (strcmp (op5, op6) == 0) )
417 /*-----------------------------------------------------------------*/
418 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
419 /*-----------------------------------------------------------------*/
420 FBYNAME (operandsNotSame7)
422 char *op1 = hTabItemWithKey (vars, 1);
423 char *op2 = hTabItemWithKey (vars, 2);
424 char *op3 = hTabItemWithKey (vars, 3);
425 char *op4 = hTabItemWithKey (vars, 4);
426 char *op5 = hTabItemWithKey (vars, 5);
427 char *op6 = hTabItemWithKey (vars, 6);
428 char *op7 = hTabItemWithKey (vars, 7);
430 if ( (strcmp (op1, op2) == 0) ||
431 (strcmp (op1, op3) == 0) ||
432 (strcmp (op1, op4) == 0) ||
433 (strcmp (op1, op5) == 0) ||
434 (strcmp (op1, op6) == 0) ||
435 (strcmp (op1, op7) == 0) ||
436 (strcmp (op2, op3) == 0) ||
437 (strcmp (op2, op4) == 0) ||
438 (strcmp (op2, op5) == 0) ||
439 (strcmp (op2, op6) == 0) ||
440 (strcmp (op2, op7) == 0) ||
441 (strcmp (op3, op4) == 0) ||
442 (strcmp (op3, op5) == 0) ||
443 (strcmp (op3, op6) == 0) ||
444 (strcmp (op3, op7) == 0) ||
445 (strcmp (op4, op5) == 0) ||
446 (strcmp (op4, op6) == 0) ||
447 (strcmp (op4, op7) == 0) ||
448 (strcmp (op5, op6) == 0) ||
449 (strcmp (op5, op7) == 0) ||
450 (strcmp (op6, op7) == 0) )
456 /*-----------------------------------------------------------------*/
457 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
458 /*-----------------------------------------------------------------*/
459 FBYNAME (operandsNotSame8)
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);
467 char *op7 = hTabItemWithKey (vars, 7);
468 char *op8 = hTabItemWithKey (vars, 8);
470 if ( (strcmp (op1, op2) == 0) ||
471 (strcmp (op1, op3) == 0) ||
472 (strcmp (op1, op4) == 0) ||
473 (strcmp (op1, op5) == 0) ||
474 (strcmp (op1, op6) == 0) ||
475 (strcmp (op1, op7) == 0) ||
476 (strcmp (op1, op8) == 0) ||
477 (strcmp (op2, op3) == 0) ||
478 (strcmp (op2, op4) == 0) ||
479 (strcmp (op2, op5) == 0) ||
480 (strcmp (op2, op6) == 0) ||
481 (strcmp (op2, op7) == 0) ||
482 (strcmp (op2, op8) == 0) ||
483 (strcmp (op3, op4) == 0) ||
484 (strcmp (op3, op5) == 0) ||
485 (strcmp (op3, op6) == 0) ||
486 (strcmp (op3, op7) == 0) ||
487 (strcmp (op3, op8) == 0) ||
488 (strcmp (op4, op5) == 0) ||
489 (strcmp (op4, op6) == 0) ||
490 (strcmp (op4, op7) == 0) ||
491 (strcmp (op4, op8) == 0) ||
492 (strcmp (op5, op6) == 0) ||
493 (strcmp (op5, op7) == 0) ||
494 (strcmp (op5, op8) == 0) ||
495 (strcmp (op6, op7) == 0) ||
496 (strcmp (op6, op8) == 0) ||
497 (strcmp (op7, op8) == 0) )
506 * takes two parameters: a variable (bound to a label name)
507 * and an expected reference count.
509 * Returns TRUE if that label is defined and referenced exactly
510 * the given number of times.
512 FBYNAME (labelRefCount)
514 int varNumber, expectedRefCount;
517 /* If we don't have the label hash table yet, build it. */
520 buildLabelRefCountHash (head);
523 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
525 char *label = hTabItemWithKey (vars, varNumber);
529 labelHashEntry *entry;
531 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
535 if (!strcmp (label, entry->name))
539 entry = hTabNextItemWK (labelHash);
545 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
546 label, entry->refCount, expectedRefCount);
549 rc = (expectedRefCount == entry->refCount);
553 fprintf (stderr, "*** internal error: no label has entry for"
554 " %s in labelRefCount peephole.\n",
560 fprintf (stderr, "*** internal error: var %d not bound"
561 " in peephole labelRefCount rule.\n",
569 "*** internal error: labelRefCount peephole restriction"
570 " malformed: %s\n", cmdLine);
575 /* Within the context of the lines currPl through endPl, determine
576 ** if the variable var contains a symbol that is volatile. Returns
577 ** TRUE only if it is certain that this was not volatile (the symbol
578 ** was found and not volatile, or var was a constant or CPU register).
579 ** Returns FALSE if the symbol was found and volatile, the symbol was
580 ** not found, or var was a indirect/pointer addressing mode.
583 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
585 char symname[SDCC_NAME_MAX + 1];
592 /* Can't tell if indirect accesses are volatile or not, so
593 ** assume they are, just to be safe.
595 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
600 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
602 if (strstr(var,"(bc)"))
604 if (strstr(var,"(de)"))
606 if (strstr(var,"(hl)"))
608 if (strstr(var,"(ix"))
610 if (strstr(var,"(iy"))
614 /* Extract a symbol name from the variable */
615 while (*vp && (*vp!='_'))
617 while (*vp && (isalnum(*vp) || *vp=='_'))
623 /* Nothing resembling a symbol name was found, so it can't
630 for (cl = currPl; cl!=endPl->next; cl = cl->next)
632 if (cl->ic && (cl->ic!=last_ic))
638 op = IC_COND (cl->ic);
639 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
640 return !op->isvolatile;
642 op = IC_JTCOND (cl->ic);
643 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
644 return !op->isvolatile;
646 op = IC_LEFT (cl->ic);
647 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
648 return !op->isvolatile;
649 op = IC_RIGHT (cl->ic);
650 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
651 return !op->isvolatile;
652 op = IC_RESULT (cl->ic);
653 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
654 return !op->isvolatile;
659 /* Couldn't find the symbol for some reason. Assume volatile. */
665 * This rule restriction has two different behaviours depending on
666 * the number of parameters given.
668 * if notVolatile (no parameters given)
669 * The rule is applied only if none of the iCodes originating
670 * the matched pattern reference a volatile operand.
672 * if notVolatile %1 ... (one or more parameters given)
673 * The rule is applied if the parameters are not expressions
674 * containing volatile symbols and are not pointer accesses.
677 FBYNAME (notVolatile)
688 /* If no parameters given, just scan the iCodes for volatile operands */
689 for (cl = currPl; cl!=endPl->next; cl = cl->next)
696 op = IC_COND (cl->ic);
697 if (IS_SYMOP (op) && op->isvolatile)
700 op = IC_JTCOND (cl->ic);
701 if (IS_SYMOP (op) && op->isvolatile)
704 op = IC_LEFT (cl->ic);
705 if (IS_SYMOP (op) && op->isvolatile)
707 op = IC_RIGHT (cl->ic);
708 if (IS_SYMOP (op) && op->isvolatile)
710 op = IC_RESULT (cl->ic);
711 if (IS_SYMOP (op) && op->isvolatile)
719 /* There were parameters; check the volatility of each */
720 while (*cmdLine && isspace(*cmdLine))
727 if (!isdigit(*cmdLine))
729 varNumber = strtol(cmdLine, &digitend, 10);
731 while (*cmdLine && isspace(*cmdLine))
734 var = hTabItemWithKey (vars, varNumber);
738 notvol = notVolatileVariable (var, currPl, endPl);
744 fprintf (stderr, "*** internal error: var %d not bound"
745 " in peephole notVolatile rule.\n",
756 "*** internal error: notVolatile peephole restriction"
757 " malformed: %s\n", cmdLine);
762 /*-----------------------------------------------------------------*/
763 /* callFuncByName - calls a function as defined in the table */
764 /*-----------------------------------------------------------------*/
766 callFuncByName (char *fname,
775 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
780 "labelInRange", labelInRange
784 "labelJTInRange", labelJTInRange
788 "operandsNotSame", operandsNotSame
792 "operandsNotSame3", operandsNotSame3
796 "operandsNotSame4", operandsNotSame4
800 "operandsNotSame5", operandsNotSame5
804 "operandsNotSame6", operandsNotSame6
808 "operandsNotSame7", operandsNotSame7
812 "operandsNotSame8", operandsNotSame8
816 "24bitMode", flat24bitMode
820 "xramMovcOption", xramMovcOption
824 "labelRefCount", labelRefCount
828 "portIsDS390", portIsDS390
831 "labelIsReturnOnly", labelIsReturnOnly
834 "okToRemoveSLOC", okToRemoveSLOC
837 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
840 "notVolatile", notVolatile
844 char *cmdCopy, *funcName, *funcArgs;
847 /* Isolate the function name part (we are passed the full condition
848 * string including arguments)
850 cmdCopy = Safe_strdup(fname);
851 funcName = strtok(cmdCopy, " \t");
852 funcArgs = strtok(NULL, "");
854 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
856 if (strcmp (ftab[i].fname, funcName) == 0)
858 rc = (*ftab[i].func) (vars, currPl, endPl, head,
866 "could not find named function \"%s\" in "
867 "peephole function table\n",
869 // If the function couldn't be found, let's assume it's
870 // a bad rule and refuse it.
879 /*-----------------------------------------------------------------*/
880 /* printLine - prints a line chain into a given file */
881 /*-----------------------------------------------------------------*/
883 printLine (lineNode * head, FILE * of)
885 iCode *last_ic = NULL;
886 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
893 if (head->ic!=last_ic)
896 if (debug_iCode_tracking)
899 fprintf (of, "; block = %d, seq = %d\n",
900 head->ic->block, head->ic->seq);
902 fprintf (of, "; iCode lost\n");
906 /* don't indent comments & labels */
908 (*head->line == ';' ||
909 head->line[strlen (head->line) - 1] == ':')) {
910 fprintf (of, "%s\n", head->line);
912 if (head->isInline && *head->line=='#') {
913 // comment out preprocessor directives in inline asm
916 fprintf (of, "\t%s\n", head->line);
922 /*-----------------------------------------------------------------*/
923 /* newPeepRule - creates a new peeprule and attach it to the root */
924 /*-----------------------------------------------------------------*/
926 newPeepRule (lineNode * match,
933 pr = Safe_alloc ( sizeof (peepRule));
935 pr->replace = replace;
936 pr->restart = restart;
940 pr->cond = Safe_strdup (cond);
945 pr->vars = newHashTable (100);
947 /* if root is empty */
949 rootRules = currRule = pr;
951 currRule = currRule->next = pr;
956 /*-----------------------------------------------------------------*/
957 /* newLineNode - creates a new peep line */
958 /*-----------------------------------------------------------------*/
960 newLineNode (char *line)
964 pl = Safe_alloc ( sizeof (lineNode));
965 pl->line = Safe_strdup (line);
970 /*-----------------------------------------------------------------*/
971 /* connectLine - connects two lines */
972 /*-----------------------------------------------------------------*/
974 connectLine (lineNode * pl1, lineNode * pl2)
978 fprintf (stderr, "trying to connect null line\n");
988 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
989 if (!*x) { fprintf(stderr,y); return ; } }
991 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
992 if (!*x) { fprintf(stderr,z); return ; } }
993 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
994 if (!*x) { fprintf(stderr,z); return ; } }
996 /*-----------------------------------------------------------------*/
997 /* getPeepLine - parses the peep lines */
998 /*-----------------------------------------------------------------*/
1000 getPeepLine (lineNode ** head, char **bpp)
1002 char lines[MAX_PATTERN_LEN];
1006 lineNode *currL = NULL;
1013 fprintf (stderr, "unexpected end of match pattern\n");
1020 while (isspace (*bp) ||
1031 /* read till end of line */
1033 while ((*bp != '\n' && *bp != '}') && *bp)
1038 while (*lp && isspace(*lp))
1040 isComment = (*lp == ';');
1042 if (!isComment || (isComment && !options.noPeepComments))
1045 *head = currL = newLineNode (lines);
1047 currL = connectLine (currL, newLineNode (lines));
1048 currL->isComment = isComment;
1056 /*-----------------------------------------------------------------*/
1057 /* readRules - reads the rules from a string buffer */
1058 /*-----------------------------------------------------------------*/
1060 readRules (char *bp)
1063 char lines[MAX_PATTERN_LEN];
1067 lineNode *currL = NULL;
1073 /* look for the token "replace" that is the
1075 while (*bp && strncmp (bp, "replace", 7))
1082 /* then look for either "restart" or '{' */
1083 while (strncmp (bp, "restart", 7) &&
1090 fprintf (stderr, "expected 'restart' or '{'\n");
1098 { /* must be restart */
1100 bp += strlen ("restart");
1102 EXPECT_CHR (bp, '{', "expected '{'\n");
1106 /* skip thru all the blank space */
1107 SKIP_SPACE (bp, "unexpected end of rule\n");
1109 match = replace = currL = NULL;
1110 /* we are the start of a rule */
1111 getPeepLine (&match, &bp);
1113 /* now look for by */
1114 EXPECT_STR (bp, "by", "expected 'by'\n");
1116 /* then look for a '{' */
1117 EXPECT_CHR (bp, '{', "expected '{'\n");
1120 SKIP_SPACE (bp, "unexpected end of rule\n");
1121 getPeepLine (&replace, &bp);
1123 /* look for a 'if' */
1124 while ((isspace (*bp) || *bp == '\n') && *bp)
1127 if (strncmp (bp, "if", 2) == 0)
1130 while ((isspace (*bp) || *bp == '\n') && *bp)
1134 fprintf (stderr, "expected condition name\n");
1138 /* look for the condition */
1140 while (*bp && (*bp != '\n'))
1146 newPeepRule (match, replace, lines, restart);
1149 newPeepRule (match, replace, NULL, restart);
1154 /*-----------------------------------------------------------------*/
1155 /* keyForVar - returns the numeric key for a var */
1156 /*-----------------------------------------------------------------*/
1162 while (isdigit (*d))
1171 /*-----------------------------------------------------------------*/
1172 /* bindVar - binds a value to a variable in the given hashtable */
1173 /*-----------------------------------------------------------------*/
1175 bindVar (int key, char **s, hTab ** vtab)
1177 char vval[MAX_PATTERN_LEN];
1181 /* first get the value of the variable */
1183 /* the value is ended by a ',' or space or newline or null or ) */
1192 /* if we find a '(' then we need to balance it */
1204 // include the trailing ')'
1213 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1215 hTabAddItem (vtab, key, vvx);
1218 /*-----------------------------------------------------------------*/
1219 /* matchLine - matches one line */
1220 /*-----------------------------------------------------------------*/
1222 matchLine (char *s, char *d, hTab ** vars)
1231 /* skip white space in both */
1232 while (isspace (*s))
1234 while (isspace (*d))
1237 /* if the destination is a var */
1238 if (*d == '%' && isdigit (*(d + 1)) && vars)
1240 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1241 /* if the variable is already bound
1242 then it MUST match with dest */
1250 /* variable not bound we need to
1252 bindVar (keyForVar (d + 1), &s, vars);
1254 /* in either case go past the variable */
1256 while (isdigit (*d))
1259 while (isspace (*s))
1261 while (isspace (*d))
1265 /* they should be an exact match other wise */
1274 /* get rid of the trailing spaces
1275 in both source & destination */
1277 while (isspace (*s))
1281 while (isspace (*d))
1284 /* after all this if only one of them
1285 has something left over then no match */
1292 /*-----------------------------------------------------------------*/
1293 /* matchRule - matches a all the rule lines */
1294 /*-----------------------------------------------------------------*/
1296 matchRule (lineNode * pl,
1301 lineNode *spl; /* source pl */
1302 lineNode *rpl; /* rule peep line */
1304 /* setToNull((void *) &pr->vars); */
1305 /* pr->vars = newHashTable(100); */
1307 /* for all the lines defined in the rule */
1313 /* if the source line starts with a ';' then
1314 comment line don't process or the source line
1315 contains == . debugger information skip it */
1317 (*spl->line == ';' || spl->isDebug))
1323 if (!matchLine (spl->line, rpl->line, &pr->vars))
1331 /* if rules ended */
1334 /* if this rule has additional conditions */
1337 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1356 reassociate_ic_down (lineNode *shead, lineNode *stail,
1357 lineNode *rhead, lineNode *rtail)
1359 lineNode *csl; /* current source line */
1360 lineNode *crl; /* current replacement line */
1366 /* skip over any comments */
1367 while (csl!=stail->next && csl->isComment)
1369 while (crl!=rtail->next && crl->isComment)
1372 /* quit if we reach the end */
1373 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1376 if (matchLine(csl->line,crl->line,NULL))
1388 reassociate_ic_up (lineNode *shead, lineNode *stail,
1389 lineNode *rhead, lineNode *rtail)
1391 lineNode *csl; /* current source line */
1392 lineNode *crl; /* current replacement line */
1398 /* skip over any comments */
1399 while (csl!=shead->prev && csl->isComment)
1401 while (crl!=rhead->prev && crl->isComment)
1404 /* quit if we reach the end */
1405 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1408 if (matchLine(csl->line,crl->line,NULL))
1419 /*------------------------------------------------------------------*/
1420 /* reassociate_ic - reassociate replacement lines with origin iCode */
1421 /*------------------------------------------------------------------*/
1423 reassociate_ic (lineNode *shead, lineNode *stail,
1424 lineNode *rhead, lineNode *rtail)
1426 lineNode *csl; /* current source line */
1427 lineNode *crl; /* current replacement line */
1431 /* Check to see if all the source lines (excluding comments) came
1432 ** for the same iCode
1435 for (csl=shead;csl!=stail->next;csl=csl->next)
1436 if (csl->ic && !csl->isComment)
1441 single_iCode = (ic!=NULL);
1442 for (csl=shead;csl!=stail->next;csl=csl->next)
1443 if ((csl->ic != ic) && !csl->isComment)
1445 /* More than one iCode was found. However, if it's just the
1446 ** last line with the different iCode and it was not changed
1447 ** in the replacement, everything else must be the first iCode.
1449 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1451 rtail->ic = stail->ic;
1452 for (crl=rhead;crl!=rtail;crl=crl->next)
1457 single_iCode = FALSE;
1461 /* If all of the source lines came from the same iCode, then so have
1462 ** all of the replacement lines too.
1466 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1471 /* The source lines span iCodes, so we may end up with replacement
1472 ** lines that we don't know which iCode(s) to associate with. Do the
1473 ** best we can by using the following strategies:
1474 ** 1) Start at the top and scan down. As long as the source line
1475 ** matches the replacement line, they have the same iCode.
1476 ** 2) Start at the bottom and scan up. As long as the source line
1477 ** matches the replacement line, they have the same iCode.
1478 ** 3) For any label in the source, look for a matching label in
1479 ** the replacment. If found, they have the same iCode. From
1480 ** these matching labels, scan down for additional matching
1481 ** lines; if found, they also have the same iCode.
1484 /* Strategy #1: Start at the top and scan down for matches
1486 reassociate_ic_down(shead,stail,rhead,rtail);
1488 /* Strategy #2: Start at the bottom and scan up for matches
1490 reassociate_ic_up(shead,stail,rhead,rtail);
1492 /* Strategy #3: Try to match labels
1497 const char *labelStart;
1500 /* skip over any comments */
1501 while (csl!=stail->next && csl->isComment)
1503 if (csl==stail->next)
1506 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1508 /* found a source line label; look for it in the replacment lines */
1512 while (crl!=rtail->next && crl->isComment)
1514 if (crl==rtail->next)
1516 if (matchLine(csl->line, crl->line, NULL))
1518 reassociate_ic_down(csl,stail,crl,rtail);
1528 /* Try to assign a meaningful iCode to any comment that is missing
1529 one. Since they are comments, it's ok to make mistakes; we are just
1530 trying to improve continuity to simplify other tests.
1533 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1535 if (!crl->ic && ic && crl->isComment)
1542 /*-----------------------------------------------------------------*/
1543 /* replaceRule - does replacement of a matching pattern */
1544 /*-----------------------------------------------------------------*/
1546 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1548 lineNode *cl = NULL;
1549 lineNode *pl = NULL, *lhead = NULL;
1550 /* a long function name and long variable name can evaluate to
1551 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1552 char lb[MAX_PATTERN_LEN*4];
1554 lineNode *comment = NULL;
1556 /* collect all the comment lines in the source */
1557 for (cl = *shead; cl != stail; cl = cl->next)
1559 if (cl->line && (*cl->line == ';' || cl->isDebug))
1561 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1562 (comment = newLineNode (cl->line)));
1563 pl->isDebug = cl->isDebug;
1564 pl->isComment = cl->isComment || (*cl->line == ';');
1569 /* for all the lines in the replacement pattern do */
1570 for (pl = pr->replace; pl; pl = pl->next)
1580 /* if the line contains a variable */
1581 if (*l == '%' && isdigit (*(l + 1)))
1583 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1586 fprintf (stderr, "used unbound variable in replacement\n");
1594 while (isdigit (*l)) {
1604 cl = connectLine (cl, newLineNode (lb));
1606 lhead = cl = newLineNode (lb);
1607 cl->isComment = pl->isComment;
1610 /* add the comments if any to the head of list */
1613 lineNode *lc = comment;
1624 /* determine which iCodes the replacment lines relate to */
1625 reassociate_ic(*shead,stail,lhead,cl);
1627 /* now we need to connect / replace the original chain */
1628 /* if there is a prev then change it */
1631 (*shead)->prev->next = lhead;
1632 lhead->prev = (*shead)->prev;
1635 /* now for the tail */
1636 if (stail && stail->next)
1638 stail->next->prev = cl;
1640 cl->next = stail->next;
1645 /* the replacement is empty - delete the source lines */
1647 (*shead)->prev->next = stail->next;
1649 stail->next->prev = (*shead)->prev;
1650 *shead = stail->next;
1654 /* Returns TRUE if this line is a label definition.
1656 * If so, start will point to the start of the label name,
1657 * and len will be it's length.
1660 isLabelDefinition (const char *line, const char **start, int *len)
1662 const char *cp = line;
1664 /* This line is a label if if consists of:
1665 * [optional whitespace] followed by identifier chars
1666 * (alnum | $ | _ ) followed by a colon.
1669 while (*cp && isspace (*cp))
1681 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1686 if ((cp == *start) || (*cp != ':'))
1691 *len = (cp - (*start));
1695 /* Quick & dirty string hash function. */
1697 hashSymbolName (const char *name)
1703 hash = (hash << 6) ^ *name;
1712 return hash % HTAB_SIZE;
1715 /* Build a hash of all labels in the passed set of lines
1716 * and how many times they are referenced.
1719 buildLabelRefCountHash (lineNode * head)
1726 assert (labelHash == NULL);
1727 labelHash = newHashTable (HTAB_SIZE);
1729 /* First pass: locate all the labels. */
1734 if (isLabelDefinition (line->line, &label, &labelLen)
1735 && labelLen <= SDCC_NAME_MAX)
1737 labelHashEntry *entry;
1739 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1741 memcpy (entry->name, label, labelLen);
1742 entry->name[labelLen] = 0;
1743 entry->refCount = -1;
1745 /* Assume function entry points are referenced somewhere, */
1746 /* even if we can't find a reference (might be from outside */
1748 if (line->ic && (line->ic->op == FUNCTION))
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 */
1845 /* don't waste time starting a match on debug symbol
1847 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1852 /* Tidy up any data stored in the hTab */
1855 if (matchRule (spl, &mtail, pr, *pls))
1860 replaceRule (pls, mtail, pr);
1862 replaceRule (&spl, mtail, pr);
1864 /* if restart rule type then
1865 start at the top again */
1874 hTabDeleteAll (pr->vars);
1875 Safe_free (pr->vars);
1879 freeTrace (&_G.values);
1882 } while (restart == TRUE);
1886 hTabDeleteAll (labelHash);
1887 freeTrace (&_G.labels);
1893 /*-----------------------------------------------------------------*/
1894 /* readFileIntoBuffer - reads a file into a string buffer */
1895 /*-----------------------------------------------------------------*/
1897 readFileIntoBuffer (char *fname)
1903 char lb[MAX_PATTERN_LEN];
1905 if (!(f = fopen (fname, "r")))
1907 fprintf (stderr, "cannot open peep rule file\n");
1911 while ((ch = fgetc (f)) != EOF)
1915 /* if we maxed out our local buffer */
1916 if (nch >= (MAX_PATTERN_LEN - 2))
1919 /* copy it into allocated buffer */
1922 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1923 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1927 rs = Safe_strdup (lb);
1933 /* if some charaters left over */
1937 /* copy it into allocated buffer */
1940 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1941 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1945 rs = Safe_strdup (lb);
1951 /*-----------------------------------------------------------------*/
1952 /* initPeepHole - initialises the peep hole optimizer stuff */
1953 /*-----------------------------------------------------------------*/
1959 /* read in the default rules */
1960 readRules (port->peep.default_rules);
1962 /* if we have any additional file read it too */
1963 if (options.peep_file)
1965 readRules (s = readFileIntoBuffer (options.peep_file));
1966 setToNull ((void *) &s);
1970 #if !OPT_DISABLE_PIC
1971 /* Convert the peep rules into pcode.
1972 NOTE: this is only support in the PIC port (at the moment)
1975 peepRules2pCode(rootRules);
1978 #if !OPT_DISABLE_PIC16
1979 /* Convert the peep rules into pcode.
1980 NOTE: this is only support in the PIC port (at the moment)
1981 and the PIC16 port (VR 030601)
1983 if (TARGET_IS_PIC16)
1984 pic16_peepRules2pCode(rootRules);