/*-------------------------------------------------------------------------
- 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)
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 <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include "SDCCglobl.h"
-#include "SDCChasht.h"
-#include "SDCCset.h"
-#include "SDCCpeeph.h"
+#include "common.h"
+static peepRule *rootRules = NULL;
+static peepRule *currRule = NULL;
-peepRule *rootRules = NULL;
-peepRule *currRule = NULL;
+#define HTAB_SIZE 53
+typedef struct
+ {
+ char name[SDCC_NAME_MAX + 1];
+ int refCount;
+ }
+labelHashEntry;
-char *defaultRules =
+static hTab *labelHash = NULL;
+
+static struct
{
-#include "SDCCpeeph.rul"
-};
-
+ 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)
- if (pl->line &&
- *pl->line != ';' &&
- pl->line[strlen(pl->line)-1] != ':' &&
- !pl->isDebug)
-
- dist ++;
+ dist++;
- if (strncmp(pl->line,buff,strlen(buff)) == 0)
- return dist;
+ if (strncmp (pl->line, buff, strlen (buff)) == 0)
+ return dist;
- if (back)
- pl = pl->prev;
- else
- pl = pl->next;
+ if (back)
+ pl = pl->prev;
+ else
+ pl = pl->next;
}
- return 0;
+ return 0;
}
/*-----------------------------------------------------------------*/
-/* labelInRange - will check to see if label %5 is within range */
+/* flat24bitMode - will check to see if we are in flat24 mode */
/*-----------------------------------------------------------------*/
-FBYNAME(labelInRange)
+FBYNAME (flat24bitMode)
{
- /* assumes that %5 pattern variable has the label name */
- char *lbl = hTabItemWithKey(vars,5);
- int dist = 0 ;
-
- if (!lbl)
- return FALSE;
-
- /* 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;
+ return (options.model == MODEL_FLAT24);
+}
- return TRUE;
+/*-----------------------------------------------------------------*/
+/* 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
+ }
+ ,
+ {
+ "labelRefCount", labelRefCount
+ }
+ ,
+ };
+ 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++; \
/*-----------------------------------------------------------------*/
/* 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;
+ }
+
+ /* 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;
+ /* 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);
-
+ }
+ 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;
- /* after all this if only one of them
- has something left over then no match */
- if (*s || *d)
- return FALSE ;
-
- return TRUE ;
+ 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;
+
+ 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);
+ }
+ else
+ {
+ rs = Safe_alloc ( strlen (lb) + 1);
+ strcpy (rs, lb);
}
- nch = 0 ;
+ 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(defaultRules);
+ /* 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
+
}