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)
181 /*-----------------------------------------------------------------*/
182 /* labelIsReturnOnly - Check if label %5 is followed by RET */
183 /*-----------------------------------------------------------------*/
184 FBYNAME (labelIsReturnOnly)
186 /* assumes that %5 pattern variable has the label name */
187 const char *label, *p;
191 label = hTabItemWithKey (vars, 5);
192 if (!label) return FALSE;
195 for(pl = currPl; pl; pl = pl->next) {
196 if (pl->line && !pl->isDebug &&
197 pl->line[strlen(pl->line)-1] == ':') {
198 if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
199 if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) ||
200 !isdigit(*(pl->line+1)) || !isdigit(*(pl->line+2)) ||
201 !isdigit(*(pl->line+3)) || !isdigit(*(pl->line+4)) ||
202 *(pl->line+5) != '$') {
203 return FALSE; /* non-local label encountered */
207 if (!pl) return FALSE; /* did not find the label */
209 if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */
211 for (p = pl->line; *p && isspace(*p); p++)
213 if (strcmp(p, "ret") == 0) return TRUE;
218 /*-----------------------------------------------------------------*/
219 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
220 /* usage of it in the code depends on a value from this section */
221 /*-----------------------------------------------------------------*/
222 FBYNAME (okToRemoveSLOC)
225 const char *sloc, *p;
226 int dummy1, dummy2, dummy3;
228 /* assumes that %1 as the SLOC name */
229 sloc = hTabItemWithKey (vars, 1);
230 if (sloc == NULL) return FALSE;
231 p = strstr(sloc, "sloc");
232 if (p == NULL) return FALSE;
234 if (sscanf(p, "%d_%d_%d", &dummy1, &dummy2, &dummy3) != 3) return FALSE;
235 /*TODO: ultra-paranoid: get funtion name from "head" and check that */
236 /* the sloc name begins with that. Probably not really necessary */
238 /* Look for any occurance of this SLOC before the peephole match */
239 for (pl = currPl->prev; pl; pl = pl->prev) {
240 if (pl->line && !pl->isDebug && !pl->isComment
241 && *pl->line != ';' && strstr(pl->line, sloc))
244 /* Look for any occurance of this SLOC after the peephole match */
245 for (pl = endPl->next; pl; pl = pl->next) {
246 if (pl->line && !pl->isDebug && !pl->isComment
247 && *pl->line != ';' && strstr(pl->line, sloc))
250 return TRUE; /* safe for a peephole to remove it :) */
254 /*-----------------------------------------------------------------*/
255 /* operandsNotSame - check if %1 & %2 are the same */
256 /*-----------------------------------------------------------------*/
257 FBYNAME (operandsNotSame)
259 char *op1 = hTabItemWithKey (vars, 1);
260 char *op2 = hTabItemWithKey (vars, 2);
262 if (strcmp (op1, op2) == 0)
268 /*-----------------------------------------------------------------*/
269 /* operandsNotSame3- check if any pair of %1,%2,%3 are the same */
270 /*-----------------------------------------------------------------*/
271 FBYNAME (operandsNotSame3)
273 char *op1 = hTabItemWithKey (vars, 1);
274 char *op2 = hTabItemWithKey (vars, 2);
275 char *op3 = hTabItemWithKey (vars, 3);
277 if ( (strcmp (op1, op2) == 0) ||
278 (strcmp (op1, op3) == 0) ||
279 (strcmp (op2, op3) == 0) )
285 /*-----------------------------------------------------------------*/
286 /* operandsNotSame4- check if any pair of %1,%2,%3,.. are the same */
287 /*-----------------------------------------------------------------*/
288 FBYNAME (operandsNotSame4)
290 char *op1 = hTabItemWithKey (vars, 1);
291 char *op2 = hTabItemWithKey (vars, 2);
292 char *op3 = hTabItemWithKey (vars, 3);
293 char *op4 = hTabItemWithKey (vars, 4);
295 if ( (strcmp (op1, op2) == 0) ||
296 (strcmp (op1, op3) == 0) ||
297 (strcmp (op1, op4) == 0) ||
298 (strcmp (op2, op3) == 0) ||
299 (strcmp (op2, op4) == 0) ||
300 (strcmp (op3, op4) == 0) )
306 /*-----------------------------------------------------------------*/
307 /* operandsNotSame5- check if any pair of %1,%2,%3,.. are the same */
308 /*-----------------------------------------------------------------*/
309 FBYNAME (operandsNotSame5)
311 char *op1 = hTabItemWithKey (vars, 1);
312 char *op2 = hTabItemWithKey (vars, 2);
313 char *op3 = hTabItemWithKey (vars, 3);
314 char *op4 = hTabItemWithKey (vars, 4);
315 char *op5 = hTabItemWithKey (vars, 5);
317 if ( (strcmp (op1, op2) == 0) ||
318 (strcmp (op1, op3) == 0) ||
319 (strcmp (op1, op4) == 0) ||
320 (strcmp (op1, op5) == 0) ||
321 (strcmp (op2, op3) == 0) ||
322 (strcmp (op2, op4) == 0) ||
323 (strcmp (op2, op5) == 0) ||
324 (strcmp (op3, op4) == 0) ||
325 (strcmp (op3, op5) == 0) ||
326 (strcmp (op4, op5) == 0) )
332 /*-----------------------------------------------------------------*/
333 /* operandsNotSame6- check if any pair of %1,%2,%3,.. are the same */
334 /*-----------------------------------------------------------------*/
335 FBYNAME (operandsNotSame6)
337 char *op1 = hTabItemWithKey (vars, 1);
338 char *op2 = hTabItemWithKey (vars, 2);
339 char *op3 = hTabItemWithKey (vars, 3);
340 char *op4 = hTabItemWithKey (vars, 4);
341 char *op5 = hTabItemWithKey (vars, 5);
342 char *op6 = hTabItemWithKey (vars, 6);
344 if ( (strcmp (op1, op2) == 0) ||
345 (strcmp (op1, op3) == 0) ||
346 (strcmp (op1, op4) == 0) ||
347 (strcmp (op1, op5) == 0) ||
348 (strcmp (op1, op6) == 0) ||
349 (strcmp (op2, op3) == 0) ||
350 (strcmp (op2, op4) == 0) ||
351 (strcmp (op2, op5) == 0) ||
352 (strcmp (op2, op6) == 0) ||
353 (strcmp (op3, op4) == 0) ||
354 (strcmp (op3, op5) == 0) ||
355 (strcmp (op3, op6) == 0) ||
356 (strcmp (op4, op5) == 0) ||
357 (strcmp (op4, op6) == 0) ||
358 (strcmp (op5, op6) == 0) )
365 /*-----------------------------------------------------------------*/
366 /* operandsNotSame7- check if any pair of %1,%2,%3,.. are the same */
367 /*-----------------------------------------------------------------*/
368 FBYNAME (operandsNotSame7)
370 char *op1 = hTabItemWithKey (vars, 1);
371 char *op2 = hTabItemWithKey (vars, 2);
372 char *op3 = hTabItemWithKey (vars, 3);
373 char *op4 = hTabItemWithKey (vars, 4);
374 char *op5 = hTabItemWithKey (vars, 5);
375 char *op6 = hTabItemWithKey (vars, 6);
376 char *op7 = hTabItemWithKey (vars, 7);
378 if ( (strcmp (op1, op2) == 0) ||
379 (strcmp (op1, op3) == 0) ||
380 (strcmp (op1, op4) == 0) ||
381 (strcmp (op1, op5) == 0) ||
382 (strcmp (op1, op6) == 0) ||
383 (strcmp (op1, op7) == 0) ||
384 (strcmp (op2, op3) == 0) ||
385 (strcmp (op2, op4) == 0) ||
386 (strcmp (op2, op5) == 0) ||
387 (strcmp (op2, op6) == 0) ||
388 (strcmp (op2, op7) == 0) ||
389 (strcmp (op3, op4) == 0) ||
390 (strcmp (op3, op5) == 0) ||
391 (strcmp (op3, op6) == 0) ||
392 (strcmp (op3, op7) == 0) ||
393 (strcmp (op4, op5) == 0) ||
394 (strcmp (op4, op6) == 0) ||
395 (strcmp (op4, op7) == 0) ||
396 (strcmp (op5, op6) == 0) ||
397 (strcmp (op5, op7) == 0) ||
398 (strcmp (op6, op7) == 0) )
404 /*-----------------------------------------------------------------*/
405 /* operandsNotSame8- check if any pair of %1,%2,%3,.. are the same */
406 /*-----------------------------------------------------------------*/
407 FBYNAME (operandsNotSame8)
409 char *op1 = hTabItemWithKey (vars, 1);
410 char *op2 = hTabItemWithKey (vars, 2);
411 char *op3 = hTabItemWithKey (vars, 3);
412 char *op4 = hTabItemWithKey (vars, 4);
413 char *op5 = hTabItemWithKey (vars, 5);
414 char *op6 = hTabItemWithKey (vars, 6);
415 char *op7 = hTabItemWithKey (vars, 7);
416 char *op8 = hTabItemWithKey (vars, 8);
418 if ( (strcmp (op1, op2) == 0) ||
419 (strcmp (op1, op3) == 0) ||
420 (strcmp (op1, op4) == 0) ||
421 (strcmp (op1, op5) == 0) ||
422 (strcmp (op1, op6) == 0) ||
423 (strcmp (op1, op7) == 0) ||
424 (strcmp (op1, op8) == 0) ||
425 (strcmp (op2, op3) == 0) ||
426 (strcmp (op2, op4) == 0) ||
427 (strcmp (op2, op5) == 0) ||
428 (strcmp (op2, op6) == 0) ||
429 (strcmp (op2, op7) == 0) ||
430 (strcmp (op2, op8) == 0) ||
431 (strcmp (op3, op4) == 0) ||
432 (strcmp (op3, op5) == 0) ||
433 (strcmp (op3, op6) == 0) ||
434 (strcmp (op3, op7) == 0) ||
435 (strcmp (op3, op8) == 0) ||
436 (strcmp (op4, op5) == 0) ||
437 (strcmp (op4, op6) == 0) ||
438 (strcmp (op4, op7) == 0) ||
439 (strcmp (op4, op8) == 0) ||
440 (strcmp (op5, op6) == 0) ||
441 (strcmp (op5, op7) == 0) ||
442 (strcmp (op5, op8) == 0) ||
443 (strcmp (op6, op7) == 0) ||
444 (strcmp (op6, op8) == 0) ||
445 (strcmp (op7, op8) == 0) )
454 * takes two parameters: a variable (bound to a label name)
455 * and an expected reference count.
457 * Returns TRUE if that label is defined and referenced exactly
458 * the given number of times.
460 FBYNAME (labelRefCount)
462 int varNumber, expectedRefCount;
465 /* If we don't have the label hash table yet, build it. */
468 buildLabelRefCountHash (head);
471 if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2)
473 char *label = hTabItemWithKey (vars, varNumber);
477 labelHashEntry *entry;
479 entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
483 if (!strcmp (label, entry->name))
487 entry = hTabNextItemWK (labelHash);
493 fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n",
494 label, entry->refCount, expectedRefCount);
497 rc = (expectedRefCount == entry->refCount);
501 fprintf (stderr, "*** internal error: no label has entry for"
502 " %s in labelRefCount peephole.\n",
508 fprintf (stderr, "*** internal error: var %d not bound"
509 " in peephole labelRefCount rule.\n",
517 "*** internal error: labelRefCount peephole restriction"
518 " malformed: %s\n", cmdLine);
523 /* Within the context of the lines currPl through endPl, determine
524 ** if the variable var contains a symbol that is volatile. Returns
525 ** TRUE only if it is certain that this was not volatile (the symbol
526 ** was found and not volatile, or var was a constant or CPU register).
527 ** Returns FALSE if the symbol was found and volatile, the symbol was
528 ** not found, or var was a indirect/pointer addressing mode.
531 notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
533 char symname[SDCC_NAME_MAX + 1];
540 /* Can't tell if indirect accesses are volatile or not, so
541 ** assume they are, just to be safe.
543 if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
548 if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
550 if (strstr(var,"(bc)"))
552 if (strstr(var,"(de)"))
554 if (strstr(var,"(hl)"))
556 if (strstr(var,"(ix"))
558 if (strstr(var,"(iy"))
562 /* Extract a symbol name from the variable */
563 while (*vp && (*vp!='_'))
565 while (*vp && (isalnum(*vp) || *vp=='_'))
571 /* Nothing resembling a symbol name was found, so it can't
578 for (cl = currPl; cl!=endPl->next; cl = cl->next)
580 if (cl->ic && (cl->ic!=last_ic))
586 op = IC_COND (cl->ic);
587 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
588 return !op->isvolatile;
590 op = IC_JTCOND (cl->ic);
591 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
592 return !op->isvolatile;
594 op = IC_LEFT (cl->ic);
595 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
596 return !op->isvolatile;
597 op = IC_RIGHT (cl->ic);
598 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
599 return !op->isvolatile;
600 op = IC_RESULT (cl->ic);
601 if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
602 return !op->isvolatile;
607 /* Couldn't find the symbol for some reason. Assume volatile. */
613 * This rule restriction has two different behaviours depending on
614 * the number of parameters given.
616 * if notVolatile (no parameters given)
617 * The rule is applied only if none of the iCodes originating
618 * the matched pattern reference a volatile operand.
620 * if notVolatile %1 ... (one or more parameters given)
621 * The rule is applied if the parameters are not expressions
622 * containing volatile symbols and are not pointer accesses.
625 FBYNAME (notVolatile)
636 /* If no parameters given, just scan the iCodes for volatile operands */
637 for (cl = currPl; cl!=endPl->next; cl = cl->next)
644 op = IC_COND (cl->ic);
645 if (IS_SYMOP (op) && op->isvolatile)
648 op = IC_JTCOND (cl->ic);
649 if (IS_SYMOP (op) && op->isvolatile)
652 op = IC_LEFT (cl->ic);
653 if (IS_SYMOP (op) && op->isvolatile)
655 op = IC_RIGHT (cl->ic);
656 if (IS_SYMOP (op) && op->isvolatile)
658 op = IC_RESULT (cl->ic);
659 if (IS_SYMOP (op) && op->isvolatile)
667 /* There were parameters; check the volatility of each */
668 while (*cmdLine && isspace(*cmdLine))
675 if (!isdigit(*cmdLine))
677 varNumber = strtol(cmdLine, &digitend, 10);
679 while (*cmdLine && isspace(*cmdLine))
682 var = hTabItemWithKey (vars, varNumber);
686 notvol = notVolatileVariable (var, currPl, endPl);
692 fprintf (stderr, "*** internal error: var %d not bound"
693 " in peephole notVolatile rule.\n",
704 "*** internal error: notVolatile peephole restriction"
705 " malformed: %s\n", cmdLine);
710 /*-----------------------------------------------------------------*/
711 /* callFuncByName - calls a function as defined in the table */
712 /*-----------------------------------------------------------------*/
714 callFuncByName (char *fname,
723 int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *);
728 "labelInRange", labelInRange
732 "operandsNotSame", operandsNotSame
736 "operandsNotSame3", operandsNotSame3
740 "operandsNotSame4", operandsNotSame4
744 "operandsNotSame5", operandsNotSame5
748 "operandsNotSame6", operandsNotSame6
752 "operandsNotSame7", operandsNotSame7
756 "operandsNotSame8", operandsNotSame8
760 "24bitMode", flat24bitMode
764 "xramMovcOption", xramMovcOption
768 "labelRefCount", labelRefCount
772 "portIsDS390", portIsDS390
775 "labelIsReturnOnly", labelIsReturnOnly
778 "okToRemoveSLOC", okToRemoveSLOC
781 "24bitModeAndPortDS390", flat24bitModeAndPortDS390
784 "notVolatile", notVolatile
788 char *cmdCopy, *funcName, *funcArgs;
791 /* Isolate the function name part (we are passed the full condition
792 * string including arguments)
794 cmdCopy = Safe_strdup(fname);
795 funcName = strtok(cmdCopy, " \t");
796 funcArgs = strtok(NULL, "");
798 for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++)
800 if (strcmp (ftab[i].fname, funcName) == 0)
802 rc = (*ftab[i].func) (vars, currPl, endPl, head,
810 "could not find named function \"%s\" in "
811 "peephole function table\n",
813 // If the function couldn't be found, let's assume it's
814 // a bad rule and refuse it.
823 /*-----------------------------------------------------------------*/
824 /* printLine - prints a line chain into a given file */
825 /*-----------------------------------------------------------------*/
827 printLine (lineNode * head, FILE * of)
829 iCode *last_ic = NULL;
830 bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
837 if (head->ic!=last_ic)
840 if (debug_iCode_tracking)
843 fprintf (of, "; block = %d, seq = %d\n",
844 head->ic->block, head->ic->seq);
846 fprintf (of, "; iCode lost\n");
850 /* don't indent comments & labels */
852 (*head->line == ';' ||
853 head->line[strlen (head->line) - 1] == ':')) {
854 fprintf (of, "%s\n", head->line);
856 if (head->isInline && *head->line=='#') {
857 // comment out preprocessor directives in inline asm
860 fprintf (of, "\t%s\n", head->line);
866 /*-----------------------------------------------------------------*/
867 /* newPeepRule - creates a new peeprule and attach it to the root */
868 /*-----------------------------------------------------------------*/
870 newPeepRule (lineNode * match,
877 pr = Safe_alloc ( sizeof (peepRule));
879 pr->replace = replace;
880 pr->restart = restart;
884 pr->cond = Safe_strdup (cond);
889 pr->vars = newHashTable (100);
891 /* if root is empty */
893 rootRules = currRule = pr;
895 currRule = currRule->next = pr;
900 /*-----------------------------------------------------------------*/
901 /* newLineNode - creates a new peep line */
902 /*-----------------------------------------------------------------*/
904 newLineNode (char *line)
908 pl = Safe_alloc ( sizeof (lineNode));
909 pl->line = Safe_strdup (line);
914 /*-----------------------------------------------------------------*/
915 /* connectLine - connects two lines */
916 /*-----------------------------------------------------------------*/
918 connectLine (lineNode * pl1, lineNode * pl2)
922 fprintf (stderr, "trying to connect null line\n");
932 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
933 if (!*x) { fprintf(stderr,y); return ; } }
935 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
936 if (!*x) { fprintf(stderr,z); return ; } }
937 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
938 if (!*x) { fprintf(stderr,z); return ; } }
940 /*-----------------------------------------------------------------*/
941 /* getPeepLine - parses the peep lines */
942 /*-----------------------------------------------------------------*/
944 getPeepLine (lineNode ** head, char **bpp)
946 char lines[MAX_PATTERN_LEN];
950 lineNode *currL = NULL;
957 fprintf (stderr, "unexpected end of match pattern\n");
964 while (isspace (*bp) ||
975 /* read till end of line */
977 while ((*bp != '\n' && *bp != '}') && *bp)
982 while (*lp && isspace(*lp))
984 isComment = (*lp == ';');
986 if (!isComment || (isComment && !options.noPeepComments))
989 *head = currL = newLineNode (lines);
991 currL = connectLine (currL, newLineNode (lines));
992 currL->isComment = isComment;
1000 /*-----------------------------------------------------------------*/
1001 /* readRules - reads the rules from a string buffer */
1002 /*-----------------------------------------------------------------*/
1004 readRules (char *bp)
1007 char lines[MAX_PATTERN_LEN];
1011 lineNode *currL = NULL;
1017 /* look for the token "replace" that is the
1019 while (*bp && strncmp (bp, "replace", 7))
1026 /* then look for either "restart" or '{' */
1027 while (strncmp (bp, "restart", 7) &&
1034 fprintf (stderr, "expected 'restart' or '{'\n");
1042 { /* must be restart */
1044 bp += strlen ("restart");
1046 EXPECT_CHR (bp, '{', "expected '{'\n");
1050 /* skip thru all the blank space */
1051 SKIP_SPACE (bp, "unexpected end of rule\n");
1053 match = replace = currL = NULL;
1054 /* we are the start of a rule */
1055 getPeepLine (&match, &bp);
1057 /* now look for by */
1058 EXPECT_STR (bp, "by", "expected 'by'\n");
1060 /* then look for a '{' */
1061 EXPECT_CHR (bp, '{', "expected '{'\n");
1064 SKIP_SPACE (bp, "unexpected end of rule\n");
1065 getPeepLine (&replace, &bp);
1067 /* look for a 'if' */
1068 while ((isspace (*bp) || *bp == '\n') && *bp)
1071 if (strncmp (bp, "if", 2) == 0)
1074 while ((isspace (*bp) || *bp == '\n') && *bp)
1078 fprintf (stderr, "expected condition name\n");
1082 /* look for the condition */
1084 while (*bp && (*bp != '\n'))
1090 newPeepRule (match, replace, lines, restart);
1093 newPeepRule (match, replace, NULL, restart);
1098 /*-----------------------------------------------------------------*/
1099 /* keyForVar - returns the numeric key for a var */
1100 /*-----------------------------------------------------------------*/
1106 while (isdigit (*d))
1115 /*-----------------------------------------------------------------*/
1116 /* bindVar - binds a value to a variable in the given hashtable */
1117 /*-----------------------------------------------------------------*/
1119 bindVar (int key, char **s, hTab ** vtab)
1121 char vval[MAX_PATTERN_LEN];
1125 /* first get the value of the variable */
1127 /* the value is ended by a ',' or space or newline or null or ) */
1136 /* if we find a '(' then we need to balance it */
1148 // include the trailing ')'
1157 vvx = traceAlloc (&_G.values, Safe_strdup(vval));
1159 hTabAddItem (vtab, key, vvx);
1162 /*-----------------------------------------------------------------*/
1163 /* matchLine - matches one line */
1164 /*-----------------------------------------------------------------*/
1166 matchLine (char *s, char *d, hTab ** vars)
1175 /* skip white space in both */
1176 while (isspace (*s))
1178 while (isspace (*d))
1181 /* if the destination is a var */
1182 if (*d == '%' && isdigit (*(d + 1)) && vars)
1184 char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
1185 /* if the variable is already bound
1186 then it MUST match with dest */
1194 /* variable not bound we need to
1196 bindVar (keyForVar (d + 1), &s, vars);
1198 /* in either case go past the variable */
1200 while (isdigit (*d))
1203 while (isspace (*s))
1205 while (isspace (*d))
1209 /* they should be an exact match other wise */
1218 /* get rid of the trailing spaces
1219 in both source & destination */
1221 while (isspace (*s))
1225 while (isspace (*d))
1228 /* after all this if only one of them
1229 has something left over then no match */
1236 /*-----------------------------------------------------------------*/
1237 /* matchRule - matches a all the rule lines */
1238 /*-----------------------------------------------------------------*/
1240 matchRule (lineNode * pl,
1245 lineNode *spl; /* source pl */
1246 lineNode *rpl; /* rule peep line */
1248 /* setToNull((void *) &pr->vars); */
1249 /* pr->vars = newHashTable(100); */
1251 /* for all the lines defined in the rule */
1257 /* if the source line starts with a ';' then
1258 comment line don't process or the source line
1259 contains == . debugger information skip it */
1261 (*spl->line == ';' || spl->isDebug))
1267 if (!matchLine (spl->line, rpl->line, &pr->vars))
1275 /* if rules ended */
1278 /* if this rule has additional conditions */
1281 if (callFuncByName (pr->cond, pr->vars, pl, spl, head))
1300 reassociate_ic_down (lineNode *shead, lineNode *stail,
1301 lineNode *rhead, lineNode *rtail)
1303 lineNode *csl; /* current source line */
1304 lineNode *crl; /* current replacement line */
1310 /* skip over any comments */
1311 while (csl!=stail->next && csl->isComment)
1313 while (crl!=rtail->next && crl->isComment)
1316 /* quit if we reach the end */
1317 if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
1320 if (matchLine(csl->line,crl->line,NULL))
1332 reassociate_ic_up (lineNode *shead, lineNode *stail,
1333 lineNode *rhead, lineNode *rtail)
1335 lineNode *csl; /* current source line */
1336 lineNode *crl; /* current replacement line */
1342 /* skip over any comments */
1343 while (csl!=shead->prev && csl->isComment)
1345 while (crl!=rhead->prev && crl->isComment)
1348 /* quit if we reach the end */
1349 if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
1352 if (matchLine(csl->line,crl->line,NULL))
1363 /*------------------------------------------------------------------*/
1364 /* reassociate_ic - reassociate replacement lines with origin iCode */
1365 /*------------------------------------------------------------------*/
1367 reassociate_ic (lineNode *shead, lineNode *stail,
1368 lineNode *rhead, lineNode *rtail)
1370 lineNode *csl; /* current source line */
1371 lineNode *crl; /* current replacement line */
1375 /* Check to see if all the source lines (excluding comments) came
1376 ** for the same iCode
1379 for (csl=shead;csl!=stail->next;csl=csl->next)
1380 if (csl->ic && !csl->isComment)
1385 single_iCode = (ic!=NULL);
1386 for (csl=shead;csl!=stail->next;csl=csl->next)
1387 if ((csl->ic != ic) && !csl->isComment)
1389 /* More than one iCode was found. However, if it's just the
1390 ** last line with the different iCode and it was not changed
1391 ** in the replacement, everything else must be the first iCode.
1393 if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
1395 rtail->ic = stail->ic;
1396 for (crl=rhead;crl!=rtail;crl=crl->next)
1401 single_iCode = FALSE;
1405 /* If all of the source lines came from the same iCode, then so have
1406 ** all of the replacement lines too.
1410 for (crl=rhead;crl!=rtail->next;crl=crl->next)
1415 /* The source lines span iCodes, so we may end up with replacement
1416 ** lines that we don't know which iCode(s) to associate with. Do the
1417 ** best we can by using the following strategies:
1418 ** 1) Start at the top and scan down. As long as the source line
1419 ** matches the replacement line, they have the same iCode.
1420 ** 2) Start at the bottom and scan up. As long as the source line
1421 ** matches the replacement line, they have the same iCode.
1422 ** 3) For any label in the source, look for a matching label in
1423 ** the replacment. If found, they have the same iCode. From
1424 ** these matching labels, scan down for additional matching
1425 ** lines; if found, they also have the same iCode.
1428 /* Strategy #1: Start at the top and scan down for matches
1430 reassociate_ic_down(shead,stail,rhead,rtail);
1432 /* Strategy #2: Start at the bottom and scan up for matches
1434 reassociate_ic_up(shead,stail,rhead,rtail);
1436 /* Strategy #3: Try to match labels
1441 const char *labelStart;
1444 /* skip over any comments */
1445 while (csl!=stail->next && csl->isComment)
1447 if (csl==stail->next)
1450 if (isLabelDefinition(csl->line, &labelStart, &labelLength))
1452 /* found a source line label; look for it in the replacment lines */
1456 while (crl!=rtail->next && crl->isComment)
1458 if (crl==rtail->next)
1460 if (matchLine(csl->line, crl->line, NULL))
1462 reassociate_ic_down(csl,stail,crl,rtail);
1472 /* Try to assign a meaningful iCode to any comment that is missing
1473 one. Since they are comments, it's ok to make mistakes; we are just
1474 trying to improve continuity to simplify other tests.
1477 for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
1479 if (!crl->ic && ic && crl->isComment)
1486 /*-----------------------------------------------------------------*/
1487 /* replaceRule - does replacement of a matching pattern */
1488 /*-----------------------------------------------------------------*/
1490 replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr)
1492 lineNode *cl = NULL;
1493 lineNode *pl = NULL, *lhead = NULL;
1494 /* a long function name and long variable name can evaluate to
1495 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
1496 char lb[MAX_PATTERN_LEN*4];
1498 lineNode *comment = NULL;
1500 /* collect all the comment lines in the source */
1501 for (cl = *shead; cl != stail; cl = cl->next)
1503 if (cl->line && (*cl->line == ';' || cl->isDebug))
1505 pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
1506 (comment = newLineNode (cl->line)));
1507 pl->isDebug = cl->isDebug;
1508 pl->isComment = cl->isComment || (*cl->line == ';');
1513 /* for all the lines in the replacement pattern do */
1514 for (pl = pr->replace; pl; pl = pl->next)
1524 /* if the line contains a variable */
1525 if (*l == '%' && isdigit (*(l + 1)))
1527 v = hTabItemWithKey (pr->vars, keyForVar (l + 1));
1530 fprintf (stderr, "used unbound variable in replacement\n");
1538 while (isdigit (*l)) {
1548 cl = connectLine (cl, newLineNode (lb));
1550 lhead = cl = newLineNode (lb);
1551 cl->isComment = pl->isComment;
1554 /* add the comments if any to the head of list */
1557 lineNode *lc = comment;
1568 /* determine which iCodes the replacment lines relate to */
1569 reassociate_ic(*shead,stail,lhead,cl);
1571 /* now we need to connect / replace the original chain */
1572 /* if there is a prev then change it */
1575 (*shead)->prev->next = lhead;
1576 lhead->prev = (*shead)->prev;
1579 /* now for the tail */
1580 if (stail && stail->next)
1582 stail->next->prev = cl;
1584 cl->next = stail->next;
1589 /* the replacement is empty - delete the source lines */
1591 (*shead)->prev->next = stail->next;
1593 stail->next->prev = (*shead)->prev;
1594 *shead = stail->next;
1598 /* Returns TRUE if this line is a label definition.
1600 * If so, start will point to the start of the label name,
1601 * and len will be it's length.
1604 isLabelDefinition (const char *line, const char **start, int *len)
1606 const char *cp = line;
1608 /* This line is a label if if consists of:
1609 * [optional whitespace] followed by identifier chars
1610 * (alnum | $ | _ ) followed by a colon.
1613 while (*cp && isspace (*cp))
1625 while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
1630 if ((cp == *start) || (*cp != ':'))
1635 *len = (cp - (*start));
1639 /* Quick & dirty string hash function. */
1641 hashSymbolName (const char *name)
1647 hash = (hash << 6) ^ *name;
1656 return hash % HTAB_SIZE;
1659 /* Build a hash of all labels in the passed set of lines
1660 * and how many times they are referenced.
1663 buildLabelRefCountHash (lineNode * head)
1670 assert (labelHash == NULL);
1671 labelHash = newHashTable (HTAB_SIZE);
1673 /* First pass: locate all the labels. */
1678 if (isLabelDefinition (line->line, &label, &labelLen)
1679 && labelLen <= SDCC_NAME_MAX)
1681 labelHashEntry *entry;
1683 entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
1685 memcpy (entry->name, label, labelLen);
1686 entry->name[labelLen] = 0;
1687 entry->refCount = -1;
1689 hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
1695 /* Second pass: for each line, note all the referenced labels. */
1696 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
1700 for (i = 0; i < HTAB_SIZE; i++)
1702 labelHashEntry *thisEntry;
1704 thisEntry = hTabFirstItemWK (labelHash, i);
1708 if (strstr (line->line, thisEntry->name))
1710 thisEntry->refCount++;
1712 thisEntry = hTabNextItemWK (labelHash);
1719 /* Spew the contents of the table. Debugging fun only. */
1720 for (i = 0; i < HTAB_SIZE; i++)
1722 labelHashEntry *thisEntry;
1724 thisEntry = hTabFirstItemWK (labelHash, i);
1728 fprintf (stderr, "label: %s ref %d\n",
1729 thisEntry->name, thisEntry->refCount);
1730 thisEntry = hTabNextItemWK (labelHash);
1736 /* How does this work?
1742 replace and restart.
1747 Where is stuff allocated?
1751 /*-----------------------------------------------------------------*/
1752 /* peepHole - matches & substitutes rules */
1753 /*-----------------------------------------------------------------*/
1755 peepHole (lineNode ** pls)
1759 lineNode *mtail = NULL;
1762 #if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
1763 /* The PIC port uses a different peep hole optimizer based on "pCode" */
1764 if (TARGET_IS_PIC || TARGET_IS_PIC16)
1768 assert(labelHash == NULL);
1775 for (pr = rootRules; pr; pr = pr->next)
1777 for (spl = *pls; spl; spl = spl->next)
1779 /* if inline assembler then no peep hole */
1783 /* don't waste time starting a match on debug symbol
1785 if (spl->isDebug || spl->isComment || *(spl->line)==';')
1790 /* Tidy up any data stored in the hTab */
1793 if (matchRule (spl, &mtail, pr, *pls))
1798 replaceRule (pls, mtail, pr);
1800 replaceRule (&spl, mtail, pr);
1802 /* if restart rule type then
1803 start at the top again */
1812 hTabDeleteAll (pr->vars);
1813 Safe_free (pr->vars);
1817 freeTrace (&_G.values);
1820 } while (restart == TRUE);
1824 hTabDeleteAll (labelHash);
1825 freeTrace (&_G.labels);
1831 /*-----------------------------------------------------------------*/
1832 /* readFileIntoBuffer - reads a file into a string buffer */
1833 /*-----------------------------------------------------------------*/
1835 readFileIntoBuffer (char *fname)
1841 char lb[MAX_PATTERN_LEN];
1843 if (!(f = fopen (fname, "r")))
1845 fprintf (stderr, "cannot open peep rule file\n");
1849 while ((ch = fgetc (f)) != EOF)
1853 /* if we maxed out our local buffer */
1854 if (nch >= (MAX_PATTERN_LEN - 2))
1857 /* copy it into allocated buffer */
1860 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1861 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1865 rs = Safe_strdup (lb);
1871 /* if some charaters left over */
1875 /* copy it into allocated buffer */
1878 rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1);
1879 strncatz (rs, lb, strlen (rs) + strlen (lb) + 1);
1883 rs = Safe_strdup (lb);
1889 /*-----------------------------------------------------------------*/
1890 /* initPeepHole - initialises the peep hole optimizer stuff */
1891 /*-----------------------------------------------------------------*/
1897 /* read in the default rules */
1898 readRules (port->peep.default_rules);
1900 /* if we have any additional file read it too */
1901 if (options.peep_file)
1903 readRules (s = readFileIntoBuffer (options.peep_file));
1904 setToNull ((void *) &s);
1908 #if !OPT_DISABLE_PIC
1909 /* Convert the peep rules into pcode.
1910 NOTE: this is only support in the PIC port (at the moment)
1913 peepRules2pCode(rootRules);
1916 #if !OPT_DISABLE_PIC16
1917 /* Convert the peep rules into pcode.
1918 NOTE: this is only support in the PIC port (at the moment)
1919 and the PIC16 port (VR 030601)
1921 if (TARGET_IS_PIC16)
1922 pic16_peepRules2pCode(rootRules);