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 -------------------------------------------------------------------------*/
29 #include "SDCCglobl.h"
30 #include "SDCChasht.h"
32 #include "SDCCpeeph.h"
35 peepRule *rootRules = NULL;
36 peepRule *currRule = NULL;
40 #include "SDCCpeeph.rul"
43 static bool matchLine (char *, char *, hTab **);
45 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head)
47 /*-----------------------------------------------------------------*/
48 /* pcDistance - afinds a label back ward or forward */
49 /*-----------------------------------------------------------------*/
50 int pcDistance (lineNode *cpos, char *lbl, bool back)
53 char buff[MAX_PATTERN_LEN];
56 sprintf(buff,"%s:",lbl);
61 pl->line[strlen(pl->line)-1] != ':' &&
66 if (strncmp(pl->line,buff,strlen(buff)) == 0)
78 /*-----------------------------------------------------------------*/
79 /* labelInRange - will check to see if label %5 is within range */
80 /*-----------------------------------------------------------------*/
83 /* assumes that %5 pattern variable has the label name */
84 char *lbl = hTabItemWithKey(vars,5);
90 /* if the previous teo instructions are "ljmp"s then don't
91 do it since it can be part of a jump table */
92 if (currPl->prev && currPl->prev->prev &&
93 strstr(currPl->prev->line,"ljmp") &&
94 strstr(currPl->prev->prev->line,"ljmp"))
97 /* calculate the label distance : the jump for reladdr can be
98 +/- 127 bytes, here Iam assuming that an average 8051
99 instruction is 2 bytes long, so if the label is more than
100 63 intructions away, the label is considered out of range
101 for a relative jump. we could get more precise this will
102 suffice for now since it catches > 90% cases */
103 dist = (pcDistance(currPl,lbl,TRUE) +
104 pcDistance(currPl,lbl,FALSE)) ;
106 if (!dist || dist > 45)
112 /*-----------------------------------------------------------------*/
113 /* operandsNotSame - check if %1 & %2 are the same */
114 /*-----------------------------------------------------------------*/
115 FBYNAME(operandsNotSame)
117 char *op1 = hTabItemWithKey(vars,1);
118 char *op2 = hTabItemWithKey(vars,2);
120 if (strcmp(op1,op2) == 0)
126 /*-----------------------------------------------------------------*/
127 /* callFuncByName - calls a function as defined in the table */
128 /*-----------------------------------------------------------------*/
129 int callFuncByName ( char *fname,
136 int (*func)(hTab *,lineNode *,lineNode *) ;
138 {"labelInRange", labelInRange },
139 {"operandsNotSame", operandsNotSame }
143 for ( i = 0 ; i < ((sizeof (ftab))/(sizeof(struct ftab))); i++)
144 if (strcmp(ftab[i].fname,fname) == 0)
145 return (*ftab[i].func)(vars,currPl,head);
146 fprintf(stderr,"could not find named function in function table\n");
150 /*-----------------------------------------------------------------*/
151 /* printLine - prints a line chain into a given file */
152 /*-----------------------------------------------------------------*/
153 void printLine (lineNode *head, FILE *of)
159 /* don't indent comments & labels */
161 ( *head->line == ';' ||
162 head->line[strlen(head->line)-1] == ':'))
163 fprintf(of,"%s\n",head->line);
165 fprintf(of,"\t%s\n",head->line);
170 /*-----------------------------------------------------------------*/
171 /* newPeepRule - creates a new peeprule and attach it to the root */
172 /*-----------------------------------------------------------------*/
173 peepRule *newPeepRule (lineNode *match ,
180 ALLOC(pr,sizeof(peepRule));
182 pr->replace= replace;
183 pr->restart = restart;
186 ALLOC_ATOMIC(pr->cond,strlen(cond)+1);
187 strcpy(pr->cond,cond);
191 pr->vars = newHashTable(100);
193 /* if root is empty */
195 rootRules = currRule = pr;
197 currRule = currRule->next = pr;
202 /*-----------------------------------------------------------------*/
203 /* newLineNode - creates a new peep line */
204 /*-----------------------------------------------------------------*/
205 lineNode *newLineNode (char *line)
209 ALLOC(pl,sizeof(lineNode));
210 ALLOC_ATOMIC(pl->line,strlen(line)+1);
211 strcpy(pl->line,line);
215 /*-----------------------------------------------------------------*/
216 /* connectLine - connects two lines */
217 /*-----------------------------------------------------------------*/
218 lineNode *connectLine (lineNode *pl1, lineNode *pl2)
221 fprintf (stderr,"trying to connect null line\n");
231 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
232 if (!*x) { fprintf(stderr,y); return ; } }
234 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
235 if (!*x) { fprintf(stderr,z); return ; } }
236 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
237 if (!*x) { fprintf(stderr,z); return ; } }
239 /*-----------------------------------------------------------------*/
240 /* getPeepLine - parses the peep lines */
241 /*-----------------------------------------------------------------*/
242 static void getPeepLine (lineNode **head, char **bpp)
244 char lines[MAX_PATTERN_LEN];
247 lineNode *currL = NULL ;
252 fprintf(stderr,"unexpected end of match pattern\n");
258 while (isspace(*bp) ||
267 /* read till end of line */
269 while ((*bp != '\n' && *bp != '}' ) && *bp)
274 *head = currL = newLineNode (lines);
276 currL = connectLine(currL,newLineNode(lines));
282 /*-----------------------------------------------------------------*/
283 /* readRules - reads the rules from a string buffer */
284 /*-----------------------------------------------------------------*/
285 static void readRules (char *bp)
288 char lines[MAX_PATTERN_LEN];
292 lineNode *currL = NULL;
298 /* look for the token "replace" that is the
300 while (*bp && strncmp(bp,"replace",7)) bp++;
306 /* then look for either "restart" or '{' */
307 while (strncmp(bp,"restart",7) &&
308 *bp != '{' && bp ) bp++ ;
312 fprintf(stderr,"expected 'restart' or '{'\n");
319 else { /* must be restart */
321 bp += strlen("restart");
323 EXPECT_CHR(bp,'{',"expected '{'\n");
327 /* skip thru all the blank space */
328 SKIP_SPACE(bp,"unexpected end of rule\n");
330 match = replace = currL = NULL ;
331 /* we are the start of a rule */
332 getPeepLine(&match, &bp);
334 /* now look for by */
335 EXPECT_STR(bp,"by","expected 'by'\n");
337 /* then look for a '{' */
338 EXPECT_CHR(bp,'{',"expected '{'\n");
341 SKIP_SPACE(bp,"unexpected end of rule\n");
342 getPeepLine (&replace, &bp);
344 /* look for a 'if' */
345 while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
347 if (strncmp(bp,"if",2) == 0) {
349 while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
351 fprintf(stderr,"expected condition name\n");
355 /* look for the condition */
357 while (isalnum(*bp)) {
362 newPeepRule(match,replace,lines,restart);
364 newPeepRule(match,replace,NULL,restart);
369 /*-----------------------------------------------------------------*/
370 /* keyForVar - returns the numeric key for a var */
371 /*-----------------------------------------------------------------*/
372 static int keyForVar (char *d)
376 while (isdigit(*d)) {
384 /*-----------------------------------------------------------------*/
385 /* bindVar - binds a value to a variable in the given hashtable */
386 /*-----------------------------------------------------------------*/
387 static void bindVar (int key, char **s, hTab **vtab)
389 char vval[MAX_PATTERN_LEN];
393 /* first get the value of the variable */
395 /* the value is ended by a ',' or space or newline or null */
402 /* if we find a '(' then we need to balance it */
407 if (*vvx == '(') ubb++;
408 if (*vvx == ')') ubb--;
416 ALLOC_ATOMIC(vvx,strlen(vval)+1);
418 hTabAddItem(vtab,key,vvx);
422 /*-----------------------------------------------------------------*/
423 /* matchLine - matches one line */
424 /*-----------------------------------------------------------------*/
425 static bool matchLine (char *s, char *d, hTab **vars)
433 /* skip white space in both */
434 while (isspace(*s)) s++;
435 while (isspace(*d)) d++;
437 /* if the destination is a var */
438 if (*d == '%' && isdigit(*(d+1))) {
439 char *v = hTabItemWithKey(*vars,keyForVar(d+1));
440 /* if the variable is already bound
441 then it MUST match with dest */
444 if (*v++ != *s++) return FALSE;
446 /* variable not bound we need to
448 bindVar (keyForVar(d+1),&s,vars);
450 /* in either case go past the variable */
452 while (isdigit(*d)) d++;
455 /* they should be an exact match other wise */
457 while (isspace(*s))s++;
458 while (isspace(*d))d++;
465 /* get rid of the trailing spaces
466 in both source & destination */
468 while (isspace(*s)) s++;
471 while (isspace(*d)) d++;
473 /* after all this if only one of them
474 has something left over then no match */
481 /*-----------------------------------------------------------------*/
482 /* matchRule - matches a all the rule lines */
483 /*-----------------------------------------------------------------*/
484 static bool matchRule (lineNode *pl,
489 lineNode *spl ; /* source pl */
490 lineNode *rpl ; /* rule peep line */
492 hTabClearAll(pr->vars);
493 /* setToNull((void **) &pr->vars); */
494 /* pr->vars = newHashTable(100); */
496 /* for all the lines defined in the rule */
501 /* if the source line starts with a ';' then
502 comment line don't process or the source line
503 contains == . debugger information skip it */
505 (*spl->line == ';' || spl->isDebug)) {
510 if (!matchLine(spl->line,rpl->line,&pr->vars))
520 /* if this rule has additional conditions */
522 if (callFuncByName (pr->cond, pr->vars,pl,head) ) {
536 /*-----------------------------------------------------------------*/
537 /* replaceRule - does replacement of a matching pattern */
538 /*-----------------------------------------------------------------*/
539 static void replaceRule (lineNode **shead, lineNode *stail, peepRule *pr)
542 lineNode *pl = NULL , *lhead = NULL;
543 char lb[MAX_PATTERN_LEN];
545 lineNode *comment = NULL;
547 /* collect all the comment lines in the source */
548 for (cl = *shead ; cl != stail ; cl = cl->next) {
549 if (cl->line && ( *cl->line == ';' || cl->isDebug)) {
550 pl = (pl ? connectLine (pl,newLineNode(cl->line)) :
551 (comment = newLineNode(cl->line)));
552 pl->isDebug = cl->isDebug;
557 /* for all the lines in the replacement pattern do */
558 for ( pl = pr->replace ; pl ; pl = pl->next ) {
565 /* if the line contains a variable */
566 if (*l == '%' && isdigit(*(l+1))) {
567 v = hTabItemWithKey(pr->vars,keyForVar(l+1));
569 fprintf(stderr,"used unbound variable in replacement\n");
576 while (isdigit(*l)) l++;
584 cl = connectLine(cl,newLineNode(lb));
586 lhead = cl = newLineNode(lb);
589 /* add the comments if any to the head of list */
591 lineNode *lc = comment;
592 while (lc->next) lc = lc->next;
599 /* now we need to connect / replace the original chain */
600 /* if there is a prev then change it */
601 if ((*shead)->prev) {
602 (*shead)->prev->next = lhead;
603 lhead->prev = (*shead)->prev;
606 /* now for the tail */
607 if (stail && stail->next) {
608 stail->next->prev = cl;
610 cl->next = stail->next;
614 /*-----------------------------------------------------------------*/
615 /* peepHole - matches & substitutes rules */
616 /*-----------------------------------------------------------------*/
617 void peepHole (lineNode **pls )
621 lineNode *mtail = NULL;
625 for (pr = rootRules ; pr ; pr = pr->next ) {
627 for (spl = *pls ; spl ; spl = spl->next ) {
629 /* if inline assembler then no peep hole */
636 if (matchRule (spl,&mtail,pr, *pls)) {
640 replaceRule(pls, mtail, pr);
642 replaceRule (&spl, mtail,pr);
644 /* if it was the start then replace
647 /* if restart rule type then
648 start at the top again */
657 /*-----------------------------------------------------------------*/
658 /* readFileIntoBuffer - reads a file into a string buffer */
659 /*-----------------------------------------------------------------*/
660 static char *readFileIntoBuffer (char *fname)
666 char lb[MAX_PATTERN_LEN];
668 if (!(f = fopen(fname,"r"))) {
669 fprintf(stderr,"cannot open peep rule file\n");
673 while ((ch = fgetc(f)) != EOF) {
676 /* if we maxed out our local buffer */
677 if (nch >= (MAX_PATTERN_LEN - 2)) {
679 /* copy it into allocated buffer */
681 rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
684 ALLOC_ATOMIC(rs,strlen(lb)+1);
691 /* if some charaters left over */
694 /* copy it into allocated buffer */
696 rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
699 ALLOC_ATOMIC(rs,strlen(lb)+1);
706 /*-----------------------------------------------------------------*/
707 /* initPeepHole - initiaises the peep hole optimizer stuff */
708 /*-----------------------------------------------------------------*/
713 /* read in the default rules */
714 readRules(defaultRules);
716 /* if we have any additional file read it too */
717 if (options.peep_file) {
718 readRules(s=readFileIntoBuffer(options.peep_file));
719 setToNull((void **) &s);