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 -------------------------------------------------------------------------*/
27 #include "SDCCpeeph.h"
29 peepRule *rootRules = NULL;
30 peepRule *currRule = NULL;
32 static bool matchLine (char *, char *, hTab **);
34 #define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head)
36 /*-----------------------------------------------------------------*/
37 /* pcDistance - afinds a label back ward or forward */
38 /*-----------------------------------------------------------------*/
39 int pcDistance (lineNode *cpos, char *lbl, bool back)
42 char buff[MAX_PATTERN_LEN];
45 sprintf(buff,"%s:",lbl);
50 pl->line[strlen(pl->line)-1] != ':' &&
55 if (strncmp(pl->line,buff,strlen(buff)) == 0)
67 /*-----------------------------------------------------------------*/
68 /* labelInRange - will check to see if label %5 is within range */
69 /*-----------------------------------------------------------------*/
72 /* assumes that %5 pattern variable has the label name */
73 char *lbl = hTabItemWithKey(vars,5);
79 /* if the previous teo instructions are "ljmp"s then don't
80 do it since it can be part of a jump table */
81 if (currPl->prev && currPl->prev->prev &&
82 strstr(currPl->prev->line,"ljmp") &&
83 strstr(currPl->prev->prev->line,"ljmp"))
86 /* calculate the label distance : the jump for reladdr can be
87 +/- 127 bytes, here Iam assuming that an average 8051
88 instruction is 2 bytes long, so if the label is more than
89 63 intructions away, the label is considered out of range
90 for a relative jump. we could get more precise this will
91 suffice for now since it catches > 90% cases */
92 dist = (pcDistance(currPl,lbl,TRUE) +
93 pcDistance(currPl,lbl,FALSE)) ;
95 if (!dist || dist > 45)
101 /*-----------------------------------------------------------------*/
102 /* operandsNotSame - check if %1 & %2 are the same */
103 /*-----------------------------------------------------------------*/
104 FBYNAME(operandsNotSame)
106 char *op1 = hTabItemWithKey(vars,1);
107 char *op2 = hTabItemWithKey(vars,2);
109 if (strcmp(op1,op2) == 0)
115 /*-----------------------------------------------------------------*/
116 /* callFuncByName - calls a function as defined in the table */
117 /*-----------------------------------------------------------------*/
118 int callFuncByName ( char *fname,
125 int (*func)(hTab *,lineNode *,lineNode *) ;
127 {"labelInRange", labelInRange },
128 {"operandsNotSame", operandsNotSame }
132 for ( i = 0 ; i < ((sizeof (ftab))/(sizeof(struct ftab))); i++)
133 if (strcmp(ftab[i].fname,fname) == 0)
134 return (*ftab[i].func)(vars,currPl,head);
135 fprintf(stderr,"could not find named function in function table\n");
139 /*-----------------------------------------------------------------*/
140 /* printLine - prints a line chain into a given file */
141 /*-----------------------------------------------------------------*/
142 void printLine (lineNode *head, FILE *of)
148 /* don't indent comments & labels */
150 ( *head->line == ';' ||
151 head->line[strlen(head->line)-1] == ':'))
152 fprintf(of,"%s\n",head->line);
154 fprintf(of,"\t%s\n",head->line);
159 /*-----------------------------------------------------------------*/
160 /* newPeepRule - creates a new peeprule and attach it to the root */
161 /*-----------------------------------------------------------------*/
162 peepRule *newPeepRule (lineNode *match ,
169 ALLOC(pr,sizeof(peepRule));
171 pr->replace= replace;
172 pr->restart = restart;
175 ALLOC_ATOMIC(pr->cond,strlen(cond)+1);
176 strcpy(pr->cond,cond);
180 pr->vars = newHashTable(100);
182 /* if root is empty */
184 rootRules = currRule = pr;
186 currRule = currRule->next = pr;
191 /*-----------------------------------------------------------------*/
192 /* newLineNode - creates a new peep line */
193 /*-----------------------------------------------------------------*/
194 lineNode *newLineNode (char *line)
198 ALLOC(pl,sizeof(lineNode));
199 ALLOC_ATOMIC(pl->line,strlen(line)+1);
200 strcpy(pl->line,line);
204 /*-----------------------------------------------------------------*/
205 /* connectLine - connects two lines */
206 /*-----------------------------------------------------------------*/
207 lineNode *connectLine (lineNode *pl1, lineNode *pl2)
210 fprintf (stderr,"trying to connect null line\n");
220 #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \
221 if (!*x) { fprintf(stderr,y); return ; } }
223 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
224 if (!*x) { fprintf(stderr,z); return ; } }
225 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
226 if (!*x) { fprintf(stderr,z); return ; } }
228 /*-----------------------------------------------------------------*/
229 /* getPeepLine - parses the peep lines */
230 /*-----------------------------------------------------------------*/
231 static void getPeepLine (lineNode **head, char **bpp)
233 char lines[MAX_PATTERN_LEN];
236 lineNode *currL = NULL ;
241 fprintf(stderr,"unexpected end of match pattern\n");
247 while (isspace(*bp) ||
256 /* read till end of line */
258 while ((*bp != '\n' && *bp != '}' ) && *bp)
263 *head = currL = newLineNode (lines);
265 currL = connectLine(currL,newLineNode(lines));
271 /*-----------------------------------------------------------------*/
272 /* readRules - reads the rules from a string buffer */
273 /*-----------------------------------------------------------------*/
274 static void readRules (char *bp)
277 char lines[MAX_PATTERN_LEN];
281 lineNode *currL = NULL;
287 /* look for the token "replace" that is the
289 while (*bp && strncmp(bp,"replace",7)) bp++;
295 /* then look for either "restart" or '{' */
296 while (strncmp(bp,"restart",7) &&
297 *bp != '{' && bp ) bp++ ;
301 fprintf(stderr,"expected 'restart' or '{'\n");
308 else { /* must be restart */
310 bp += strlen("restart");
312 EXPECT_CHR(bp,'{',"expected '{'\n");
316 /* skip thru all the blank space */
317 SKIP_SPACE(bp,"unexpected end of rule\n");
319 match = replace = currL = NULL ;
320 /* we are the start of a rule */
321 getPeepLine(&match, &bp);
323 /* now look for by */
324 EXPECT_STR(bp,"by","expected 'by'\n");
326 /* then look for a '{' */
327 EXPECT_CHR(bp,'{',"expected '{'\n");
330 SKIP_SPACE(bp,"unexpected end of rule\n");
331 getPeepLine (&replace, &bp);
333 /* look for a 'if' */
334 while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
336 if (strncmp(bp,"if",2) == 0) {
338 while ((isspace(*bp) || *bp == '\n') && *bp) bp++;
340 fprintf(stderr,"expected condition name\n");
344 /* look for the condition */
346 while (isalnum(*bp)) {
351 newPeepRule(match,replace,lines,restart);
353 newPeepRule(match,replace,NULL,restart);
358 /*-----------------------------------------------------------------*/
359 /* keyForVar - returns the numeric key for a var */
360 /*-----------------------------------------------------------------*/
361 static int keyForVar (char *d)
365 while (isdigit(*d)) {
373 /*-----------------------------------------------------------------*/
374 /* bindVar - binds a value to a variable in the given hashtable */
375 /*-----------------------------------------------------------------*/
376 static void bindVar (int key, char **s, hTab **vtab)
378 char vval[MAX_PATTERN_LEN];
382 /* first get the value of the variable */
384 /* the value is ended by a ',' or space or newline or null */
391 /* if we find a '(' then we need to balance it */
396 if (*vvx == '(') ubb++;
397 if (*vvx == ')') ubb--;
405 ALLOC_ATOMIC(vvx,strlen(vval)+1);
407 hTabAddItem(vtab,key,vvx);
411 /*-----------------------------------------------------------------*/
412 /* matchLine - matches one line */
413 /*-----------------------------------------------------------------*/
414 static bool matchLine (char *s, char *d, hTab **vars)
422 /* skip white space in both */
423 while (isspace(*s)) s++;
424 while (isspace(*d)) d++;
426 /* if the destination is a var */
427 if (*d == '%' && isdigit(*(d+1))) {
428 char *v = hTabItemWithKey(*vars,keyForVar(d+1));
429 /* if the variable is already bound
430 then it MUST match with dest */
433 if (*v++ != *s++) return FALSE;
435 /* variable not bound we need to
437 bindVar (keyForVar(d+1),&s,vars);
439 /* in either case go past the variable */
441 while (isdigit(*d)) d++;
444 /* they should be an exact match other wise */
446 while (isspace(*s))s++;
447 while (isspace(*d))d++;
454 /* get rid of the trailing spaces
455 in both source & destination */
457 while (isspace(*s)) s++;
460 while (isspace(*d)) d++;
462 /* after all this if only one of them
463 has something left over then no match */
470 /*-----------------------------------------------------------------*/
471 /* matchRule - matches a all the rule lines */
472 /*-----------------------------------------------------------------*/
473 static bool matchRule (lineNode *pl,
478 lineNode *spl ; /* source pl */
479 lineNode *rpl ; /* rule peep line */
481 hTabClearAll(pr->vars);
482 /* setToNull((void **) &pr->vars); */
483 /* pr->vars = newHashTable(100); */
485 /* for all the lines defined in the rule */
490 /* if the source line starts with a ';' then
491 comment line don't process or the source line
492 contains == . debugger information skip it */
494 (*spl->line == ';' || spl->isDebug)) {
499 if (!matchLine(spl->line,rpl->line,&pr->vars))
509 /* if this rule has additional conditions */
511 if (callFuncByName (pr->cond, pr->vars,pl,head) ) {
525 /*-----------------------------------------------------------------*/
526 /* replaceRule - does replacement of a matching pattern */
527 /*-----------------------------------------------------------------*/
528 static void replaceRule (lineNode **shead, lineNode *stail, peepRule *pr)
531 lineNode *pl = NULL , *lhead = NULL;
532 char lb[MAX_PATTERN_LEN];
534 lineNode *comment = NULL;
536 /* collect all the comment lines in the source */
537 for (cl = *shead ; cl != stail ; cl = cl->next) {
538 if (cl->line && ( *cl->line == ';' || cl->isDebug)) {
539 pl = (pl ? connectLine (pl,newLineNode(cl->line)) :
540 (comment = newLineNode(cl->line)));
541 pl->isDebug = cl->isDebug;
546 /* for all the lines in the replacement pattern do */
547 for ( pl = pr->replace ; pl ; pl = pl->next ) {
554 /* if the line contains a variable */
555 if (*l == '%' && isdigit(*(l+1))) {
556 v = hTabItemWithKey(pr->vars,keyForVar(l+1));
558 fprintf(stderr,"used unbound variable in replacement\n");
565 while (isdigit(*l)) l++;
573 cl = connectLine(cl,newLineNode(lb));
575 lhead = cl = newLineNode(lb);
578 /* add the comments if any to the head of list */
580 lineNode *lc = comment;
581 while (lc->next) lc = lc->next;
588 /* now we need to connect / replace the original chain */
589 /* if there is a prev then change it */
590 if ((*shead)->prev) {
591 (*shead)->prev->next = lhead;
592 lhead->prev = (*shead)->prev;
595 /* now for the tail */
596 if (stail && stail->next) {
597 stail->next->prev = cl;
599 cl->next = stail->next;
603 /*-----------------------------------------------------------------*/
604 /* peepHole - matches & substitutes rules */
605 /*-----------------------------------------------------------------*/
606 void peepHole (lineNode **pls )
610 lineNode *mtail = NULL;
614 for (pr = rootRules ; pr ; pr = pr->next ) {
616 for (spl = *pls ; spl ; spl = spl->next ) {
618 /* if inline assembler then no peep hole */
625 if (matchRule (spl,&mtail,pr, *pls)) {
629 replaceRule(pls, mtail, pr);
631 replaceRule (&spl, mtail,pr);
633 /* if it was the start then replace
636 /* if restart rule type then
637 start at the top again */
646 /*-----------------------------------------------------------------*/
647 /* readFileIntoBuffer - reads a file into a string buffer */
648 /*-----------------------------------------------------------------*/
649 static char *readFileIntoBuffer (char *fname)
655 char lb[MAX_PATTERN_LEN];
657 if (!(f = fopen(fname,"r"))) {
658 fprintf(stderr,"cannot open peep rule file\n");
662 while ((ch = fgetc(f)) != EOF) {
665 /* if we maxed out our local buffer */
666 if (nch >= (MAX_PATTERN_LEN - 2)) {
668 /* copy it into allocated buffer */
670 rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
673 ALLOC_ATOMIC(rs,strlen(lb)+1);
680 /* if some charaters left over */
683 /* copy it into allocated buffer */
685 rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1);
688 ALLOC_ATOMIC(rs,strlen(lb)+1);
695 /*-----------------------------------------------------------------*/
696 /* initPeepHole - initiaises the peep hole optimizer stuff */
697 /*-----------------------------------------------------------------*/
702 /* read in the default rules */
703 readRules(port->peep.default_rules);
705 /* if we have any additional file read it too */
706 if (options.peep_file) {
707 readRules(s=readFileIntoBuffer(options.peep_file));
708 setToNull((void **) &s);