-2006-12-36 Borut Razem <borut.razem AT siol.net>
+2006-12-26 Bernhard Held <bernhard AT bernhardheld.de>
+
+ * src/SDCCpeeph.c: made labelHashEntry global,
+ made pcDistance, FBYNAME static,
+ (pcDistance): made static, use isComment and isLabel,
+ (deadMove): added,
+ (getLabelRef): added, extracted from labelRefCount(),
+ (labelRefCount): use new getLabelRef(),
+ (callFuncByName): made static, added deadMove,
+ use isComment and isLabel,
+ (newPeepRule): made static, set isLabel,
+ (isLabelDefinition): added parameter isPeepRule to allow '%' in
+ labels from peephole rules,
+ (buildLabelRefCountHash): speed up by running isLabelDefinition() only
+ when isComment or isLabel is set
+ * src/SDCCpeeph.h: added "isLabel" and "visited" to struct lineNode,
+ added labelHashEntry, isLabelDefinition, labelHash and getLabelRef
+ to make them global
+ * src/mcs51/peep.h: added
+ * src/mcs51/peep.c: added, implements mcs51DeadMove()
+ * src/port.h: added peep->deadMove to port structure
+ * src/mcs51/main.c: initialize peep->deadMove with mcs51DeadMove
+ * src/mcs51/peeph.def: renumbered rule 300 to 400, added new rule 300
+ deadMove, finally removed no. 1 and 2
+ * src/mcs51/gen.c,
+ * src/pic/gen.c,
+ * src/z80/gen.c,
+ * src/z80/ralloc.c,
+ * src/pic16/gen.c,
+ * src/ds390/gen.c,
+ * src/hc08/gen.c: mark lines with isComment or isLabel
+ * sim/ucsim/s51.src/uc390hw.cc: don't waist 65535 ticks before CKRDY
+ * .version,
+ * sdcc.spec: bumped version to 2.6.3
+
+2006-12-26 Borut Razem <borut.razem AT siol.net>
* support/cpp2/Makefile.in: added dependency on options.h
* configure: regenerated
Group: Applications/Engineering
Summary: Small Device C Compiler
Requires: sdcc-common
-Version: 2.6.0
+Version: 2.6.3
Release: 2
Source: %{name}-src-%{version}.tar.gz
URL: http://sdcc.sourceforge.net/
%doc %{_defaultdocdir}
%changelog
+* Sun Dec 26 2006 - bernhard AT bernhardheld.de
+- version updated
+* Sun Sep 03 2006 - Christer Weinigel
+- fixed build of doc
* Tue Mar 09 2004 - bernhard AT bernhardheld.de
- split into two packages
* Wed Feb 26 2004 - bernhard AT bernhardheld.de
if (cell == cell_exif)
{
if (ctm_ticks &&
- uc390->ticks->ticks >= ctm_ticks + 65535)
+ uc390->ticks->ticks >= ctm_ticks + 50 /*65535*/)
{
ctm_ticks = 0;
cell->set (cell->get() | 0x08); /* set CKRDY */
static peepRule *currRule = NULL;
#define HTAB_SIZE 53
-typedef struct
- {
- char name[SDCC_NAME_MAX + 1];
- int refCount;
- }
-labelHashEntry;
-static hTab *labelHash = NULL;
+hTab *labelHash = NULL;
static struct
{
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, \
+#define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
lineNode *head, char *cmdLine)
#if !OPT_DISABLE_PIC
/* pcDistance - afinds a label back ward or forward */
/*-----------------------------------------------------------------*/
-int
+static int
pcDistance (lineNode * cpos, char *lbl, bool back)
{
lineNode *pl = cpos;
{
if (pl->line &&
- *pl->line != ';' &&
- pl->line[strlen (pl->line) - 1] != ':' &&
+ !pl->isComment &&
+ !pl->isLabel &&
!pl->isDebug) {
if (port->peep.getSize) {
dist += port->peep.getSize(pl);
for(pl = currPl; pl; pl = pl->next) {
if (pl->line && !pl->isDebug && !pl->isComment &&
- pl->line[strlen(pl->line)-1] == ':') {
+ pl->isLabel) {
if (strncmp(pl->line, label, len) == 0) break; /* Found Label */
if (strlen(pl->line) != 7 || !ISCHARDIGIT(*(pl->line)) ||
!ISCHARDIGIT(*(pl->line+1)) || !ISCHARDIGIT(*(pl->line+2)) ||
return TRUE; /* safe for a peephole to remove it :) */
}
+/*-----------------------------------------------------------------*/
+/* deadMove - Check, if a pop/push pair can be removed */
+/*-----------------------------------------------------------------*/
+FBYNAME (deadMove)
+{
+ char *op = hTabItemWithKey (vars, 1);
+
+ if (port->peep.deadMove)
+ return port->peep.deadMove (op, currPl, head);
+
+ fprintf (stderr, "Function deadMove not initialized in port structure\n");
+ return FALSE;
+}
/*-----------------------------------------------------------------*/
/* operandsNotSame - check if %1 & %2 are the same */
return TRUE;
}
+/*-----------------------------------------------------------------*/
+/* labelHashEntry- searches for a label in the list labelHash */
+/* Builds labelHash, if it does not yet exist. */
+/* Returns the labelHashEntry or NULL */
+/*-----------------------------------------------------------------*/
+labelHashEntry *
+getLabelRef (const char *label, lineNode *head)
+{
+ labelHashEntry *entry;
+
+ /* If we don't have the label hash table yet, build it. */
+ if (!labelHash)
+ {
+ buildLabelRefCountHash (head);
+ }
+
+ entry = hTabFirstItemWK (labelHash, hashSymbolName (label));
+
+ while (entry)
+ {
+ if (!strcmp (label, entry->name))
+ {
+ break;
+ }
+ entry = hTabNextItemWK (labelHash);
+ }
+ return entry;
+}
/* 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));
+ labelHashEntry *entry = getLabelRef (label, head);
- while (entry)
- {
- if (!strcmp (label, entry->name))
- {
- break;
- }
- entry = hTabNextItemWK (labelHash);
- }
if (entry)
{
#if 0
/*-----------------------------------------------------------------*/
/* callFuncByName - calls a function as defined in the table */
/*-----------------------------------------------------------------*/
-int
+static int
callFuncByName (char *fname,
hTab * vars,
lineNode * currPl,
{
"okToRemoveSLOC", okToRemoveSLOC
},
+ {
+ "deadMove", deadMove
+ },
{
"24bitModeAndPortDS390", flat24bitModeAndPortDS390
},
/* don't indent comments & labels */
if (head->line &&
- (*head->line == ';' ||
- head->line[strlen (head->line) - 1] == ':')) {
+ (head->isComment || head->isLabel)) {
fprintf (of, "%s\n", head->line);
} else {
if (head->isInline && *head->line=='#') {
/*-----------------------------------------------------------------*/
/* newPeepRule - creates a new peeprule and attach it to the root */
/*-----------------------------------------------------------------*/
-peepRule *
+static peepRule *
newPeepRule (lineNode * match,
lineNode * replace,
char *cond,
if (!isComment || (isComment && !options.noPeepComments))
{
+ const char *dummy1;
+ int dummy2;
+
if (!currL)
*head = currL = newLineNode (lines);
else
currL = connectLine (currL, newLineNode (lines));
currL->isComment = isComment;
+ currL->isLabel = isLabelDefinition (currL->line, &dummy1, &dummy2,
+ TRUE);
}
}
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))
+ if (csl->isLabel)
{
/* found a source line label; look for it in the replacment lines */
crl = rhead;
else
lhead = cl = newLineNode (lb);
cl->isComment = pl->isComment;
+ cl->isLabel = pl->isLabel;
}
/* add the comments if any to the head of list */
* and len will be it's length.
*/
bool
-isLabelDefinition (const char *line, const char **start, int *len)
+isLabelDefinition (const char *line, const char **start, int *len,
+ bool isPeepRule)
{
const char *cp = line;
*start = cp;
- while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_'))
+ while (ISCHARALNUM (*cp) || (*cp == '$') || (*cp == '_') ||
+ (isPeepRule && (*cp == '%')))
{
cp++;
}
labelHash = newHashTable (HTAB_SIZE);
/* First pass: locate all the labels. */
- line = head;
-
- while (line)
+ for (line = head; line; line = line->next)
{
- if (isLabelDefinition (line->line, &label, &labelLen)
- && labelLen <= SDCC_NAME_MAX)
+ if (line->isLabel ||
+ line->isInline)
{
- labelHashEntry *entry;
+ /* run isLabelDefinition to:
+ - look for labels in inline assembler
+ - calculate labelLen
+ */
+ if (isLabelDefinition (line->line, &label, &labelLen, FALSE) &&
+ labelLen <= SDCC_NAME_MAX)
+ {
+ labelHashEntry *entry;
- entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
+ entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
- memcpy (entry->name, label, labelLen);
- entry->name[labelLen] = 0;
- entry->refCount = -1;
+ 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++;
+ /* 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);
+ hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
+ }
}
- line = line->next;
}
unsigned int isInline:1;
unsigned int isComment:1;
unsigned int isDebug:1;
+ unsigned int isLabel:1;
+ unsigned int visited:1;
struct asmLineNode *aln;
struct lineNode *prev;
struct lineNode *next;
}
peepRule;
+typedef struct
+ {
+ char name[SDCC_NAME_MAX + 1];
+ int refCount;
+ /* needed for deadMove: */
+ bool passedLabel;
+ int jmpToCount;
+ }
+labelHashEntry;
+
+bool isLabelDefinition (const char *line, const char **start, int *len,
+ bool isPeepRule);
+
+extern hTab *labelHash;
+labelHashEntry *getLabelRef (const char *label, lineNode *head);
+
void printLine (lineNode *, FILE *);
lineNode *newLineNode (char *);
lineNode *connectLine (lineNode *, lineNode *);
emitcode ("setb","F1"); \
emitcode ("jbc","EA,!tlabel",lbl->key+100); \
emitcode ("clr","F1"); \
- emitcode ("","!tlabeldef",lbl->key+100); \
+ emitLabel (lbl); \
}}
#define UNPROTECT_SP { if (options.protect_sp_update) { \
emitcode ("mov","EA,F1"); \
lineCurr->isDebug = _G.debugLine;
lineCurr->ic = _G.current_iCode;
lineCurr->aln = ds390newAsmLineNode(_currentDPS);
+ lineCurr->isComment = (*lbp == ';');
va_end (ap);
}
emitLabel (symbol *tlbl)
{
emitcode ("", "!tlabeldef", tlbl->key + 100);
+ lineCurr->isLabel = 1;
}
/*-----------------------------------------------------------------*/
emitcode (";", "-----------------------------------------");
emitcode ("", "%s:", sym->rname);
+ lineCurr->isLabel = 1;
ftype = operandType (IC_LEFT (ic));
_G.currentFunc = sym;
D (emitcode (";", "genLabel"));
- emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
+ emitLabel (IC_LABEL (ic));
}
/*-----------------------------------------------------------------*/
emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
freeAsmop (count, NULL, ic, FALSE);
emitcode ("mov", "dps,#!constbyte",0x21); /* Select DPTR2 & auto-toggle. */
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
if (fromc) {
emitcode ("clr","a");
emitcode ("movc", "a,@a+dptr");
emitcode ("addc","a,#!constbyte",0xFF);
emitcode ("mov","b,a");
emitcode ("sjmp","!tlabel",lbl->key+100);
- emitcode ("","!tlabeldef",lbl1->key+100);
+ emitLabel (lbl1);
}
emitcode ("mov", "dps,#0");
_G.dptrInUse = _G.dptr1InUse = 0;
emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
freeAsmop (count, NULL, ic, FALSE);
emitcode ("mov", "dps,#!constbyte",0x21); /* Select DPTR2 & auto-toggle. */
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
if (fromc) {
emitcode ("clr","a");
emitcode ("movc", "a,@a+dptr");
emitcode ("addc","a,#!constbyte",0xFF);
emitcode ("mov","b,a");
emitcode ("sjmp","!tlabel",lbl->key+100);
- emitcode ("","!tlabeldef",lbl1->key+100);
+ emitLabel (lbl1);
emitcode ("clr","a");
- emitcode ("","!tlabeldef",lbl2->key+100);
+ emitLabel (lbl2);
aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
aopPut(IC_RESULT(ic),"a",0);
freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
emitcode ("mov", "dps,#!constbyte",0x1); /* Select DPTR2 */
emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
freeAsmop (count, NULL, ic, FALSE);
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
emitcode ("movx", "a,@dptr"); /* read data from port */
emitcode ("dec","dps"); /* switch to DPTR */
emitcode ("movx", "@dptr,a"); /* save into location */
emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
freeAsmop (count, NULL, ic, FALSE);
emitcode ("mov", "dps,#!constbyte",0x1); /* Select DPTR2 */
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
emitcode ("movx", "a,@dptr");
emitcode ("dec","dps"); /* switch to DPTR */
emitcode ("movx", "@dptr,a");
emitcode ("addc","a,#!constbyte",0xFF);
emitcode ("mov","b,a");
emitcode ("sjmp","!tlabel",lbl->key+100);
- emitcode ("","!tlabeldef",lbl1->key+100);
+ emitLabel (lbl1);
}
emitcode ("mov", "dps,#0");
_G.dptrInUse = _G.dptr1InUse = 0;
emitcode (";","OH JOY auto increment with djnz (very fast)");
emitcode ("mov", "dps,#!constbyte",0x0); /* Select DPTR */
emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
emitcode ("movx", "a,@dptr"); /* read data from port */
emitcode ("inc","dps"); /* switch to DPTR2 */
emitcode ("movx", "@dptr,a"); /* save into location */
emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
freeAsmop (count, NULL, ic, FALSE);
emitcode ("mov", "dps,#!constbyte",0x0); /* Select DPTR */
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
emitcode ("movx", "a,@dptr");
emitcode ("inc", "dptr");
emitcode ("inc","dps"); /* switch to DPTR2 */
emitcode ("addc","a,#!constbyte",0xFF);
emitcode ("mov","b,a");
emitcode ("sjmp","!tlabel",lbl->key+100);
- emitcode ("","!tlabeldef",lbl1->key+100);
+ emitLabel (lbl1);
}
emitcode ("mov", "dps,#0");
_G.dptrInUse = _G.dptr1InUse = 0;
l = aopGet(val, 0, FALSE, FALSE, NULL);
emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
MOVA(l);
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
emitcode ("movx", "@dptr,a");
emitcode ("inc", "dptr");
emitcode ("djnz","b,!tlabel",lbl->key+100);
emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
emitcode ("movx", "@dptr,a");
emitcode ("inc", "dptr");
emitcode ("addc","a,#!constbyte",0xFF);
emitcode ("mov","b,a");
emitcode ("sjmp","!tlabel",lbl->key+100);
- emitcode ("","!tlabeldef",lbl1->key+100);
+ emitLabel (lbl1);
}
freeAsmop (count, NULL, ic, FALSE);
unsavermask(rsave);
aopPut(IC_RESULT(ic),"r3",1);
}
freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
unsavermask(rsave);
}
emitcode ("jz","!tlabel",lbl->key+100);
emitcode ("mov","r2,#!constbyte",0xff);
emitcode ("mov","r3,#!constbyte",0xff);
- emitcode ("","!tlabeldef",lbl->key+100);
+ emitLabel (lbl);
/* we don't care about the pointer : we just save the handle */
rsym = OP_SYMBOL(IC_RESULT(ic));
if (rsym->liveFrom != rsym->liveTo) {
emitLabel (symbol *tlbl)
{
emitcode ("", "%05d$:", (tlbl->key +100));
+ lineCurr->isLabel = 1;
}
/*-----------------------------------------------------------------*/
emitcode ("tsta", "");
emitcode ("bne", "%05d$", (tlbl->key + 100));
emitcode ("tstx", "");
- emitcode ("", "%05d$:", (tlbl->key + 100));
+ emitLabel (tlbl);
}
else
{
emitcode ("tst", "%s", aopAdrStr (aop, 0, FALSE));
emitcode ("bne", "%05d$", (tlbl->key + 100));
emitcode ("tst", "%s", aopAdrStr (aop, 1, FALSE));
- emitcode ("", "%05d$:", (tlbl->key + 100));
+ emitLabel (tlbl);
break;
}
}
emitcode (";", "-----------------------------------------");
emitcode ("", "%s:", sym->rname);
+ lineCurr->isLabel = 1;
ftype = operandType (IC_LEFT (ic));
_G.stackOfs = 0;
debugFile->writeLabel(IC_LABEL (ic), ic);
- emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
+ emitLabel (IC_LABEL (ic));
}
emitLabel (symbol *tlbl)
{
emitcode ("", "%05d$:", tlbl->key + 100);
+ lineCurr->isLabel = 1;
}
/*-----------------------------------------------------------------*/
emitcode (";", "-----------------------------------------");
emitcode ("", "%s:", sym->rname);
+ lineCurr->isLabel = 1;
ftype = operandType (IC_LEFT (ic));
_G.currentFunc = sym;
if (IC_LABEL (ic) == entryLabel)
return;
- emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
+ emitLabel (IC_LABEL (ic));
}
/*-----------------------------------------------------------------*/
_defaultRules,
getInstructionSize,
getRegsRead,
- getRegsWritten
+ getRegsWritten,
+ mcs51DeadMove
},
{
/* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
--- /dev/null
+/*-------------------------------------------------------------------------
+ peep.c - source file for peephole optimizer helper functions
+
+ Written By - Bernhard Held
+
+ This program is free software; you can redistribute it and/or modify it
+ 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!
+-------------------------------------------------------------------------*/
+
+#include "common.h"
+#include "ralloc.h"
+
+#define D(x) x
+#define DEADMOVEERROR "Internal error: deadmove\n"
+
+typedef enum
+{
+ S4O_FOUNDOPCODE,
+ S4O_PUSHPOP,
+ S4O_CONDJMP,
+ S4O_WR_OP,
+ S4O_RD_OP,
+ S4O_TERM,
+ S4O_VISITED,
+ S4O_ABORT
+} S4O_RET;
+
+static struct
+{
+ lineNode *head;
+} _G;
+
+/*-----------------------------------------------------------------*/
+/* univisitLines - clear "visited" flag in all lines */
+/*-----------------------------------------------------------------*/
+static void
+unvisitLines (lineNode *pl)
+{
+ for (; pl; pl = pl->next)
+ pl->visited = FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* cleanLabelRef - clear label jump-counter and pass-flag */
+/*-----------------------------------------------------------------*/
+static void
+cleanLabelRef (void)
+{
+ int key;
+ labelHashEntry *entry;
+
+ if (!labelHash)
+ return;
+ for (entry = (labelHashEntry *) hTabFirstItem (labelHash, &key);
+ entry;
+ entry = (labelHashEntry *) hTabNextItem (labelHash, &key))
+ {
+ entry->passedLabel = FALSE;
+ entry->jmpToCount = 0;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* checkLabelRef - check all entries in labelHash */
+/* The path from 'pop' to 'push' must be the only possible path. */
+/* There must not be any paths in or out of this path. */
+/* This is checked by counting the label references. */
+/*-----------------------------------------------------------------*/
+static bool
+checkLabelRef (void)
+{
+ int key;
+ labelHashEntry *entry;
+
+ if (!labelHash)
+ {
+ /* no labels at all: no problems ;-) */
+ return TRUE;
+ }
+
+ for (entry = (labelHashEntry *) hTabFirstItem (labelHash, &key);
+ entry;
+ entry = (labelHashEntry *) hTabNextItem (labelHash, &key))
+ {
+
+ /* In our path we passed a label,
+ but we didn't meet all references (jumps) to this label.
+ This means that the code jumps from outside into this path. */
+ if (entry->passedLabel &&
+ entry->jmpToCount != entry->refCount)
+ {
+ return FALSE;
+ }
+
+ /* In our path we jumped to (referenced) a label,
+ but we we didn't pass it.
+ This means that there's a code path into our path. */
+ if (!entry->passedLabel &&
+ entry->jmpToCount != 0)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* setLabelRefPassedLabel - set flag "passedLabel" in entry */
+/* of the list labelHash */
+/*-----------------------------------------------------------------*/
+static bool
+setLabelRefPassedLabel (const char *label)
+{
+ labelHashEntry *entry;
+
+ entry = getLabelRef (label, _G.head);
+ if (!entry)
+ return FALSE;
+ entry->passedLabel = TRUE;
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* incLabelJmpToCount - increment counter "jmpToCount" in entry */
+/* of the list labelHash */
+/*-----------------------------------------------------------------*/
+static bool
+incLabelJmpToCount (const char *label)
+{
+ labelHashEntry *entry;
+
+ entry = getLabelRef (label, _G.head);
+ if (!entry)
+ return FALSE;
+ entry->jmpToCount++;
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* findLabel - */
+/* 1. extracts label in the opcode pl */
+/* 2. increment "label jump-to count" in labelHash */
+/* 3. search lineNode with label definition and return it */
+/*-----------------------------------------------------------------*/
+static lineNode *
+findLabel (const lineNode *pl)
+{
+ char *p;
+ lineNode *cpl;
+
+ /* 1. extract label in opcode */
+
+ /* In each mcs51 jumping opcode the label is at the end of the opcode */
+ p = strlen (pl->line) - 1 + pl->line;
+
+ /* scan backward until ',' or '\t' */
+ for (; p > pl->line; p--)
+ if (*p == ',' || *p == '\t')
+ break;
+
+ /* sanity check */
+ if (p == pl->line)
+ {
+ D(fprintf (stderr, DEADMOVEERROR);)
+ return NULL;
+ }
+
+ /* skip ',' resp. '\t' */
+ ++p;
+
+ /* 2. increment "label jump-to count" */
+ if (!incLabelJmpToCount (p))
+ return NULL;
+
+ /* 3. search lineNode with label definition and return it */
+ for (cpl = _G.head; cpl; cpl = cpl->next)
+ {
+ if ( cpl->isLabel
+ && strcmp (p, cpl->line) == 0)
+ {
+ return cpl;
+ }
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* scan4op - "executes" and examines the assembler opcodes, */
+/* follows conditional and un-conditional jumps. */
+/* Moreover it registers all passed labels. */
+/* */
+/* Parameter: */
+/* lineNode **pl */
+/* scanning starts from pl; */
+/* pl also returns the last scanned line */
+/* const char *pReg */
+/* points to a register (e.g. "ar0"). scan4op() tests for */
+/* read or write operations with this register */
+/* const char *untilOp */
+/* points to NULL or a opcode (e.g. "push"). */
+/* scan4op() returns if it hits this opcode. */
+/* lineNode **plCond */
+/* If a conditional branch is met plCond points to the */
+/* lineNode of the conditional branch */
+/* */
+/* Returns: */
+/* S4O_ABORT */
+/* on error */
+/* S4O_VISITED */
+/* hit lineNode with "visited" flag set: scan4op() already */
+/* scanned this opcode. */
+/* S4O_FOUNDOPCODE */
+/* found opcode and operand, to which untilOp and pReg are */
+/* pointing to. */
+/* S4O_RD_OP, S4O_WR_OP */
+/* hit an opcode reading or writing from pReg */
+/* S4O_PUSHPOP */
+/* hit a "push" or "pop" opcode */
+/* S4O_CONDJMP */
+/* hit a conditional jump opcode. pl and plCond return the */
+/* two possible branches. */
+/* S4O_TERM */
+/* acall, lcall, ret and reti "terminate" a scan. */
+/*-----------------------------------------------------------------*/
+static S4O_RET
+scan4op (lineNode **pl, const char *pReg, const char *untilOp,
+ lineNode **plCond)
+{
+ char *p;
+ int len;
+ bool isConditionalJump;
+
+ /* pReg points to e.g. "ar0"..."ar7" */
+ len = strlen (pReg);
+
+ for (; *pl; *pl = (*pl)->next)
+ {
+ if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment)
+ continue;
+
+ /* don't optimize across inline assembler,
+ e.g. isLabel doesn't work there */
+ if ((*pl)->isInline)
+ return S4O_ABORT;
+
+ if ((*pl)->visited)
+ return S4O_VISITED;
+ (*pl)->visited = TRUE;
+
+ /* found untilOp? */
+ if (untilOp && strncmp ((*pl)->line, untilOp, strlen (untilOp)) == 0)
+ {
+ p = (*pl)->line + strlen (untilOp);
+ if (*p == '\t' && strncmp (p + 1, pReg, len) == 0)
+ return S4O_FOUNDOPCODE;
+ else
+ {
+ /* found untilOp but without our pReg */
+ return S4O_ABORT;
+ }
+ }
+
+ /* found pReg? */
+ p = strchr ((*pl)->line, '\t');
+ if (p)
+ {
+ /* skip '\t' */
+ p++;
+
+ /* course search */
+ if (strstr (p, pReg + 1))
+ {
+ /* ok, let's have a closer look */
+
+ /* get index into pReg table */
+ int rIdx;
+
+ for (rIdx = 0; rIdx < mcs51_nRegs; ++rIdx)
+ if (strcmp (regs8051[rIdx].name, pReg + 1) == 0)
+ break;
+
+ /* sanity check */
+ if (rIdx >= mcs51_nRegs)
+ {
+ D(fprintf (stderr, DEADMOVEERROR);)
+ return S4O_ABORT;
+ }
+
+ /* does opcode read from pReg? */
+ if (bitVectBitValue (port->peep.getRegsRead ((*pl)), rIdx))
+ return S4O_RD_OP;
+ /* does opcode write to pReg? */
+ if (bitVectBitValue (port->peep.getRegsWritten ((*pl)), rIdx))
+ return S4O_WR_OP;
+
+ /* should never reach here */
+ D(fprintf (stderr, DEADMOVEERROR);)
+ return S4O_ABORT;
+ }
+ }
+
+ /* found label? */
+ if ((*pl)->isLabel)
+ {
+ const char *start;
+ char label[SDCC_NAME_MAX + 1];
+ int len;
+
+ if (!isLabelDefinition ((*pl)->line, &start, &len, FALSE))
+ return S4O_ABORT;
+ memcpy (label, start, len);
+ label[len] = '\0';
+ /* register passing this label */
+ if (!setLabelRefPassedLabel (label))
+ {
+ D(fprintf (stderr, DEADMOVEERROR);)
+ return S4O_ABORT;
+ }
+ continue;
+ }
+
+ /* branch or terminate? */
+ isConditionalJump = FALSE;
+ switch ((*pl)->line[0])
+ {
+ case 'a':
+ if (strncmp ("acall", (*pl)->line, 5) == 0)
+ return S4O_TERM;
+ if (strncmp ("ajmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ case 'c':
+ if (strncmp ("cjne", (*pl)->line, 4) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'd':
+ if (strncmp ("djnz", (*pl)->line, 4) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'j':
+ if (strncmp ("jmp", (*pl)->line, 3) == 0)
+ /* "jmp @a+dptr": no chance to trace execution */
+ return S4O_ABORT;
+ if (strncmp ("jc", (*pl)->line, 2) == 0 ||
+ strncmp ("jnc", (*pl)->line, 3) == 0 ||
+ strncmp ("jz", (*pl)->line, 2) == 0 ||
+ strncmp ("jnz", (*pl)->line, 3) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ if (strncmp ("jbc", (*pl)->line, 3) == 0 ||
+ strncmp ("jb", (*pl)->line, 2) == 0 ||
+ strncmp ("jnb", (*pl)->line, 3) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'l':
+ if (strncmp ("lcall", (*pl)->line, 5) == 0)
+ return S4O_TERM;
+ if (strncmp ("ljmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ case 'p':
+ if (strncmp ("pop", (*pl)->line, 3) == 0 ||
+ strncmp ("push", (*pl)->line, 4) == 0)
+ return S4O_PUSHPOP;
+ break;
+ case 'r':
+ /* pcall uses ret */
+ if (strncmp ("ret", (*pl)->line, 3) == 0) /* catches "reti" too */
+ return S4O_TERM;
+ break;
+ case 's':
+ if (strncmp ("sjmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ default:
+ break;
+ } /* switch ((*pl)->line[0]) */
+
+ if (isConditionalJump)
+ {
+ *plCond = findLabel (*pl);
+ if (!*plCond)
+ return S4O_ABORT;
+ return S4O_CONDJMP;
+ }
+ } /* for (; *pl; *pl = (*pl)->next) */
+ return S4O_ABORT;
+}
+
+/*-----------------------------------------------------------------*/
+/* doPushScan - scan through area 1. This small wrapper handles: */
+/* - action required on different return values */
+/* - recursion in case of conditional branches */
+/*-----------------------------------------------------------------*/
+static bool
+doPushScan (lineNode **pl, const char *pReg)
+{
+ lineNode *plConditional, *pushPl = NULL;
+
+ for (;; *pl = (*pl)->next)
+ {
+ switch (scan4op (pl, pReg, "push", &plConditional))
+ {
+ case S4O_FOUNDOPCODE:
+ /* this is what we're looking for */
+ return TRUE;
+ case S4O_VISITED:
+ if (!pushPl)
+ {
+ D(fprintf (stderr, DEADMOVEERROR);)
+ return FALSE;
+ }
+ *pl = pushPl;
+ /* already checked */
+ return TRUE;
+ case S4O_CONDJMP:
+ /* two possible destinations: recurse */
+ {
+ lineNode *pushPl2 = plConditional;
+
+ if (!doPushScan (&pushPl2, pReg))
+ return FALSE;
+ pushPl = pushPl2;
+ }
+ continue;
+ default:
+ return FALSE;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* doTermScan - scan through area 2. This small wrapper handles: */
+/* - action required on different return values */
+/* - recursion in case of conditional branches */
+/*-----------------------------------------------------------------*/
+static bool
+doTermScan (lineNode **pl, const char *pReg)
+{
+ lineNode *plConditional;
+
+ for (;; *pl = (*pl)->next)
+ {
+ switch (scan4op (pl, pReg, NULL, &plConditional))
+ {
+ case S4O_TERM:
+ case S4O_VISITED:
+ case S4O_WR_OP:
+ /* all these are terminating condtions */
+ return TRUE;
+ case S4O_PUSHPOP:
+ /* don't care, go on */
+ continue;
+ case S4O_CONDJMP:
+ /* two possible destinations: recurse */
+ {
+ lineNode *pl2 = plConditional;
+
+ if (!doTermScan (&pl2, pReg))
+ return FALSE;
+ }
+ continue;
+ case S4O_RD_OP:
+ default:
+ /* no go */
+ return FALSE;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* - */
+/*-----------------------------------------------------------------*/
+bool
+mcs51DeadMove (const char *op1, lineNode *currPl, lineNode *head)
+{
+ char pReg[5] = "ar";
+ lineNode *pushPl, *pl;
+
+ /* A pop/push pair can be removed, if these criteria are met
+ (ar0 is just an example here, ar0...ar7 are possible):
+
+ pop ar0
+
+ ; area 1
+
+ ; There must not be in area 1:
+ ; - read or write access of ar0
+ ; - "acall", "lcall", "pop", "ret", "reti" or "jmp @a+dptr" opcodes
+ ; - "push" opcode, which doesn't push ar0
+ ; - inline assembly
+ ; - a jump in or out of area 1 (see checkLabelRef())
+
+ ; Direct manipulation of sp is not detected. This isn't necessary
+ ; as long as sdcc doesn't emit such code in area 1.
+
+ ; area 1 must be terminated by a:
+ push ar0
+
+ ; area 2
+
+ ; There must not be:
+ ; - read access of ar0
+ ; - "jmp @a+dptr" opcode
+ ; - inline assembly
+ ; - a jump in or out of area 2 (see checkLabelRef())
+
+ ; An "acall", "lcall", "ret", "reti" or write access of ar0 terminate
+ ; the search, and the pop/push pair can safely be removed.
+ */
+
+ _G.head = head;
+ strcat (pReg, op1);
+
+ unvisitLines (_G.head);
+ cleanLabelRef();
+
+ /* area 1 */
+ pushPl = currPl->next;
+ if (!doPushScan (&pushPl, pReg))
+ return FALSE;
+
+ if (!checkLabelRef())
+ return FALSE;
+
+ /* area 2 */
+ pl = pushPl->next;
+ if (!doTermScan (&pl, pReg))
+ return FALSE;
+ if (!checkLabelRef())
+ return FALSE;
+
+ /* Success! */
+ if (options.noPeepComments)
+ {
+ /* remove pushPl from list */
+ pushPl->prev->next = pushPl->next;
+ pushPl->next->prev = pushPl->prev;
+ }
+ else
+ {
+ /* replace 'push ar0' by comment */
+ #define STR ";\tPeephole\tpush %s removed"
+ int size = sizeof(STR) + 2;
+
+ pushPl->line = Safe_alloc (size);
+ SNPRINTF (pushPl->line, size, STR, pReg);
+ pushPl->isComment = TRUE;
+ }
+
+ /* 'pop ar0' will be removed by peephole framework after returning TRUE */
+ return TRUE;
+}
--- /dev/null
+/*-------------------------------------------------------------------------
+ peep.h - header file for peephole optimizer helper functions
+
+ Written By - Bernhard Held
+
+ This program is free software; you can redistribute it and/or modify it
+ 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!
+-------------------------------------------------------------------------*/
+
+bool mcs51DeadMove (const char *op, lineNode *currPl, lineNode *head);
-//replace restart {
-// pop %1
-// push %1
-//} by {
-// ; Peephole 1 removed pop %1 push %1 (not push pop)
-//}
-
-//replace restart {
-// pop %1
-// mov %2,%3
-// push %1
-//} by {
-// ; Peephole 2 removed pop %1 push %1 (not push pop)
-// mov %2,%3
-//}
-
-//
// added by Jean Louis VERN for
// his shift stuff
replace {
%3:
} if labelRefCount(%3 1), labelRefCountChange(%3 -1)
+replace restart {
+ pop ar%1
+} by {
+ ; Peephole 300 pop ar%1 removed
+} if deadMove %1
// should be one of the last peepholes
replace{
%1:
} by {
- ; Peephole 300 removed redundant label %1
+ ; Peephole 400 removed redundant label %1
} if labelRefCount(%1 0)
{
va_list ap;
char lb[INITIAL_INLINEASM];
- unsigned char *lbp = (unsigned char *)lb;
+ char *lbp = lb;
va_start(ap,fmt);
(lineHead = newLineNode(lb)));
lineCurr->isInline = _G.inLine;
lineCurr->isDebug = _G.debugLine;
+ lineCurr->isLabel = (lbp[strlen (lbp) - 1] == ':');
if(debug_verbose)
addpCode2pBlock(pb,newpCodeCharP(lb));
(lineHead = newLineNode(lb)));
lineCurr->isInline = _G.inLine;
lineCurr->isDebug = _G.debugLine;
+ lineCurr->isComment = 1;
pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(lb));
va_end(ap);
(lineHead = newLineNode(lb)));
lineCurr->isInline = _G.inLine;
lineCurr->isDebug = _G.debugLine;
+ lineCurr->isLabel = (lbp[strlen (lbp) - 1] == ':');
+ lineCurr->isComment = (*lbp == ';');
// VR fprintf(stderr, "lb = <%s>\n", lbp);
#include "SDCCicode.h"
#include "SDCCargs.h"
#include "SDCCpeeph.h"
+#include "mcs51/peep.h"
#define TARGET_ID_MCS51 1
#define TARGET_ID_GBZ80 2
int (*getSize)(lineNode *line);
bitVect * (*getRegsRead)(lineNode *line);
bitVect * (*getRegsWritten)(lineNode *line);
+ bool (*deadMove) (const char *op, lineNode *currPl, lineNode *head);
}
peep;
_G.lines.current->isInline = _G.lines.isInline;
_G.lines.current->isDebug = _G.lines.isDebug;
_G.lines.current->ic = _G.current_iCode;
+ _G.lines.current->isComment = (*buffer == ';');
}
static void
emitLabel (int key)
{
emit2 ("!tlabeldef", key);
+ _G.lines.current->isLabel = 1;
spillCached ();
}
fetchHL (AOP (IC_LEFT (ic)));
emit2 ("jp !*hl");
emit2 ("!tlabeldef", (rlbl->key + 100));
+ _G.lines.current->isLabel = 1;
_G.stack.pushed -= 2;
}
freeAsmop (IC_LEFT (ic), NULL, ic);
{
sprintf (buffer, "%s_start", sym->rname);
emit2 ("!labeldef", buffer);
+ _G.lines.current->isLabel = 1;
}
emit2 ("!functionlabeldef", sym->rname);
+ _G.lines.current->isLabel = 1;
ftype = operandType (IC_LEFT (ic));
emit2 ("jp PO,!tlabel", tlbl->key + 100);
emit2 ("!ei");
emit2 ("!tlabeldef", (tlbl->key + 100));
+ _G.lines.current->isLabel = 1;
}
}
}
{
sprintf (buffer, "%s_end", sym->rname);
emit2 ("!labeldef", buffer);
+ _G.lines.current->isLabel = 1;
}
_G.flushStatics = 1;
{
emit2 ("clr c");
emit2 ("!tlabeldef", tlbl->key + 100);
+ _G.lines.current->isLabel = 1;
}
// if(left & literal)
else
emit2 ("jp PO,!tlabel", tlbl->key + 100);
aopPut (AOP (IC_RESULT (ic)), "!one", 0);
emit2 ("!tlabeldef", (tlbl->key + 100));
+ _G.lines.current->isLabel = 1;
freeAsmop (IC_RESULT (ic), NULL, ic);
}
else
emit2 ("jp PO,!tlabel", tlbl->key + 100);
emit2 ("!ei");
emit2 ("!tlabeldef", (tlbl->key + 100));
+ _G.lines.current->isLabel = 1;
}
}
}
}
+#if 0
/** Returns the rematerialized string for a remat var.
*/
static char *
}
return buffer;
}
+#endif
/*-----------------------------------------------------------------*/
/* regTypeNum - computes the type & number of registers required */