X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCpeeph.c;h=070d902338c5dbcb5ac69baa2ca1199393f6d63f;hb=a1e11a9b941704e32663e69f81d8e5f5afcb4d2e;hp=aa923fbbe1ef100bed2c1270c71e3df5527851e5;hpb=01ad33a1bb9aec417dab3e45e57cac53b38fdb66;p=fw%2Fsdcc diff --git a/src/SDCCpeeph.c b/src/SDCCpeeph.c index aa923fbb..070d9023 100644 --- a/src/SDCCpeeph.c +++ b/src/SDCCpeeph.c @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------- - SDCCpeeph.c - The peep hole optimizer: for interpreting the + SDCCpeeph.c - The peep hole optimizer: for interpreting the peep hole rules Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) @@ -8,213 +8,391 @@ under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! + what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ #include "common.h" -#include "SDCCpeeph.h" -peepRule *rootRules = NULL; -peepRule *currRule = NULL; +static peepRule *rootRules = NULL; +static peepRule *currRule = NULL; + +#define HTAB_SIZE 53 +typedef struct + { + char name[SDCC_NAME_MAX + 1]; + int refCount; + } +labelHashEntry; + +static hTab *labelHash = NULL; + +static struct +{ + allocTrace values; + allocTrace labels; +} _G; + +static int hashSymbolName (const char *name); +static void buildLabelRefCountHash (lineNode * head); static bool matchLine (char *, char *, hTab **); -#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head) +#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *head, \ + const char *cmdLine) + +#if !OPT_DISABLE_PIC +void peepRules2pCode(peepRule *); +#endif /*-----------------------------------------------------------------*/ /* pcDistance - afinds a label back ward or forward */ /*-----------------------------------------------------------------*/ -int pcDistance (lineNode *cpos, char *lbl, bool back) +int +pcDistance (lineNode * cpos, char *lbl, bool back) { - lineNode *pl = cpos; - char buff[MAX_PATTERN_LEN]; - int dist = 0 ; + lineNode *pl = cpos; + char buff[MAX_PATTERN_LEN]; + int dist = 0; - sprintf(buff,"%s:",lbl); - while (pl) { + sprintf (buff, "%s:", lbl); + while (pl) + { - if (pl->line && - *pl->line != ';' && - pl->line[strlen(pl->line)-1] != ':' && - !pl->isDebug) - - dist ++; + if (pl->line && + *pl->line != ';' && + pl->line[strlen (pl->line) - 1] != ':' && + !pl->isDebug) - if (strncmp(pl->line,buff,strlen(buff)) == 0) - return dist; + dist++; - if (back) - pl = pl->prev; - else - pl = pl->next; + if (strncmp (pl->line, buff, strlen (buff)) == 0) + return dist; + + if (back) + pl = pl->prev; + else + pl = pl->next; } - return 0; + return 0; } /*-----------------------------------------------------------------*/ -/* labelInRange - will check to see if label %5 is within range */ +/* flat24bitModeAndPortDS390 - */ /*-----------------------------------------------------------------*/ -FBYNAME(labelInRange) +FBYNAME (flat24bitModeAndPortDS390) { - /* assumes that %5 pattern variable has the label name */ - char *lbl = hTabItemWithKey(vars,5); - int dist = 0 ; + return ((strcmp(port->target,"ds390") == 0) && + (options.model == MODEL_FLAT24)); +} - if (!lbl) - return FALSE; +/*-----------------------------------------------------------------*/ +/* portIsDS390 - return true if port is DS390 */ +/*-----------------------------------------------------------------*/ +FBYNAME (portIsDS390) +{ + return (strcmp(port->target,"ds390") == 0); +} - /* if the previous teo instructions are "ljmp"s then don't - do it since it can be part of a jump table */ - if (currPl->prev && currPl->prev->prev && - strstr(currPl->prev->line,"ljmp") && - strstr(currPl->prev->prev->line,"ljmp")) - return FALSE ; - - /* calculate the label distance : the jump for reladdr can be - +/- 127 bytes, here Iam assuming that an average 8051 - instruction is 2 bytes long, so if the label is more than - 63 intructions away, the label is considered out of range - for a relative jump. we could get more precise this will - suffice for now since it catches > 90% cases */ - dist = (pcDistance(currPl,lbl,TRUE) + - pcDistance(currPl,lbl,FALSE)) ; - - if (!dist || dist > 45) - return FALSE; +/*-----------------------------------------------------------------*/ +/* flat24bitMode - will check to see if we are in flat24 mode */ +/*-----------------------------------------------------------------*/ +FBYNAME (flat24bitMode) +{ + return (options.model == MODEL_FLAT24); +} - return TRUE; +/*-----------------------------------------------------------------*/ +/* xramMovcOption - check if using movc to read xram */ +/*-----------------------------------------------------------------*/ +FBYNAME (xramMovcOption) +{ + return (options.xram_movc && (strcmp(port->target,"mcs51") == 0)); +} + +/*-----------------------------------------------------------------*/ +/* labelInRange - will check to see if label %5 is within range */ +/*-----------------------------------------------------------------*/ +FBYNAME (labelInRange) +{ + /* assumes that %5 pattern variable has the label name */ + char *lbl = hTabItemWithKey (vars, 5); + int dist = 0; + + if (!lbl) + return FALSE; + + /* if the previous two instructions are "ljmp"s then don't + do it since it can be part of a jump table */ + if (currPl->prev && currPl->prev->prev && + strstr (currPl->prev->line, "ljmp") && + strstr (currPl->prev->prev->line, "ljmp")) + return FALSE; + + /* calculate the label distance : the jump for reladdr can be + +/- 127 bytes, here Iam assuming that an average 8051 + instruction is 2 bytes long, so if the label is more than + 63 intructions away, the label is considered out of range + for a relative jump. we could get more precise this will + suffice for now since it catches > 90% cases */ + dist = (pcDistance (currPl, lbl, TRUE) + + pcDistance (currPl, lbl, FALSE)); + +/* if (!dist || dist > 45) has produced wrong sjmp */ + /* 07-Sep-2000 Michael Schmitt */ + /* FIX for Peephole 132 */ + /* switch with lots of case can lead to a sjmp with a distance */ + /* out of the range for sjmp */ + if (!dist || dist > 43) + return FALSE; + + return TRUE; } /*-----------------------------------------------------------------*/ /* operandsNotSame - check if %1 & %2 are the same */ /*-----------------------------------------------------------------*/ -FBYNAME(operandsNotSame) +FBYNAME (operandsNotSame) { - char *op1 = hTabItemWithKey(vars,1); - char *op2 = hTabItemWithKey(vars,2); + char *op1 = hTabItemWithKey (vars, 1); + char *op2 = hTabItemWithKey (vars, 2); - if (strcmp(op1,op2) == 0) - return FALSE; - else - return TRUE; + if (strcmp (op1, op2) == 0) + return FALSE; + else + return TRUE; +} + +/* labelRefCount: + + * takes two parameters: a variable (bound to a label name) + * and an expected reference count. + * + * Returns TRUE if that label is defined and referenced exactly + * the given number of times. + */ +FBYNAME (labelRefCount) +{ + int varNumber, expectedRefCount; + bool rc = FALSE; + + /* If we don't have the label hash table yet, build it. */ + if (!labelHash) + { + buildLabelRefCountHash (head); + } + + if (sscanf (cmdLine, "%*[ \t%]%d %d", &varNumber, &expectedRefCount) == 2) + { + char *label = hTabItemWithKey (vars, varNumber); + + if (label) + { + labelHashEntry *entry; + + entry = hTabFirstItemWK (labelHash, hashSymbolName (label)); + + while (entry) + { + if (!strcmp (label, entry->name)) + { + break; + } + entry = hTabNextItemWK (labelHash); + } + if (entry) + { +#if 0 + /* debug spew. */ + fprintf (stderr, "labelRefCount: %s has refCount %d, want %d\n", + label, entry->refCount, expectedRefCount); +#endif + + rc = (expectedRefCount == entry->refCount); + } + else + { + fprintf (stderr, "*** internal error: no label has entry for" + " %s in labelRefCount peephole.\n", + label); + } + } + else + { + fprintf (stderr, "*** internal error: var %d not bound" + " in peephole labelRefCount rule.\n", + varNumber); + } + + } + else + { + fprintf (stderr, + "*** internal error: labelRefCount peephole restriction" + " malformed: %s\n", cmdLine); + } + return rc; } /*-----------------------------------------------------------------*/ /* callFuncByName - calls a function as defined in the table */ /*-----------------------------------------------------------------*/ -int callFuncByName ( char *fname, - hTab *vars, - lineNode *currPl, - lineNode *head) +int +callFuncByName (char *fname, + hTab * vars, + lineNode * currPl, + lineNode * head) { - struct ftab { - char *fname ; - int (*func)(hTab *,lineNode *,lineNode *) ; - } ftab[] = { - {"labelInRange", labelInRange }, - {"operandsNotSame", operandsNotSame } - }; - int i; - - for ( i = 0 ; i < ((sizeof (ftab))/(sizeof(struct ftab))); i++) - if (strcmp(ftab[i].fname,fname) == 0) - return (*ftab[i].func)(vars,currPl,head); - fprintf(stderr,"could not find named function in function table\n"); - return TRUE; + struct ftab + { + char *fname; + int (*func) (hTab *, lineNode *, lineNode *, const char *); + } + ftab[] = + { + { + "labelInRange", labelInRange + } + , + { + "operandsNotSame", operandsNotSame + } + , + { + "24bitMode", flat24bitMode + } + , + { + "xramMovcOption", xramMovcOption + } + , + { + "labelRefCount", labelRefCount + } + , + { + "portIsDS390", portIsDS390 + }, + { + "24bitModeAndPortDS390", flat24bitModeAndPortDS390 + } + }; + int i; + + for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++) + if (strncmp (ftab[i].fname, fname, strlen (ftab[i].fname)) == 0) + { + return (*ftab[i].func) (vars, currPl, head, + fname + strlen (ftab[i].fname)); + } + fprintf (stderr, "could not find named function in function table\n"); + return TRUE; } /*-----------------------------------------------------------------*/ /* printLine - prints a line chain into a given file */ /*-----------------------------------------------------------------*/ -void printLine (lineNode *head, FILE *of) +void +printLine (lineNode * head, FILE * of) { - if (!of) - of = stdout ; - - while (head) { - /* don't indent comments & labels */ - if (head->line && - ( *head->line == ';' || - head->line[strlen(head->line)-1] == ':')) - fprintf(of,"%s\n",head->line); - else - fprintf(of,"\t%s\n",head->line); - head = head->next; + if (!of) + of = stdout; + + while (head) + { + /* don't indent comments & labels */ + if (head->line && + (*head->line == ';' || + head->line[strlen (head->line) - 1] == ':')) { + fprintf (of, "%s\n", head->line); + } else { + if (head->isInline && *head->line=='#') { + // comment out preprocessor directives in inline asm + fprintf (of, ";"); + } + fprintf (of, "\t%s\n", head->line); + } + head = head->next; } } /*-----------------------------------------------------------------*/ /* newPeepRule - creates a new peeprule and attach it to the root */ /*-----------------------------------------------------------------*/ -peepRule *newPeepRule (lineNode *match , - lineNode *replace, - char *cond , - int restart) +peepRule * +newPeepRule (lineNode * match, + lineNode * replace, + char *cond, + int restart) { - peepRule *pr ; - - ALLOC(pr,sizeof(peepRule)); - pr->match = match; - pr->replace= replace; - pr->restart = restart; - - if (cond && *cond) { - ALLOC_ATOMIC(pr->cond,strlen(cond)+1); - strcpy(pr->cond,cond); - } else - pr->cond = NULL ; - - pr->vars = newHashTable(100); - - /* if root is empty */ - if (!rootRules) - rootRules = currRule = pr; - else - currRule = currRule->next = pr; - - return pr; + peepRule *pr; + + pr = Safe_alloc ( sizeof (peepRule)); + pr->match = match; + pr->replace = replace; + pr->restart = restart; + + if (cond && *cond) + { + pr->cond = Safe_alloc ( strlen (cond) + 1); + strcpy (pr->cond, cond); + } + else + pr->cond = NULL; + + pr->vars = newHashTable (100); + + /* if root is empty */ + if (!rootRules) + rootRules = currRule = pr; + else + currRule = currRule->next = pr; + + return pr; } /*-----------------------------------------------------------------*/ /* newLineNode - creates a new peep line */ /*-----------------------------------------------------------------*/ -lineNode *newLineNode (char *line) +lineNode * +newLineNode (char *line) { - lineNode *pl; + lineNode *pl; - ALLOC(pl,sizeof(lineNode)); - ALLOC_ATOMIC(pl->line,strlen(line)+1); - strcpy(pl->line,line); - return pl; + pl = Safe_alloc ( sizeof (lineNode)); + pl->line = Safe_alloc ( strlen (line) + 1); + strcpy (pl->line, line); + return pl; } /*-----------------------------------------------------------------*/ /* connectLine - connects two lines */ /*-----------------------------------------------------------------*/ -lineNode *connectLine (lineNode *pl1, lineNode *pl2) +lineNode * +connectLine (lineNode * pl1, lineNode * pl2) { - if (!pl1 || !pl2) { - fprintf (stderr,"trying to connect null line\n"); - return NULL ; + if (!pl1 || !pl2) + { + fprintf (stderr, "trying to connect null line\n"); + return NULL; } - pl2->prev = pl1; - pl1->next = pl2; + pl2->prev = pl1; + pl1->next = pl2; - return pl2; + return pl2; } #define SKIP_SPACE(x,y) { while (*x && (isspace(*x) || *x == '\n')) x++; \ @@ -228,483 +406,761 @@ lineNode *connectLine (lineNode *pl1, lineNode *pl2) /*-----------------------------------------------------------------*/ /* getPeepLine - parses the peep lines */ /*-----------------------------------------------------------------*/ -static void getPeepLine (lineNode **head, char **bpp) +static void +getPeepLine (lineNode ** head, char **bpp) { - char lines[MAX_PATTERN_LEN]; - char *lp; - - lineNode *currL = NULL ; - char *bp = *bpp; - while (1) { - - if (!*bp) { - fprintf(stderr,"unexpected end of match pattern\n"); - return ; + char lines[MAX_PATTERN_LEN]; + char *lp; + + lineNode *currL = NULL; + char *bp = *bpp; + while (1) + { + + if (!*bp) + { + fprintf (stderr, "unexpected end of match pattern\n"); + return; } - - if (*bp == '\n') { - bp++ ; - while (isspace(*bp) || - *bp == '\n') bp++; + + if (*bp == '\n') + { + bp++; + while (isspace (*bp) || + *bp == '\n') + bp++; } - - if (*bp == '}') { - bp++ ; - break; + + if (*bp == '}') + { + bp++; + break; } - - /* read till end of line */ - lp = lines ; - while ((*bp != '\n' && *bp != '}' ) && *bp) - *lp++ = *bp++ ; - - *lp = '\0'; - if (!currL) - *head = currL = newLineNode (lines); - else - currL = connectLine(currL,newLineNode(lines)); - } - - *bpp = bp; + + /* read till end of line */ + lp = lines; + while ((*bp != '\n' && *bp != '}') && *bp) + *lp++ = *bp++; + + *lp = '\0'; + if (!currL) + *head = currL = newLineNode (lines); + else + currL = connectLine (currL, newLineNode (lines)); + } + + *bpp = bp; } /*-----------------------------------------------------------------*/ /* readRules - reads the rules from a string buffer */ /*-----------------------------------------------------------------*/ -static void readRules (char *bp) +static void +readRules (char *bp) { - char restart = 0 ; - char lines[MAX_PATTERN_LEN]; - char *lp; - lineNode *match; - lineNode *replace; - lineNode *currL = NULL; - - if (!bp) - return; - top: - restart = 0; - /* look for the token "replace" that is the - start of a rule */ - while (*bp && strncmp(bp,"replace",7)) bp++; - - /* if not found */ - if (!*bp) - return ; - - /* then look for either "restart" or '{' */ - while (strncmp(bp,"restart",7) && - *bp != '{' && bp ) bp++ ; - - /* not found */ - if (!*bp) { - fprintf(stderr,"expected 'restart' or '{'\n"); - return ; - } - - /* if brace */ - if (*bp == '{') - bp++ ; - else { /* must be restart */ - restart++; - bp += strlen("restart"); - /* look for '{' */ - EXPECT_CHR(bp,'{',"expected '{'\n"); - bp++; + char restart = 0; + char lines[MAX_PATTERN_LEN]; + char *lp; + lineNode *match; + lineNode *replace; + lineNode *currL = NULL; + + if (!bp) + return; +top: + restart = 0; + /* look for the token "replace" that is the + start of a rule */ + while (*bp && strncmp (bp, "replace", 7)) + bp++; + + /* if not found */ + if (!*bp) + return; + + /* then look for either "restart" or '{' */ + while (strncmp (bp, "restart", 7) && + *bp != '{' && bp) + bp++; + + /* not found */ + if (!*bp) + { + fprintf (stderr, "expected 'restart' or '{'\n"); + return; } - /* skip thru all the blank space */ - SKIP_SPACE(bp,"unexpected end of rule\n"); - - match = replace = currL = NULL ; - /* we are the start of a rule */ - getPeepLine(&match, &bp); - - /* now look for by */ - EXPECT_STR(bp,"by","expected 'by'\n"); - - /* then look for a '{' */ - EXPECT_CHR(bp,'{',"expected '{'\n"); - bp++ ; - - SKIP_SPACE(bp,"unexpected end of rule\n"); - getPeepLine (&replace, &bp); - - /* look for a 'if' */ - while ((isspace(*bp) || *bp == '\n') && *bp) bp++; - - if (strncmp(bp,"if",2) == 0) { - bp += 2; - while ((isspace(*bp) || *bp == '\n') && *bp) bp++; - if (!*bp) { - fprintf(stderr,"expected condition name\n"); - return; + /* if brace */ + if (*bp == '{') + bp++; + else + { /* must be restart */ + restart++; + bp += strlen ("restart"); + /* look for '{' */ + EXPECT_CHR (bp, '{', "expected '{'\n"); + bp++; + } + + /* skip thru all the blank space */ + SKIP_SPACE (bp, "unexpected end of rule\n"); + + match = replace = currL = NULL; + /* we are the start of a rule */ + getPeepLine (&match, &bp); + + /* now look for by */ + EXPECT_STR (bp, "by", "expected 'by'\n"); + + /* then look for a '{' */ + EXPECT_CHR (bp, '{', "expected '{'\n"); + bp++; + + SKIP_SPACE (bp, "unexpected end of rule\n"); + getPeepLine (&replace, &bp); + + /* look for a 'if' */ + while ((isspace (*bp) || *bp == '\n') && *bp) + bp++; + + if (strncmp (bp, "if", 2) == 0) + { + bp += 2; + while ((isspace (*bp) || *bp == '\n') && *bp) + bp++; + if (!*bp) + { + fprintf (stderr, "expected condition name\n"); + return; } - - /* look for the condition */ - lp = lines; - while (isalnum(*bp)) { - *lp++ = *bp++; + + /* look for the condition */ + lp = lines; + while (*bp && (*bp != '\n')) + { + *lp++ = *bp++; } - *lp = '\0'; - - newPeepRule(match,replace,lines,restart); - } else - newPeepRule(match,replace,NULL,restart); - goto top; + *lp = '\0'; + + newPeepRule (match, replace, lines, restart); + } + else + newPeepRule (match, replace, NULL, restart); + goto top; } /*-----------------------------------------------------------------*/ /* keyForVar - returns the numeric key for a var */ /*-----------------------------------------------------------------*/ -static int keyForVar (char *d) +static int +keyForVar (char *d) { - int i = 0; + int i = 0; - while (isdigit(*d)) { - i *= 10 ; - i += (*d++ - '0') ; + while (isdigit (*d)) + { + i *= 10; + i += (*d++ - '0'); } - return i; + return i; } /*-----------------------------------------------------------------*/ /* bindVar - binds a value to a variable in the given hashtable */ /*-----------------------------------------------------------------*/ -static void bindVar (int key, char **s, hTab **vtab) +static void +bindVar (int key, char **s, hTab ** vtab) { - char vval[MAX_PATTERN_LEN]; - char *vvx; - char *vv = vval; - - /* first get the value of the variable */ - vvx = *s; - /* the value is ended by a ',' or space or newline or null */ - while (*vvx && - *vvx != ',' && - !isspace(*vvx) && - *vvx != '\n' && - *vvx != ':' ) { - char ubb = 0 ; - /* if we find a '(' then we need to balance it */ - if (*vvx == '(') { - ubb++ ; - while (ubb) { - *vv++ = *vvx++ ; - if (*vvx == '(') ubb++; - if (*vvx == ')') ubb--; + char vval[MAX_PATTERN_LEN]; + char *vvx; + char *vv = vval; + + /* first get the value of the variable */ + vvx = *s; + /* the value is ended by a ',' or space or newline or null or ) */ + while (*vvx && + *vvx != ',' && + !isspace (*vvx) && + *vvx != '\n' && + *vvx != ':' && + *vvx != ')') + { + char ubb = 0; + /* if we find a '(' then we need to balance it */ + if (*vvx == '(') + { + ubb++; + while (ubb) + { + *vv++ = *vvx++; + if (*vvx == '(') + ubb++; + if (*vvx == ')') + ubb--; } - } else - *vv++ = *vvx++ ; - } - *s = vvx ; - *vv = '\0'; - /* got value */ - ALLOC_ATOMIC(vvx,strlen(vval)+1); - strcpy(vvx,vval); - hTabAddItem(vtab,key,vvx); - + // include the trailing ')' + *vv++ = *vvx++; + } + else + *vv++ = *vvx++; + } + *s = vvx; + *vv = '\0'; + /* got value */ + vvx = traceAlloc (&_G.values, Safe_alloc(strlen (vval) + 1)); + strcpy (vvx, vval); + + hTabAddItem (vtab, key, vvx); } /*-----------------------------------------------------------------*/ /* matchLine - matches one line */ /*-----------------------------------------------------------------*/ -static bool matchLine (char *s, char *d, hTab **vars) -{ - - if (!s || !(*s)) - return FALSE; +static bool +matchLine (char *s, char *d, hTab ** vars) +{ - while (*s && *d) { - - /* skip white space in both */ - while (isspace(*s)) s++; - while (isspace(*d)) d++; - - /* if the destination is a var */ - if (*d == '%' && isdigit(*(d+1))) { - char *v = hTabItemWithKey(*vars,keyForVar(d+1)); - /* if the variable is already bound - then it MUST match with dest */ - if (v) { - while (*v) - if (*v++ != *s++) return FALSE; - } else - /* variable not bound we need to - bind it */ - bindVar (keyForVar(d+1),&s,vars); - - /* in either case go past the variable */ - d++ ; - while (isdigit(*d)) d++; + if (!s || !(*s)) + return FALSE; + + while (*s && *d) + { + + /* skip white space in both */ + while (isspace (*s)) + s++; + while (isspace (*d)) + d++; + + /* if the destination is a var */ + if (*d == '%' && isdigit (*(d + 1))) + { + char *v = hTabItemWithKey (*vars, keyForVar (d + 1)); + /* if the variable is already bound + then it MUST match with dest */ + if (v) + { + while (*v) + if (*v++ != *s++) + return FALSE; + } + else + /* variable not bound we need to + bind it */ + bindVar (keyForVar (d + 1), &s, vars); + + /* in either case go past the variable */ + d++; + while (isdigit (*d)) + d++; } - /* they should be an exact match other wise */ - if (*s && *d) { - while (isspace(*s))s++; - while (isspace(*d))d++; - if (*s++ != *d++) - return FALSE; + /* they should be an exact match other wise */ + if (*s && *d) + { + while (isspace (*s)) + s++; + while (isspace (*d)) + d++; + if (*s++ != *d++) + return FALSE; } } - /* get rid of the trailing spaces - in both source & destination */ - if (*s) - while (isspace(*s)) s++; + /* get rid of the trailing spaces + in both source & destination */ + if (*s) + while (isspace (*s)) + s++; - if (*d) - while (isspace(*d)) d++; + if (*d) + while (isspace (*d)) + d++; - /* after all this if only one of them - has something left over then no match */ - if (*s || *d) - return FALSE ; - - return TRUE ; + /* after all this if only one of them + has something left over then no match */ + if (*s || *d) + return FALSE; + + return TRUE; } /*-----------------------------------------------------------------*/ /* matchRule - matches a all the rule lines */ /*-----------------------------------------------------------------*/ -static bool matchRule (lineNode *pl, - lineNode **mtail, - peepRule *pr, - lineNode *head) +static bool +matchRule (lineNode * pl, + lineNode ** mtail, + peepRule * pr, + lineNode * head) { - lineNode *spl ; /* source pl */ - lineNode *rpl ; /* rule peep line */ - - hTabClearAll(pr->vars); + lineNode *spl; /* source pl */ + lineNode *rpl; /* rule peep line */ + /* setToNull((void **) &pr->vars); */ /* pr->vars = newHashTable(100); */ - /* for all the lines defined in the rule */ - rpl = pr->match; - spl = pl ; - while (spl && rpl) { - - /* if the source line starts with a ';' then - comment line don't process or the source line - contains == . debugger information skip it */ - if (spl->line && - (*spl->line == ';' || spl->isDebug)) { - spl = spl->next; - continue; + /* for all the lines defined in the rule */ + rpl = pr->match; + spl = pl; + while (spl && rpl) + { + + /* if the source line starts with a ';' then + comment line don't process or the source line + contains == . debugger information skip it */ + if (spl->line && + (*spl->line == ';' || spl->isDebug)) + { + spl = spl->next; + continue; } - if (!matchLine(spl->line,rpl->line,&pr->vars)) - return FALSE ; - - rpl = rpl->next ; - if (rpl) - spl = spl->next ; - } - - /* if rules ended */ - if (!rpl) { - /* if this rule has additional conditions */ - if ( pr->cond) { - if (callFuncByName (pr->cond, pr->vars,pl,head) ) { - *mtail = spl; - return TRUE; - } else - return FALSE; - } else { - *mtail = spl; - return TRUE; + if (!matchLine (spl->line, rpl->line, &pr->vars)) + return FALSE; + + rpl = rpl->next; + if (rpl) + spl = spl->next; + } + + /* if rules ended */ + if (!rpl) + { + /* if this rule has additional conditions */ + if (pr->cond) + { + if (callFuncByName (pr->cond, pr->vars, pl, head)) + { + *mtail = spl; + return TRUE; + } + else + return FALSE; + } + else + { + *mtail = spl; + return TRUE; } } - else - return FALSE; + else + return FALSE; } /*-----------------------------------------------------------------*/ /* replaceRule - does replacement of a matching pattern */ /*-----------------------------------------------------------------*/ -static void replaceRule (lineNode **shead, lineNode *stail, peepRule *pr) +static void +replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr) { - lineNode *cl = NULL; - lineNode *pl = NULL , *lhead = NULL; - char lb[MAX_PATTERN_LEN]; - char *lbp; - lineNode *comment = NULL; - - /* collect all the comment lines in the source */ - for (cl = *shead ; cl != stail ; cl = cl->next) { - if (cl->line && ( *cl->line == ';' || cl->isDebug)) { - pl = (pl ? connectLine (pl,newLineNode(cl->line)) : - (comment = newLineNode(cl->line))); - pl->isDebug = cl->isDebug; + lineNode *cl = NULL; + lineNode *pl = NULL, *lhead = NULL; + /* a long function name and long variable name can evaluate to + 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */ + char lb[MAX_PATTERN_LEN*4]; + char *lbp; + lineNode *comment = NULL; + + /* collect all the comment lines in the source */ + for (cl = *shead; cl != stail; cl = cl->next) + { + if (cl->line && (*cl->line == ';' || cl->isDebug)) + { + pl = (pl ? connectLine (pl, newLineNode (cl->line)) : + (comment = newLineNode (cl->line))); + pl->isDebug = cl->isDebug; } } - cl = NULL; - - /* for all the lines in the replacement pattern do */ - for ( pl = pr->replace ; pl ; pl = pl->next ) { - char *v; - char *l; - lbp = lb; - - l = pl->line; - while (*l) { - /* if the line contains a variable */ - if (*l == '%' && isdigit(*(l+1))) { - v = hTabItemWithKey(pr->vars,keyForVar(l+1)); - if (!v) { - fprintf(stderr,"used unbound variable in replacement\n"); - l++; - continue; + cl = NULL; + + /* for all the lines in the replacement pattern do */ + for (pl = pr->replace; pl; pl = pl->next) + { + char *v; + char *l; + lbp = lb; + + l = pl->line; + + while (*l) + { + /* if the line contains a variable */ + if (*l == '%' && isdigit (*(l + 1))) + { + v = hTabItemWithKey (pr->vars, keyForVar (l + 1)); + if (!v) + { + fprintf (stderr, "used unbound variable in replacement\n"); + l++; + continue; } - while (*v) - *lbp++ = *v++; + while (*v) { + *lbp++ = *v++; + } + l++; + while (isdigit (*l)) { l++; - while (isdigit(*l)) l++; - continue ; + } + continue; } - *lbp++ = *l++; + *lbp++ = *l++; } - *lbp = '\0'; - if (cl) - cl = connectLine(cl,newLineNode(lb)); - else - lhead = cl = newLineNode(lb); - } - - /* add the comments if any to the head of list */ - if (comment) { - lineNode *lc = comment; - while (lc->next) lc = lc->next; - lc->next = lhead; - if (lhead) - lhead->prev = lc; - lhead = comment; - } - - /* now we need to connect / replace the original chain */ - /* if there is a prev then change it */ - if ((*shead)->prev) { - (*shead)->prev->next = lhead; - lhead->prev = (*shead)->prev; - } else - *shead = lhead; - /* now for the tail */ - if (stail && stail->next) { - stail->next->prev = cl; - if (cl) - cl->next = stail->next; - } + *lbp = '\0'; + if (cl) + cl = connectLine (cl, newLineNode (lb)); + else + lhead = cl = newLineNode (lb); + } + + /* add the comments if any to the head of list */ + if (comment) + { + lineNode *lc = comment; + while (lc->next) + lc = lc->next; + lc->next = lhead; + if (lhead) + lhead->prev = lc; + lhead = comment; + } + + /* now we need to connect / replace the original chain */ + /* if there is a prev then change it */ + if ((*shead)->prev) + { + (*shead)->prev->next = lhead; + lhead->prev = (*shead)->prev; + } + else + *shead = lhead; + /* now for the tail */ + if (stail && stail->next) + { + stail->next->prev = cl; + if (cl) + cl->next = stail->next; + } } +/* Returns TRUE if this line is a label definition. + + * If so, start will point to the start of the label name, + * and len will be it's length. + */ +bool +isLabelDefinition (const char *line, const char **start, int *len) +{ + const char *cp = line; + + /* This line is a label if if consists of: + * [optional whitespace] followed by identifier chars + * (alnum | $ | _ ) followed by a colon. + */ + + while (*cp && isspace (*cp)) + { + cp++; + } + + if (!*cp) + { + return FALSE; + } + + *start = cp; + + while (isalnum (*cp) || (*cp == '$') || (*cp == '_')) + { + cp++; + } + + if ((cp == *start) || (*cp != ':')) + { + return FALSE; + } + + *len = (cp - (*start)); + return TRUE; +} + +/* Quick & dirty string hash function. */ +static int +hashSymbolName (const char *name) +{ + int hash = 0; + + while (*name) + { + hash = (hash << 6) ^ *name; + name++; + } + + if (hash < 0) + { + hash = -hash; + } + + return hash % HTAB_SIZE; +} + +/* Build a hash of all labels in the passed set of lines + * and how many times they are referenced. + */ +static void +buildLabelRefCountHash (lineNode * head) +{ + lineNode *line; + const char *label; + int labelLen; + int i; + + assert (labelHash == NULL); + labelHash = newHashTable (HTAB_SIZE); + + /* First pass: locate all the labels. */ + line = head; + + while (line) + { + if (isLabelDefinition (line->line, &label, &labelLen) + && labelLen <= SDCC_NAME_MAX) + { + labelHashEntry *entry; + + entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry))); + + memcpy (entry->name, label, labelLen); + entry->name[labelLen] = 0; + entry->refCount = -1; + + hTabAddItem (&labelHash, hashSymbolName (entry->name), entry); + } + line = line->next; + } + + + /* Second pass: for each line, note all the referenced labels. */ + /* This is ugly, O(N^2) stuff. Optimizations welcome... */ + line = head; + while (line) + { + for (i = 0; i < HTAB_SIZE; i++) + { + labelHashEntry *thisEntry; + + thisEntry = hTabFirstItemWK (labelHash, i); + + while (thisEntry) + { + if (strstr (line->line, thisEntry->name)) + { + thisEntry->refCount++; + } + thisEntry = hTabNextItemWK (labelHash); + } + } + line = line->next; + } + +#if 0 + /* Spew the contents of the table. Debugging fun only. */ + for (i = 0; i < HTAB_SIZE; i++) + { + labelHashEntry *thisEntry; + + thisEntry = hTabFirstItemWK (labelHash, i); + + while (thisEntry) + { + fprintf (stderr, "label: %s ref %d\n", + thisEntry->name, thisEntry->refCount); + thisEntry = hTabNextItemWK (labelHash); + } + } +#endif +} + +/* How does this work? + peepHole + For each rule, + For each line, + Try to match + If it matches, + replace and restart. + + matchRule + matchLine + + Where is stuff allocated? + +*/ + /*-----------------------------------------------------------------*/ /* peepHole - matches & substitutes rules */ /*-----------------------------------------------------------------*/ -void peepHole (lineNode **pls ) +void +peepHole (lineNode ** pls) { - lineNode *spl ; - peepRule *pr ; - lineNode *mtail = NULL; - - top: - /* for all rules */ - for (pr = rootRules ; pr ; pr = pr->next ) { - - for (spl = *pls ; spl ; spl = spl->next ) { - - /* if inline assembler then no peep hole */ - if (spl->isInline) - continue ; - - mtail = NULL ; - - /* if it matches */ - if (matchRule (spl,&mtail,pr, *pls)) { - - /* then replace */ - if (spl == *pls) - replaceRule(pls, mtail, pr); - else - replaceRule (&spl, mtail,pr); - - /* if it was the start then replace - the start */ - - /* if restart rule type then - start at the top again */ - if (pr->restart) - goto top; - } - } + lineNode *spl; + peepRule *pr; + lineNode *mtail = NULL; + bool restart; + +#if !OPT_DISABLE_PIC + /* The PIC port uses a different peep hole optimizer based on "pCode" */ + if (TARGET_IS_PIC) + return; +#endif + + assert(labelHash == NULL); + + do + { + restart = FALSE; + + /* for all rules */ + for (pr = rootRules; pr; pr = pr->next) + { + for (spl = *pls; spl; spl = spl->next) + { + /* if inline assembler then no peep hole */ + if (spl->isInline) + continue; + + mtail = NULL; + + /* Tidy up any data stored in the hTab */ + + /* if it matches */ + if (matchRule (spl, &mtail, pr, *pls)) + { + + /* then replace */ + if (spl == *pls) + replaceRule (pls, mtail, pr); + else + replaceRule (&spl, mtail, pr); + + /* if restart rule type then + start at the top again */ + if (pr->restart) + { + restart = TRUE; + } + } + + if (pr->vars) + { + hTabDeleteAll (pr->vars); + Safe_free (pr->vars); + pr->vars = NULL; + } + + freeTrace (&_G.values); + } + } + } while (restart == TRUE); + + if (labelHash) + { + hTabDeleteAll (labelHash); + freeTrace (&_G.labels); } + labelHash = NULL; } /*-----------------------------------------------------------------*/ /* readFileIntoBuffer - reads a file into a string buffer */ /*-----------------------------------------------------------------*/ -static char *readFileIntoBuffer (char *fname) +static char * +readFileIntoBuffer (char *fname) { - FILE *f; - char *rs = NULL; - int nch = 0 ; - int ch; - char lb[MAX_PATTERN_LEN]; - - if (!(f = fopen(fname,"r"))) { - fprintf(stderr,"cannot open peep rule file\n"); - return NULL; - } - - while ((ch = fgetc(f)) != EOF) { - lb[nch++] = ch; - - /* if we maxed out our local buffer */ - if (nch >= (MAX_PATTERN_LEN - 2)) { - lb[nch] = '\0'; - /* copy it into allocated buffer */ - if (rs) { - rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1); - strcat(rs,lb); - } else { - ALLOC_ATOMIC(rs,strlen(lb)+1); - strcpy(rs,lb); + FILE *f; + char *rs = NULL; + int nch = 0; + int ch; + char lb[MAX_PATTERN_LEN]; + + if (!(f = fopen (fname, "r"))) + { + fprintf (stderr, "cannot open peep rule file\n"); + return NULL; + } + + while ((ch = fgetc (f)) != EOF) + { + lb[nch++] = ch; + + /* if we maxed out our local buffer */ + if (nch >= (MAX_PATTERN_LEN - 2)) + { + lb[nch] = '\0'; + /* copy it into allocated buffer */ + if (rs) + { + rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1); + strcat (rs, lb); } - nch = 0 ; + else + { + rs = Safe_alloc ( strlen (lb) + 1); + strcpy (rs, lb); + } + nch = 0; } } - /* if some charaters left over */ - if (nch) { - lb[nch] = '\0'; - /* copy it into allocated buffer */ - if (rs) { - rs = GC_realloc(rs,strlen(rs)+strlen(lb)+1); - strcat(rs,lb); - } else { - ALLOC_ATOMIC(rs,strlen(lb)+1); - strcpy(rs,lb); + /* if some charaters left over */ + if (nch) + { + lb[nch] = '\0'; + /* copy it into allocated buffer */ + if (rs) + { + rs = Safe_realloc (rs, strlen (rs) + strlen (lb) + 1); + strcat (rs, lb); + } + else + { + rs = Safe_alloc ( strlen (lb) + 1); + strcpy (rs, lb); } } - return rs; + return rs; } /*-----------------------------------------------------------------*/ -/* initPeepHole - initiaises the peep hole optimizer stuff */ +/* initPeepHole - initialises the peep hole optimizer stuff */ /*-----------------------------------------------------------------*/ -void initPeepHole () +void +initPeepHole () { - char *s; + char *s; - /* read in the default rules */ - readRules(port->peep.default_rules); + /* read in the default rules */ + readRules (port->peep.default_rules); - /* if we have any additional file read it too */ - if (options.peep_file) { - readRules(s=readFileIntoBuffer(options.peep_file)); - setToNull((void **) &s); + /* if we have any additional file read it too */ + if (options.peep_file) + { + readRules (s = readFileIntoBuffer (options.peep_file)); + setToNull ((void **) &s); } + + +#if !OPT_DISABLE_PIC + /* Convert the peep rules into pcode. + NOTE: this is only support in the PIC port (at the moment) + */ + if (TARGET_IS_PIC) { + peepRules2pCode(rootRules); + } +#endif + }