X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCpeeph.c;h=269465814a99369fce1e1c27a89101bd6c96f32f;hb=19fdf6efc7b53ac971bbbba19fda314f0fa3db87;hp=e052e3ea6b28ceca3a6e24b2a199c0318ab60840;hpb=ea1b8716bdb4c19fc4ca7fec3ce8259a506a6df3;p=fw%2Fsdcc diff --git a/src/SDCCpeeph.c b/src/SDCCpeeph.c index e052e3ea..26946581 100644 --- a/src/SDCCpeeph.c +++ b/src/SDCCpeeph.c @@ -48,125 +48,22 @@ static int hashSymbolName (const char *name); 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) + lineNode *head, 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) @@ -183,8 +80,8 @@ 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; } @@ -207,7 +104,8 @@ pcDistance (lineNode * cpos, char *lbl, bool back) /*-----------------------------------------------------------------*/ FBYNAME (flat24bitModeAndPortDS390) { - return ((strcmp(port->target,"ds390") == 0) && + return (((strcmp(port->target,"ds390") == 0) || + (strcmp(port->target,"ds400") == 0)) && (options.model == MODEL_FLAT24)); } @@ -216,7 +114,8 @@ FBYNAME (flat24bitModeAndPortDS390) /*-----------------------------------------------------------------*/ FBYNAME (portIsDS390) { - return (strcmp(port->target,"ds390") == 0); + return ((strcmp(port->target,"ds390") == 0) || + (strcmp(port->target,"ds400") == 0)); } /*-----------------------------------------------------------------*/ @@ -252,6 +151,10 @@ FBYNAME (labelInRange) 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 && @@ -275,6 +178,51 @@ FBYNAME (labelInRange) return TRUE; } + +/*-----------------------------------------------------------------*/ +/* labelJTInRange - will check to see if label %5 and up are */ +/* within range. */ +/* Specifically meant to optimize long (3-byte) jumps to short */ +/* (2-byte) jumps in jumptables */ +/*-----------------------------------------------------------------*/ +FBYNAME (labelJTInRange) +{ + char *lbl; + int dist, count, i; + + if (!getenv("SDCC_SJMP_JUMPTABLE")) + return FALSE; + + /* Only optimize within a jump table */ + if (currPl->ic && currPl->ic->op != JUMPTABLE) + return FALSE; + + count = elementsInSet( IC_JTLABELS (currPl->ic) ); + + /* check all labels (this is needed if the case statements are unsorted) */ + for (i=0; i 127+ /* range of sjmp */ + (7+3*i)+ /* offset between this jump and currPl, + should use pcDistance instead? */ + (count-i-1) /* if peephole applies distance is shortened */ + ) + return FALSE; + } + return TRUE; +} + + /*-----------------------------------------------------------------*/ /* labelIsReturnOnly - Check if label %5 is followed by RET */ /*-----------------------------------------------------------------*/ @@ -284,13 +232,14 @@ FBYNAME (labelIsReturnOnly) const char *label, *p; const lineNode *pl; int len; + char * retInst; label = hTabItemWithKey (vars, 5); if (!label) return FALSE; len = strlen(label); for(pl = currPl; pl; pl = pl->next) { - if (pl->line && !pl->isDebug && + if (pl->line && !pl->isDebug && !pl->isComment && pl->line[strlen(pl->line)-1] == ':') { if (strncmp(pl->line, label, len) == 0) break; /* Found Label */ if (strlen(pl->line) != 7 || !isdigit(*(pl->line)) || @@ -303,11 +252,17 @@ FBYNAME (labelIsReturnOnly) } if (!pl) return FALSE; /* did not find the label */ pl = pl->next; + while (pl && (pl->isDebug || pl->isComment)) + pl = pl->next; if (!pl || !pl->line || pl->isDebug) return FALSE; /* next line not valid */ p = pl->line; for (p = pl->line; *p && isspace(*p); p++) ; - if (strcmp(p, "ret") == 0) return TRUE; + + retInst = "ret"; + if (TARGET_IS_HC08) + retInst = "rts"; + if (strcmp(p, retInst) == 0) return TRUE; return FALSE; } @@ -617,6 +572,393 @@ FBYNAME (labelRefCount) return rc; } + +/* labelRefCountChange: + * takes two parameters: a variable (bound to a label name) + * and a signed int for changing the reference count. + * + * Please note, this function is not a conditional. It unconditionally + * changes the label. It should be passed as the 'last' function + * so it only is applied if all other conditions have been met. + * + * should always return TRUE + */ +FBYNAME (labelRefCountChange) +{ + int varNumber, RefCountDelta; + bool rc = FALSE; + + /* If we don't have the label hash table yet, build it. */ + if (!labelHash) + { + buildLabelRefCountHash (head); + } + + if (sscanf (cmdLine, "%*[ \t%]%d %i", &varNumber, &RefCountDelta) == 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 <= entry->refCount + RefCountDelta) + { + entry->refCount += RefCountDelta; + rc = TRUE; + } + else + { + fprintf (stderr, "*** internal error: label %s may not get" + " negative refCount in %s peephole.\n", + label, __FUNCTION__); + } + } + else + { + fprintf (stderr, "*** internal error: no label has entry for" + " %s in %s peephole.\n", + label, __FUNCTION__); + } + } + else + { + fprintf (stderr, "*** internal error: var %d not bound" + " in peephole %s rule.\n", + varNumber, __FUNCTION__); + } + } + else + { + fprintf (stderr, + "*** internal error: labelRefCount peephole restriction" + " malformed: %s\n", cmdLine); + } + 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; +} + + +/*------------------------------------------------------------------*/ +/* setFromConditionArgs - parse a peephole condition's arguments */ +/* to produce a set of strings, one per argument. Variables %x will */ +/* be replaced with their values. String literals (in single quotes)*/ +/* are accepted and return in unquoted form. */ +/*------------------------------------------------------------------*/ +static set * +setFromConditionArgs (char *cmdLine, hTab * vars) +{ + int varNumber; + char *var; + char *digitend; + set *operands = NULL; + + if (!cmdLine) + return NULL; + + while (*cmdLine && isspace(*cmdLine)) + cmdLine++; + + while (*cmdLine) + { + if (*cmdLine == '%') + { + cmdLine++; + if (!isdigit(*cmdLine)) + goto error; + varNumber = strtol(cmdLine, &digitend, 10); + cmdLine = digitend; + + var = hTabItemWithKey (vars, varNumber); + + if (var) + { + addSetHead (&operands, var); + } + else + goto error; + } + else if (*cmdLine == '\'' ) + { + char quote = *cmdLine; + + var = ++cmdLine; + while (*cmdLine && *cmdLine != quote) + cmdLine++; + if (*cmdLine == quote) + *cmdLine++ = '\0'; + else + goto error; + addSetHead (&operands, var); + } + else + goto error; + + while (*cmdLine && isspace(*cmdLine)) + cmdLine++; + } + + return operands; + +error: + deleteSet (&operands); + return NULL; +} + +static const char * +operandBaseName (const char *op) +{ + if (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400) + { + if (!strcmp (op, "acc") || !strncmp (op, "acc.", 4)) + return "a"; + if (!strncmp (op, "ar", 2) && isdigit(*(op+2)) && !*(op+3)) + return op+1; + } + + return op; +} + + +/*-------------------------------------------------------------------*/ +/* operandsNotRelated - returns true of the condition's operands are */ +/* not related (taking into account register name aliases). N-way */ +/* comparison performed between all operands. */ +/*-------------------------------------------------------------------*/ +FBYNAME (operandsNotRelated) +{ + set *operands; + const char *op1, *op2; + + operands = setFromConditionArgs (cmdLine, vars); + + if (!operands) + { + fprintf (stderr, + "*** internal error: operandsNotRelated peephole restriction" + " malformed: %s\n", cmdLine); + return FALSE; + } + + while ((op1 = setFirstItem (operands))) + { + deleteSetItem (&operands, (void*)op1); + op1 = operandBaseName (op1); + + for (op2 = setFirstItem (operands); op2; op2 = setNextItem (operands)) + { + op2 = operandBaseName (op2); + if (strcmp (op1, op2) == 0) + { + deleteSet (&operands); + return FALSE; + } + } + } + + deleteSet (&operands); + return TRUE; +} + + /*-----------------------------------------------------------------*/ /* callFuncByName - calls a function as defined in the table */ /*-----------------------------------------------------------------*/ @@ -630,7 +972,7 @@ callFuncByName (char *fname, struct ftab { char *fname; - int (*func) (hTab *, lineNode *, lineNode *, lineNode *, const char *); + int (*func) (hTab *, lineNode *, lineNode *, lineNode *, char *); } ftab[] = { @@ -638,6 +980,10 @@ callFuncByName (char *fname, "labelInRange", labelInRange } , + { + "labelJTInRange", labelJTInRange + } + , { "operandsNotSame", operandsNotSame } @@ -689,40 +1035,96 @@ callFuncByName (char *fname, }, { "24bitModeAndPortDS390", flat24bitModeAndPortDS390 + }, + { + "notVolatile", notVolatile + }, + { + "operandsNotRelated", operandsNotRelated + }, + { + "labelRefCountChange", labelRefCountChange } }; int i; - char *cmdCopy, *funcName, *funcArgs; - int rc = -1; + char *cmdCopy, *funcName, *funcArgs, *cmdTerm; + char c; + int rc; /* Isolate the function name part (we are passed the full condition * string including arguments) */ - cmdCopy = Safe_strdup(fname); - funcName = strtok(cmdCopy, " \t"); - funcArgs = strtok(NULL, ""); - - for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++) + cmdTerm = cmdCopy = Safe_strdup(fname); + + do { - if (strcmp (ftab[i].fname, funcName) == 0) - { - rc = (*ftab[i].func) (vars, currPl, endPl, head, - funcArgs); - } - } - - Safe_free(cmdCopy); + funcArgs = funcName = cmdTerm; + while ((c = *funcArgs) && c != ' ' && c != '\t' && c != '(') + funcArgs++; + *funcArgs = '\0'; /* terminate the function name */ + if (c) + funcArgs++; + + /* Find the start of the arguments */ + if (c == ' ' || c == '\t') + while ((c = *funcArgs) && (c == ' ' || c == '\t')) + funcArgs++; + + /* If the arguments started with an opening parenthesis, */ + /* use the closing parenthesis for the end of the */ + /* arguments and look for the start of another condition */ + /* that can optionally follow. If there was no opening */ + /* parethesis, then everything that follows are arguments */ + /* and there can be no additional conditions. */ + if (c == '(') + { + cmdTerm = funcArgs; + while ((c = *cmdTerm) && c != ')') + cmdTerm++; + *cmdTerm = '\0'; /* terminate the arguments */ + if (c == ')') + { + cmdTerm++; + while ((c = *cmdTerm) && (c == ' ' || c == '\t' || c == ',')) + cmdTerm++; + if (!*cmdTerm) + cmdTerm = NULL; + } + else + cmdTerm = NULL; /* closing parenthesis missing */ + } + else + cmdTerm = NULL; + + if (!*funcArgs) + funcArgs = NULL; + + rc = -1; + for (i = 0; i < ((sizeof (ftab)) / (sizeof (struct ftab))); i++) + { + if (strcmp (ftab[i].fname, funcName) == 0) + { + rc = (*ftab[i].func) (vars, currPl, endPl, head, + funcArgs); + break; + } + } - if (rc == -1) - { - fprintf (stderr, - "could not find named function \"%s\" in " - "peephole function table\n", - funcName); - // If the function couldn't be found, let's assume it's - // a bad rule and refuse it. - rc = FALSE; + if (rc == -1) + { + fprintf (stderr, + "could not find named function \"%s\" in " + "peephole function table\n", + funcName); + // If the function couldn't be found, let's assume it's + // a bad rule and refuse it. + rc = FALSE; + break; + } } + while (rc && cmdTerm); + + Safe_free(cmdCopy); return rc; } @@ -733,11 +1135,27 @@ callFuncByName (char *fname, 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 == ';' || @@ -798,6 +1216,7 @@ newLineNode (char *line) pl = Safe_alloc ( sizeof (lineNode)); pl->line = Safe_strdup (line); + pl->ic = NULL; return pl; } @@ -835,6 +1254,7 @@ getPeepLine (lineNode ** head, char **bpp) { char lines[MAX_PATTERN_LEN]; char *lp; + int isComment; lineNode *currL = NULL; char *bp = *bpp; @@ -865,12 +1285,22 @@ getPeepLine (lineNode ** head, char **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; @@ -1058,7 +1488,7 @@ matchLine (char *s, char *d, hTab ** vars) 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 @@ -1078,15 +1508,16 @@ matchLine (char *s, char *d, hTab ** vars) 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; } @@ -1123,7 +1554,7 @@ matchRule (lineNode * pl, 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 */ @@ -1174,6 +1605,193 @@ matchRule (lineNode * pl, 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 */ /*-----------------------------------------------------------------*/ @@ -1196,6 +1814,7 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr) pl = (pl ? connectLine (pl, newLineNode (cl->line)) : (comment = newLineNode (cl->line))); pl->isDebug = cl->isDebug; + pl->isComment = cl->isComment || (*cl->line == ';'); } } cl = NULL; @@ -1238,6 +1857,7 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr) cl = connectLine (cl, newLineNode (lb)); else lhead = cl = newLineNode (lb); + cl->isComment = pl->isComment; } /* add the comments if any to the head of list */ @@ -1252,20 +1872,35 @@ replaceRule (lineNode ** shead, lineNode * stail, peepRule * pr) 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; } } @@ -1359,6 +1994,12 @@ buildLabelRefCountHash (lineNode * head) memcpy (entry->name, label, labelLen); entry->name[labelLen] = 0; entry->refCount = -1; + + /* Assume function entry points are referenced somewhere, */ + /* even if we can't find a reference (might be from outside */ + /* the function) */ + if (line->ic && (line->ic->op == FUNCTION)) + entry->refCount++; hTabAddItem (&labelHash, hashSymbolName (entry->name), entry); } @@ -1433,9 +2074,9 @@ peepHole (lineNode ** pls) 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 @@ -1453,6 +2094,11 @@ peepHole (lineNode ** pls) /* 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; @@ -1570,7 +2216,7 @@ initPeepHole () if (options.peep_file) { readRules (s = readFileIntoBuffer (options.peep_file)); - setToNull ((void **) &s); + setToNull ((void *) &s); } @@ -1578,9 +2224,18 @@ initPeepHole () /* 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 }