static void buildLabelRefCountHash (lineNode * head);
static bool matchLine (char *, char *, hTab **);
+bool isLabelDefinition (const char *line, const char **start, int *len);
#define FBYNAME(x) int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
lineNode *head, const char *cmdLine)
#if !OPT_DISABLE_PIC
-void peepRules2pCode(peepRule *);
+void peepRules2pCode(peepRule *);
+#endif
+
+#if !OPT_DISABLE_PIC16
+void pic16_peepRules2pCode(peepRule *);
#endif
/*-----------------------------------------------------------------*/
/* pcDistance - afinds a label back ward or forward */
/*-----------------------------------------------------------------*/
-int
-mcs51_instruction_size(const char *inst)
-{
- char *op, op1[256], op2[256];
- int opsize;
- const char *p;
-
- while (*inst && isspace(*inst)) inst++;
-
- #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
- if (ISINST("lcall")) return 3;
- if (ISINST("ret")) return 1;
- if (ISINST("ljmp")) return 3;
- if (ISINST("sjmp")) return 2;
- if (ISINST("rlc")) return 1;
- if (ISINST("rrc")) return 1;
- if (ISINST("rl")) return 1;
- if (ISINST("rr")) return 1;
- if (ISINST("swap")) return 1;
- if (ISINST("movx")) return 1;
- if (ISINST("movc")) return 1;
- if (ISINST("push")) return 2;
- if (ISINST("pop")) return 2;
- if (ISINST("jc")) return 2;
- if (ISINST("jnc")) return 2;
- if (ISINST("jb")) return 3;
- if (ISINST("jnb")) return 3;
- if (ISINST("jbc")) return 3;
- if (ISINST("jmp")) return 1; // always jmp @a+dptr
- if (ISINST("jz")) return 2;
- if (ISINST("jnz")) return 2;
- if (ISINST("cjne")) return 3;
- if (ISINST("mul")) return 1;
- if (ISINST("div")) return 1;
- if (ISINST("da")) return 1;
- if (ISINST("xchd")) return 1;
- if (ISINST("reti")) return 1;
- if (ISINST("nop")) return 1;
- if (ISINST("acall")) return 1;
- if (ISINST("ajmp")) return 2;
-
- p = inst;
- while (*p && isalnum(*p)) p++;
- for (op = op1, opsize=0; *p && *p != ',' && opsize < sizeof(op1); p++) {
- if (!isspace(*p)) *op++ = *p, opsize++;
- }
- *op = '\0';
- if (*p == ',') p++;
- for (op = op2, opsize=0; *p && *p != ',' && opsize < sizeof(op2); p++) {
- if (!isspace(*p)) *op++ = *p, opsize++;
- }
- *op = '\0';
-
- #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
- #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
- #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
- #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
-
- if (ISINST("mov")) {
- if (IS_C(op1) || IS_C(op2)) return 2;
- if (IS_A(op1)) {
- if (IS_Rn(op2) || IS_atRi(op2)) return 1;
- return 2;
- }
- if (IS_Rn(op1) || IS_atRi(op1)) {
- if (IS_A(op2)) return 1;
- return 2;
- }
- if (strcmp(op1, "dptr") == 0) return 3;
- if (IS_A(op2) || IS_Rn(op2) || IS_atRi(op2)) return 2;
- return 3;
- }
- if (ISINST("add") || ISINST("addc") || ISINST("subb") || ISINST("xch")) {
- if (IS_Rn(op2) || IS_atRi(op2)) return 1;
- return 2;
- }
- if (ISINST("inc") || ISINST("dec")) {
- if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
- if (strcmp(op1, "dptr") == 0) return 1;
- return 2;
- }
- if (ISINST("anl") || ISINST("orl") || ISINST("xrl")) {
- if (IS_C(op1)) return 2;
- if (IS_A(op1)) {
- if (IS_Rn(op2) || IS_atRi(op2)) return 1;
- return 2;
- } else {
- if (IS_A(op2)) return 2;
- return 3;
- }
- }
- if (ISINST("clr") || ISINST("setb") || ISINST("cpl")) {
- if (IS_A(op1) || IS_C(op1)) return 1;
- return 2;
- }
- if (ISINST("djnz")) {
- if (IS_Rn(op1)) return 2;
- return 3;
- }
-
- if (*inst == 'a' && *(inst+1) == 'r' && *(inst+2) >= '0' && *(inst+2) <= '7' && op1[0] == '=') {
- /* ignore ar0 = 0x00 type definitions */
- return 0;
- }
-
- fprintf(stderr, "Warning, peephole unrecognized instruction: %s\n", inst);
- return 3;
-}
int
pcDistance (lineNode * cpos, char *lbl, bool back)
*pl->line != ';' &&
pl->line[strlen (pl->line) - 1] != ':' &&
!pl->isDebug) {
- if (strcmp(port->target,"mcs51") == 0) {
- dist += mcs51_instruction_size(pl->line);
+ if (port->peep.getSize) {
+ dist += port->peep.getSize(pl);
} else {
dist += 3;
}
/*-----------------------------------------------------------------*/
FBYNAME (flat24bitModeAndPortDS390)
{
- return ((strcmp(port->target,"ds390") == 0) &&
+ return (((strcmp(port->target,"ds390") == 0) ||
+ (strcmp(port->target,"ds400") == 0)) &&
(options.model == MODEL_FLAT24));
}
/*-----------------------------------------------------------------*/
FBYNAME (portIsDS390)
{
- return (strcmp(port->target,"ds390") == 0);
+ return ((strcmp(port->target,"ds390") == 0) ||
+ (strcmp(port->target,"ds400") == 0));
}
/*-----------------------------------------------------------------*/
if (!lbl)
return FALSE;
+ /* Don't optimize jumps in a jump table; a more generic test */
+ if (currPl->ic && currPl->ic->op == JUMPTABLE)
+ 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 &&
return rc;
}
+/* Within the context of the lines currPl through endPl, determine
+** if the variable var contains a symbol that is volatile. Returns
+** TRUE only if it is certain that this was not volatile (the symbol
+** was found and not volatile, or var was a constant or CPU register).
+** Returns FALSE if the symbol was found and volatile, the symbol was
+** not found, or var was a indirect/pointer addressing mode.
+*/
+static bool
+notVolatileVariable(char *var, lineNode *currPl, lineNode *endPl)
+{
+ char symname[SDCC_NAME_MAX + 1];
+ char *p = symname;
+ char *vp = var;
+ lineNode *cl;
+ operand *op;
+ iCode *last_ic;
+
+ /* Can't tell if indirect accesses are volatile or not, so
+ ** assume they are, just to be safe.
+ */
+ if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)
+ {
+ if (*var=='@')
+ return FALSE;
+ }
+ if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
+ {
+ if (strstr(var,"(bc)"))
+ return FALSE;
+ if (strstr(var,"(de)"))
+ return FALSE;
+ if (strstr(var,"(hl)"))
+ return FALSE;
+ if (strstr(var,"(ix"))
+ return FALSE;
+ if (strstr(var,"(iy"))
+ return FALSE;
+ }
+
+ /* Extract a symbol name from the variable */
+ while (*vp && (*vp!='_'))
+ vp++;
+ while (*vp && (isalnum(*vp) || *vp=='_'))
+ *p++ = *vp++;
+ *p='\0';
+
+ if (!symname[0])
+ {
+ /* Nothing resembling a symbol name was found, so it can't
+ be volatile
+ */
+ return TRUE;
+ }
+
+ last_ic = NULL;
+ for (cl = currPl; cl!=endPl->next; cl = cl->next)
+ {
+ if (cl->ic && (cl->ic!=last_ic))
+ {
+ last_ic = cl->ic;
+ switch (cl->ic->op)
+ {
+ case IFX:
+ op = IC_COND (cl->ic);
+ if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
+ return !op->isvolatile;
+ case JUMPTABLE:
+ op = IC_JTCOND (cl->ic);
+ if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
+ return !op->isvolatile;
+ default:
+ op = IC_LEFT (cl->ic);
+ if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
+ return !op->isvolatile;
+ op = IC_RIGHT (cl->ic);
+ if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
+ return !op->isvolatile;
+ op = IC_RESULT (cl->ic);
+ if (IS_SYMOP (op) && !strcmp(OP_SYMBOL (op)->rname,symname) )
+ return !op->isvolatile;
+ }
+ }
+ }
+
+ /* Couldn't find the symbol for some reason. Assume volatile. */
+ return FALSE;
+}
+
+/* notVolatile:
+ *
+ * This rule restriction has two different behaviours depending on
+ * the number of parameters given.
+ *
+ * if notVolatile (no parameters given)
+ * The rule is applied only if none of the iCodes originating
+ * the matched pattern reference a volatile operand.
+ *
+ * if notVolatile %1 ... (one or more parameters given)
+ * The rule is applied if the parameters are not expressions
+ * containing volatile symbols and are not pointer accesses.
+ *
+ */
+FBYNAME (notVolatile)
+{
+ int varNumber;
+ char *var;
+ bool notvol;
+ char *digitend;
+ lineNode *cl;
+ operand *op;
+
+ if (!cmdLine)
+ {
+ /* If no parameters given, just scan the iCodes for volatile operands */
+ for (cl = currPl; cl!=endPl->next; cl = cl->next)
+ {
+ if (cl->ic)
+ {
+ switch (cl->ic->op)
+ {
+ case IFX:
+ op = IC_COND (cl->ic);
+ if (IS_SYMOP (op) && op->isvolatile)
+ return FALSE;
+ case JUMPTABLE:
+ op = IC_JTCOND (cl->ic);
+ if (IS_SYMOP (op) && op->isvolatile)
+ return FALSE;
+ default:
+ op = IC_LEFT (cl->ic);
+ if (IS_SYMOP (op) && op->isvolatile)
+ return FALSE;
+ op = IC_RIGHT (cl->ic);
+ if (IS_SYMOP (op) && op->isvolatile)
+ return FALSE;
+ op = IC_RESULT (cl->ic);
+ if (IS_SYMOP (op) && op->isvolatile)
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
+
+ /* There were parameters; check the volatility of each */
+ while (*cmdLine && isspace(*cmdLine))
+ cmdLine++;
+ while (*cmdLine)
+ {
+ if (*cmdLine!='%')
+ goto error;
+ cmdLine++;
+ if (!isdigit(*cmdLine))
+ goto error;
+ varNumber = strtol(cmdLine, &digitend, 10);
+ cmdLine = digitend;
+ while (*cmdLine && isspace(*cmdLine))
+ cmdLine++;
+
+ var = hTabItemWithKey (vars, varNumber);
+
+ if (var)
+ {
+ notvol = notVolatileVariable (var, currPl, endPl);
+ if (!notvol)
+ return FALSE;
+ }
+ else
+ {
+ fprintf (stderr, "*** internal error: var %d not bound"
+ " in peephole notVolatile rule.\n",
+ varNumber);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+
+error:
+ fprintf (stderr,
+ "*** internal error: notVolatile peephole restriction"
+ " malformed: %s\n", cmdLine);
+ return FALSE;
+}
+
+
/*-----------------------------------------------------------------*/
/* callFuncByName - calls a function as defined in the table */
/*-----------------------------------------------------------------*/
},
{
"24bitModeAndPortDS390", flat24bitModeAndPortDS390
+ },
+ {
+ "notVolatile", notVolatile
}
};
int i;
}
}
- Safe_free(cmdCopy);
-
if (rc == -1)
{
fprintf (stderr,
// a bad rule and refuse it.
rc = FALSE;
}
+
+ Safe_free(cmdCopy);
return rc;
}
void
printLine (lineNode * head, FILE * of)
{
+ iCode *last_ic = NULL;
+ bool debug_iCode_tracking = (getenv("DEBUG_ICODE_TRACKING")!=NULL);
+
if (!of)
of = stdout;
while (head)
{
+ if (head->ic!=last_ic)
+ {
+ last_ic = head->ic;
+ if (debug_iCode_tracking)
+ {
+ if (head->ic)
+ fprintf (of, "; block = %d, seq = %d\n",
+ head->ic->block, head->ic->seq);
+ else
+ fprintf (of, "; iCode lost\n");
+ }
+ }
+
/* don't indent comments & labels */
if (head->line &&
(*head->line == ';' ||
pl = Safe_alloc ( sizeof (lineNode));
pl->line = Safe_strdup (line);
+ pl->ic = NULL;
return pl;
}
{
char lines[MAX_PATTERN_LEN];
char *lp;
+ int isComment;
lineNode *currL = NULL;
char *bp = *bpp;
lp = lines;
while ((*bp != '\n' && *bp != '}') && *bp)
*lp++ = *bp++;
-
*lp = '\0';
- if (!currL)
- *head = currL = newLineNode (lines);
- else
- currL = connectLine (currL, newLineNode (lines));
+
+ lp = lines;
+ while (*lp && isspace(*lp))
+ lp++;
+ isComment = (*lp == ';');
+
+ if (!isComment || (isComment && !options.noPeepComments))
+ {
+ if (!currL)
+ *head = currL = newLineNode (lines);
+ else
+ currL = connectLine (currL, newLineNode (lines));
+ currL->isComment = isComment;
+ }
+
}
*bpp = bp;
d++;
/* if the destination is a var */
- if (*d == '%' && isdigit (*(d + 1)))
+ if (*d == '%' && isdigit (*(d + 1)) && vars)
{
char *v = hTabItemWithKey (*vars, keyForVar (d + 1));
/* if the variable is already bound
d++;
while (isdigit (*d))
d++;
- }
- /* they should be an exact match other wise */
- if (*s && *d)
- {
while (isspace (*s))
s++;
while (isspace (*d))
d++;
+ }
+
+ /* they should be an exact match other wise */
+ if (*s && *d)
+ {
if (*s++ != *d++)
return FALSE;
}
lineNode *spl; /* source pl */
lineNode *rpl; /* rule peep line */
-/* setToNull((void **) &pr->vars); */
+/* setToNull((void *) &pr->vars); */
/* pr->vars = newHashTable(100); */
/* for all the lines defined in the rule */
return FALSE;
}
+static void
+reassociate_ic_down (lineNode *shead, lineNode *stail,
+ lineNode *rhead, lineNode *rtail)
+{
+ lineNode *csl; /* current source line */
+ lineNode *crl; /* current replacement line */
+
+ csl = shead;
+ crl = rhead;
+ while (1)
+ {
+ /* skip over any comments */
+ while (csl!=stail->next && csl->isComment)
+ csl = csl->next;
+ while (crl!=rtail->next && crl->isComment)
+ crl = crl->next;
+
+ /* quit if we reach the end */
+ if ((csl==stail->next) || (crl==rtail->next) || crl->ic)
+ break;
+
+ if (matchLine(csl->line,crl->line,NULL))
+ {
+ crl->ic = csl->ic;
+ csl = csl->next;
+ crl = crl->next;
+ }
+ else
+ break;
+ }
+}
+
+static void
+reassociate_ic_up (lineNode *shead, lineNode *stail,
+ lineNode *rhead, lineNode *rtail)
+{
+ lineNode *csl; /* current source line */
+ lineNode *crl; /* current replacement line */
+
+ csl = stail;
+ crl = rtail;
+ while (1)
+ {
+ /* skip over any comments */
+ while (csl!=shead->prev && csl->isComment)
+ csl = csl->prev;
+ while (crl!=rhead->prev && crl->isComment)
+ crl = crl->prev;
+
+ /* quit if we reach the end */
+ if ((csl==shead->prev) || (crl==rhead->prev) || crl->ic)
+ break;
+
+ if (matchLine(csl->line,crl->line,NULL))
+ {
+ crl->ic = csl->ic;
+ csl = csl->prev;
+ crl = crl->prev;
+ }
+ else
+ break;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* reassociate_ic - reassociate replacement lines with origin iCode */
+/*------------------------------------------------------------------*/
+static void
+reassociate_ic (lineNode *shead, lineNode *stail,
+ lineNode *rhead, lineNode *rtail)
+{
+ lineNode *csl; /* current source line */
+ lineNode *crl; /* current replacement line */
+ bool single_iCode;
+ iCode *ic;
+
+ /* Check to see if all the source lines (excluding comments) came
+ ** for the same iCode
+ */
+ ic = NULL;
+ for (csl=shead;csl!=stail->next;csl=csl->next)
+ if (csl->ic && !csl->isComment)
+ {
+ ic = csl->ic;
+ break;
+ }
+ single_iCode = (ic!=NULL);
+ for (csl=shead;csl!=stail->next;csl=csl->next)
+ if ((csl->ic != ic) && !csl->isComment)
+ {
+ /* More than one iCode was found. However, if it's just the
+ ** last line with the different iCode and it was not changed
+ ** in the replacement, everything else must be the first iCode.
+ */
+ if ((csl==stail) && matchLine (stail->line, rtail->line, NULL))
+ {
+ rtail->ic = stail->ic;
+ for (crl=rhead;crl!=rtail;crl=crl->next)
+ crl->ic = ic;
+ return;
+ }
+
+ single_iCode = FALSE;
+ break;
+ }
+
+ /* If all of the source lines came from the same iCode, then so have
+ ** all of the replacement lines too.
+ */
+ if (single_iCode)
+ {
+ for (crl=rhead;crl!=rtail->next;crl=crl->next)
+ crl->ic = ic;
+ return;
+ }
+
+ /* The source lines span iCodes, so we may end up with replacement
+ ** lines that we don't know which iCode(s) to associate with. Do the
+ ** best we can by using the following strategies:
+ ** 1) Start at the top and scan down. As long as the source line
+ ** matches the replacement line, they have the same iCode.
+ ** 2) Start at the bottom and scan up. As long as the source line
+ ** matches the replacement line, they have the same iCode.
+ ** 3) For any label in the source, look for a matching label in
+ ** the replacment. If found, they have the same iCode. From
+ ** these matching labels, scan down for additional matching
+ ** lines; if found, they also have the same iCode.
+ */
+
+ /* Strategy #1: Start at the top and scan down for matches
+ */
+ reassociate_ic_down(shead,stail,rhead,rtail);
+
+ /* Strategy #2: Start at the bottom and scan up for matches
+ */
+ reassociate_ic_up(shead,stail,rhead,rtail);
+
+ /* Strategy #3: Try to match labels
+ */
+ csl = shead;
+ while (1)
+ {
+ const char *labelStart;
+ int labelLength;
+
+ /* skip over any comments */
+ while (csl!=stail->next && csl->isComment)
+ csl = csl->next;
+ if (csl==stail->next)
+ break;
+
+ if (isLabelDefinition(csl->line, &labelStart, &labelLength))
+ {
+ /* found a source line label; look for it in the replacment lines */
+ crl = rhead;
+ while (1)
+ {
+ while (crl!=rtail->next && crl->isComment)
+ crl = crl->next;
+ if (crl==rtail->next)
+ break;
+ if (matchLine(csl->line, crl->line, NULL))
+ {
+ reassociate_ic_down(csl,stail,crl,rtail);
+ break;
+ }
+ else
+ crl = crl->next;
+ }
+ }
+ csl = csl->next;
+ }
+
+ /* Try to assign a meaningful iCode to any comment that is missing
+ one. Since they are comments, it's ok to make mistakes; we are just
+ trying to improve continuity to simplify other tests.
+ */
+ ic = NULL;
+ for (crl=rtail;crl!=rhead->prev;crl=crl->prev)
+ {
+ if (!crl->ic && ic && crl->isComment)
+ crl->ic = ic;
+ ic = crl->ic;
+ }
+}
+
+
/*-----------------------------------------------------------------*/
/* replaceRule - does replacement of a matching pattern */
/*-----------------------------------------------------------------*/
pl = (pl ? connectLine (pl, newLineNode (cl->line)) :
(comment = newLineNode (cl->line)));
pl->isDebug = cl->isDebug;
+ pl->isComment = cl->isComment || (*cl->line == ';');
}
}
cl = NULL;
cl = connectLine (cl, newLineNode (lb));
else
lhead = cl = newLineNode (lb);
+ cl->isComment = pl->isComment;
}
/* add the comments if any to the head of list */
lhead = comment;
}
- /* now we need to connect / replace the original chain */
- /* if there is a prev then change it */
- if ((*shead)->prev)
+ if (lhead)
{
- (*shead)->prev->next = lhead;
- lhead->prev = (*shead)->prev;
+ /* determine which iCodes the replacment lines relate to */
+ reassociate_ic(*shead,stail,lhead,cl);
+
+ /* 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;
+ }
+ *shead = lhead;
+ /* now for the tail */
+ if (stail && stail->next)
+ {
+ stail->next->prev = cl;
+ if (cl)
+ cl->next = stail->next;
+ }
}
- *shead = lhead;
- /* now for the tail */
- if (stail && stail->next)
+ else
{
- stail->next->prev = cl;
- if (cl)
- cl->next = stail->next;
+ /* the replacement is empty - delete the source lines */
+ if ((*shead)->prev)
+ (*shead)->prev->next = stail->next;
+ if (stail->next)
+ stail->next->prev = (*shead)->prev;
+ *shead = stail->next;
}
}
lineNode *mtail = NULL;
bool restart;
-#if !OPT_DISABLE_PIC
+#if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
/* The PIC port uses a different peep hole optimizer based on "pCode" */
- if (TARGET_IS_PIC)
+ if (TARGET_IS_PIC || TARGET_IS_PIC16)
return;
#endif
/* if inline assembler then no peep hole */
if (spl->isInline)
continue;
+
+ /* don't waste time starting a match on debug symbol
+ ** or comment */
+ if (spl->isDebug || spl->isComment || *(spl->line)==';')
+ continue;
mtail = NULL;
if (options.peep_file)
{
readRules (s = readFileIntoBuffer (options.peep_file));
- setToNull ((void **) &s);
+ setToNull ((void *) &s);
}
/* Convert the peep rules into pcode.
NOTE: this is only support in the PIC port (at the moment)
*/
- if (TARGET_IS_PIC) {
- peepRules2pCode(rootRules);
- }
+ if (TARGET_IS_PIC)
+ peepRules2pCode(rootRules);
+#endif
+
+#if !OPT_DISABLE_PIC16
+ /* Convert the peep rules into pcode.
+ NOTE: this is only support in the PIC port (at the moment)
+ and the PIC16 port (VR 030601)
+ */
+ if (TARGET_IS_PIC16)
+ pic16_peepRules2pCode(rootRules);
+
#endif
}