gbdk-releases/sdcc/src/SDCCBBlock.c
2015-01-10 16:25:09 +01:00

716 lines
19 KiB
C

/*-------------------------------------------------------------------------
SDCCBBlock.c - routines to manipulate basic Blocks
Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
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"
int eBBNum = 0;
set *graphEdges = NULL; /* list of edges in this flow graph */
struct _dumpFiles dumpFiles[] = {
{DUMP_RAW0, ".dumpraw0", NULL},
{DUMP_RAW1, ".dumpraw1", NULL},
{DUMP_CSE, ".dumpcse", NULL},
{DUMP_DFLOW, ".dumpdflow", NULL},
{DUMP_GCSE, ".dumpgcse", NULL},
{DUMP_DEADCODE, ".dumpdeadcode", NULL},
{DUMP_LOOP, ".dumploop", NULL},
{DUMP_LOOPG, ".dumploopg", NULL},
{DUMP_LOOPD, ".dumploopd", NULL},
{DUMP_RANGE, ".dumprange", NULL},
{DUMP_PACK, ".dumppack", NULL},
{DUMP_RASSGN, ".dumprassgn", NULL},
{DUMP_LRANGE, ".dumplrange", NULL},
{0, NULL, NULL}
};
/*-----------------------------------------------------------------*/
/* printEntryLabel - prints entry label of a ebblock */
/*-----------------------------------------------------------------*/
DEFSETFUNC (printEntryLabel)
{
eBBlock *bp = item;
fprintf (stdout, " %-20s ", bp->entryLabel->name);
return 0;
}
/*-----------------------------------------------------------------*/
/* neweBBlock - allocate & return a new extended basic block */
/*-----------------------------------------------------------------*/
eBBlock *
neweBBlock ()
{
eBBlock *ebb;
ebb = Safe_alloc (sizeof (eBBlock));
return ebb;
}
/*-----------------------------------------------------------------*/
/* newEdge - allocates & initialises an edge to given values */
/*-----------------------------------------------------------------*/
edge *
newEdge (eBBlock * from, eBBlock * to)
{
edge *ep;
ep = Safe_alloc (sizeof (edge));
ep->from = from;
ep->to = to;
return ep;
}
/*-----------------------------------------------------------------*/
/* appendDumpFile - if not already created, create the dump file */
/*-----------------------------------------------------------------*/
FILE *appendDumpFile (int id) {
struct _dumpFiles *dumpFilesPtr=dumpFiles;
while (dumpFilesPtr->id) {
if (dumpFilesPtr->id==id)
break;
dumpFilesPtr++;
}
if (!dumpFilesPtr->id) {
fprintf (stdout, "internal error: appendDumpFile: unknown dump file.\n");
exit (1);
}
if (!dumpFilesPtr->filePtr) {
// not used before, create it
strcpy (scratchFileName, srcFileName);
strcat (scratchFileName, dumpFilesPtr->ext);
if (!(dumpFilesPtr->filePtr = fopen (scratchFileName, "w"))) {
werror (E_FILE_OPEN_ERR, scratchFileName);
exit (1);
}
}
return dumpFilesPtr->filePtr;
}
/*-----------------------------------------------------------------*/
/* closeDumpFiles - close possible opened dumpfiles */
/*-----------------------------------------------------------------*/
void closeDumpFiles() {
struct _dumpFiles *dumpFilesPtr;
for (dumpFilesPtr=dumpFiles; dumpFilesPtr->id; dumpFilesPtr++) {
if (dumpFilesPtr->filePtr) {
fclose (dumpFilesPtr->filePtr);
//dprintf ("closed %s\n", dumpFilesPtr->ext);
}
}
}
/*-----------------------------------------------------------------*/
/* dumpLiveRanges - dump liverange information into a file */
/*-----------------------------------------------------------------*/
void
dumpLiveRanges (int id, hTab * liveRanges)
{
FILE *file;
symbol *sym;
int k;
if (id) {
file=appendDumpFile(id);
} else {
file = stdout;
}
for (sym = hTabFirstItem (liveRanges, &k); sym;
sym = hTabNextItem (liveRanges, &k))
{
fprintf (file, "%s [k%d lr%d:%d so:%d]{ re%d rm%d}",
(sym->rname[0] ? sym->rname : sym->name),
sym->key,
sym->liveFrom, sym->liveTo,
sym->stack,
sym->isreqv, sym->remat
);
fprintf (file, "{");
printTypeChain (sym->type, file);
if (sym->usl.spillLoc)
{
fprintf (file, "}{ sir@ %s", sym->usl.spillLoc->rname);
}
fprintf (file, "}");
fprintf (file, "\n");
}
fflush(file);
}
/*-----------------------------------------------------------------*/
/* dumpEbbsToFileExt - writeall the basic blocks to a file */
/*-----------------------------------------------------------------*/
void
dumpEbbsToFileExt (int id, eBBlock ** ebbs, int count)
{
FILE *of;
int i;
if (id) {
of=appendDumpFile(id);
} else {
of = stdout;
}
for (i = 0; i < count; i++)
{
fprintf (of, "\n----------------------------------------------------------------\n");
fprintf (of, "Basic Block %s : loop Depth = %d noPath = %d , lastinLoop = %d\n",
ebbs[i]->entryLabel->name,
ebbs[i]->depth,
ebbs[i]->noPath,
ebbs[i]->isLastInLoop);
fprintf (of, "\ndefines bitVector :");
bitVectDebugOn (ebbs[i]->defSet, of);
fprintf (of, "\nlocal defines bitVector :");
bitVectDebugOn (ebbs[i]->ldefs, of);
fprintf (of, "\npointers Set bitvector :");
bitVectDebugOn (ebbs[i]->ptrsSet, of);
if (ebbs[i]->isLastInLoop) {
fprintf (of, "\nInductions Set bitvector :");
bitVectDebugOn (ebbs[i]->linds, of);
}
fprintf (of, "\n----------------------------------------------------------------\n");
printiCChain (ebbs[i]->sch, of);
}
fflush(of);
}
/*-----------------------------------------------------------------*/
/* iCode2eBBlock - converts a sequnce till label to a ebb */
/*-----------------------------------------------------------------*/
eBBlock *
iCode2eBBlock (iCode * ic)
{
iCode *loop;
eBBlock *ebb = neweBBlock (); /* a llocate an entry */
/* put the first one unconditionally */
ebb->sch = ic;
/* if this is a label then */
if (ic->op == LABEL)
ebb->entryLabel = ic->argLabel.label;
else
{
sprintf (buffer, "_eBBlock%d", eBBNum++);
ebb->entryLabel = newSymbol (buffer, 1);
ebb->entryLabel->key = labelKey++;
}
if (ic &&
(ic->op == GOTO ||
ic->op == JUMPTABLE ||
ic->op == IFX))
{
ebb->ech = ebb->sch;
return ebb;
}
if ((ic->next && ic->next->op == LABEL) ||
!ic->next)
{
ebb->ech = ebb->sch;
return ebb;
}
/* loop thru till we find one with a label */
for (loop = ic->next; loop; loop = loop->next)
{
/* if this is the last one */
if (!loop->next)
break;
/* if this is a function call */
if (loop->op == CALL || loop->op == PCALL)
{
ebb->hasFcall = 1;
if (currFunc)
FUNC_HASFCALL(currFunc->type) = 1;
}
/* if the next one is a label */
/* if this is a goto or ifx */
if (loop->next->op == LABEL ||
loop->op == GOTO ||
loop->op == JUMPTABLE ||
loop->op == IFX)
break;
}
/* mark the end of the chain */
ebb->ech = loop;
return ebb;
}
/*-----------------------------------------------------------------*/
/* eBBWithEntryLabel - finds the basic block with the entry label */
/*-----------------------------------------------------------------*/
eBBlock *
eBBWithEntryLabel (eBBlock ** ebbs, symbol * eLabel, int count)
{
int i;
for (i = 0; i < count; i++)
{
if (isSymbolEqual (ebbs[i]->entryLabel, eLabel))
return ebbs[i];
}
return NULL;
}
/*-----------------------------------------------------------------*/
/* ifFromIs - will return 1 if the from block matches this */
/*-----------------------------------------------------------------*/
DEFSETFUNC (ifFromIs)
{
edge *ep = item;
V_ARG (eBBlock *, this);
if (ep->from == this)
return 1;
return 0;
}
/*-----------------------------------------------------------------*/
/* edgesTo - returns a set of edges with to == supplied value */
/*-----------------------------------------------------------------*/
set *
edgesTo (eBBlock * to)
{
set *result = NULL;
edge *loop;
for (loop = setFirstItem (graphEdges); loop; loop = setNextItem (graphEdges))
if (loop->to == to && !loop->from->noPath)
addSet (&result, loop->from);
return result;
}
/*-----------------------------------------------------------------*/
/* addiCodeToeBBlock - will add an iCode to the end of a block */
/*-----------------------------------------------------------------*/
void
addiCodeToeBBlock (eBBlock * ebp, iCode * ic, iCode * ip)
{
ic->prev = ic->next = NULL;
/* if the insert point is given */
if (ip)
{
ic->lineno = ip->lineno;
ic->prev = ip->prev;
ip->prev = ic;
ic->next = ip;
if (!ic->prev)
ebp->sch = ic;
else
ic->prev->next = ic;
return;
}
/* if the block has no instructions */
if (ebp->ech == NULL)
{
ebp->sch = ebp->ech = ic;
ic->next = NULL;
return;
}
/* if the last instruction is a goto */
/* we add it just before the goto */
if (ebp->ech->op == GOTO || ebp->ech->op == JUMPTABLE
|| ebp->ech->op == RETURN)
{
ic->lineno = ebp->ech->lineno;
ic->prev = ebp->ech->prev;
ebp->ech->prev = ic;
ic->next = ebp->ech;
if (!ic->prev) /* was the last only on in the block */
ebp->sch = ic;
else
ic->prev->next = ic;
return;
}
/* if the last one was a ifx statement we check to see */
/* if the condition was defined in the previous instruction */
/* if this is true then we put it before the condition else */
/* we put it before if, this is to reduce register pressure, */
/* we don't have to hold condition too long in a register */
if (ebp->ech->op == IFX)
{
iCode *ipoint;
/* if ( !ebp->ech->prev ) */
/* ipoint = ebp->ech ; */
/* else */
/* if (!IC_RESULT(ebp->ech->prev)) */
/* ipoint = ebp->ech ; */
/* else */
/* if (IC_COND(ebp->ech)->key == IC_RESULT(ebp->ech->prev)->key) */
/* ipoint = ebp->ech->prev; */
/* else */
/* ipoint = ebp->ech ; */
ipoint = ebp->ech;
ic->lineno = ipoint->lineno;
ic->prev = ipoint->prev;
ipoint->prev = ic;
ic->next = ipoint;
if (!ic->prev)
ebp->sch = ic;
else
ic->prev->next = ic;
return;
}
/* will add it to the very end */
ip = ebp->ech;
ip->next = ic;
ic->prev = ip;
ic->next = NULL;
ebp->ech = ic;
return;
}
/*-----------------------------------------------------------------*/
/* remiCodeFromeBBlock - remove an iCode from BBlock */
/*-----------------------------------------------------------------*/
void
remiCodeFromeBBlock (eBBlock * ebb, iCode * ic)
{
if (ic->prev)
ic->prev->next = ic->next;
else
ebb->sch = ic->next;
if (ic->next)
ic->next->prev = ic->prev;
else
ebb->ech = ic->prev;
}
/*-----------------------------------------------------------------*/
/* iCodeBreakDown : breakDown iCode chain to blocks */
/*-----------------------------------------------------------------*/
eBBlock **
iCodeBreakDown (iCode * ic, int *count)
{
eBBlock **ebbs = NULL;
iCode *loop = ic;
*count = 0;
/* allocate for the first entry */
ebbs = Safe_alloc (sizeof (eBBlock **));
while (loop)
{
/* convert 2 block */
eBBlock *ebb = iCode2eBBlock (loop);
loop = ebb->ech->next;
ebb->ech->next = NULL; /* mark the end of this chain */
if (loop)
loop->prev = NULL;
ebb->bbnum = *count; /* save this block number */
/* put it in the array */
ebbs[(*count)++] = ebb;
/* allocate for the next one. Remember to clear the new */
/* pointer at the end, that was created by realloc. */
ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
ebbs[*count] = 0;
/* if this one ends in a goto or a conditional */
/* branch then check if the block it is going */
/* to already exists, if yes then this could */
/* be a loop, add a preheader to the block it */
/* goes to if it does not already have one */
if (ebbs[(*count) - 1]->ech &&
(ebbs[(*count) - 1]->ech->op == GOTO ||
ebbs[(*count) - 1]->ech->op == IFX))
{
symbol *label;
eBBlock *destBlock;
if (ebbs[(*count) - 1]->ech->op == GOTO)
label = IC_LABEL (ebbs[(*count) - 1]->ech);
else if (!(label = IC_TRUE (ebbs[(*count) - 1]->ech)))
label = IC_FALSE (ebbs[(*count) - 1]->ech);
if ((destBlock = eBBWithEntryLabel (ebbs, label, (*count))) &&
destBlock->preHeader == NULL &&
otherPathsPresent (ebbs, destBlock))
{
symbol *preHeaderLabel = newiTempPreheaderLabel ();
int i, j;
eBBlock *pBlock;
/* go thru all block replacing the entryLabel with new label */
/* till we reach the block , then we insert a new ebblock */
for (i = 0; i < (*count); i++)
{
if (ebbs[i] == destBlock)
break;
replaceLabel (ebbs[i], label, preHeaderLabel);
}
(*count)++;
/* if we have stopped at the block , allocate for an extra one */
ebbs = Safe_realloc (ebbs, (*count + 1) * sizeof (eBBlock **));
ebbs[*count] = 0;
/* then move the block down one count */
pBlock = ebbs[j = i];
for (i += 1; i < (*count); i++)
{
eBBlock *xBlock;
xBlock = ebbs[i];
ebbs[i] = pBlock;
ebbs[i]->bbnum = i;
pBlock = xBlock;
}
destBlock->preHeader = ebbs[j] = neweBBlock ();
ebbs[j]->bbnum = j;
ebbs[j]->entryLabel = preHeaderLabel;
ebbs[j]->sch = ebbs[j]->ech = newiCodeLabelGoto (LABEL, preHeaderLabel);
ebbs[j]->sch->lineno = destBlock->sch->lineno;
}
}
}
/* mark the end */
ebbs[*count] = NULL;
return ebbs;
}
/*-----------------------------------------------------------------*/
/* replaceSymBySym : - replace operand by operand in blocks */
/* replaces only left & right in blocks */
/*-----------------------------------------------------------------*/
void
replaceSymBySym (set * sset, operand * src, operand * dest)
{
set *loop;
eBBlock *rBlock;
/* for all blocks in the set do */
for (loop = sset; loop; loop = loop->next)
{
iCode *ic;
rBlock = loop->item;
/* for all instructions in this block do */
for (ic = rBlock->sch; ic; ic = ic->next)
{
/* if we find usage */
if (ic->op == IFX && isOperandEqual (src, IC_COND (ic)))
{
bitVectUnSetBit (OP_USES (IC_COND (ic)), ic->key);
IC_COND (ic) = operandFromOperand (dest);
OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key);
continue;
}
if (isOperandEqual (IC_RIGHT (ic), src))
{
bitVectUnSetBit (OP_USES (IC_RIGHT (ic)), ic->key);
IC_RIGHT (ic) = operandFromOperand (dest);
IC_RIGHT (ic)->isaddr = 0;
OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key);
}
if (isOperandEqual (IC_LEFT (ic), src))
{
bitVectUnSetBit (OP_USES (IC_LEFT (ic)), ic->key);
if (POINTER_GET (ic) && IS_ITEMP (dest))
{
IC_LEFT (ic) = operandFromOperand (dest);
IC_LEFT (ic)->isaddr = 1;
}
else
{
IC_LEFT (ic) = operandFromOperand (dest);
IC_LEFT (ic)->isaddr = 0;
}
OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key);
}
/* special case for pointer sets */
if (POINTER_SET (ic) &&
isOperandEqual (IC_RESULT (ic), src))
{
bitVectUnSetBit (OP_USES (IC_RESULT (ic)), ic->key);
IC_RESULT (ic) = operandFromOperand (dest);
IC_RESULT (ic)->isaddr = 1;
OP_USES (dest) = bitVectSetBit (OP_USES (dest), ic->key);
}
}
}
}
/*-----------------------------------------------------------------*/
/* replaceLabel - replace reference to one label by another */
/*-----------------------------------------------------------------*/
void
replaceLabel (eBBlock * ebp, symbol * fromLbl, symbol * toLbl)
{
iCode *ic;
if (!ebp)
return;
for (ic = ebp->sch; ic; ic = ic->next)
{
switch (ic->op)
{
case GOTO:
if (isSymbolEqual (IC_LABEL (ic), fromLbl))
IC_LABEL (ic) = toLbl;
break;
case IFX:
if (IC_TRUE (ic) && isSymbolEqual (IC_TRUE (ic), fromLbl))
IC_TRUE (ic) = toLbl;
else if (isSymbolEqual (IC_FALSE (ic), fromLbl))
IC_FALSE (ic) = toLbl;
break;
}
}
return;
}
/*-----------------------------------------------------------------*/
/* iCodeFromeBBlock - convert basic block to iCode chain */
/*-----------------------------------------------------------------*/
iCode *
iCodeFromeBBlock (eBBlock ** ebbs, int count)
{
int i = 1;
iCode *ric = ebbs[0]->sch;
iCode *lic = ebbs[0]->ech;
for (; i < count; i++)
{
if (ebbs[i]->sch == NULL)
continue;
if (ebbs[i]->noPath &&
(ebbs[i]->entryLabel != entryLabel &&
ebbs[i]->entryLabel != returnLabel))
{
werror (W_CODE_UNREACH, ebbs[i]->sch->filename, ebbs[i]->sch->lineno);
continue;
}
lic->next = ebbs[i]->sch;
lic->next->prev = lic;
lic = ebbs[i]->ech;
}
return ric;
}
/*-----------------------------------------------------------------*/
/* otherPathsPresent - determines if there is a path from _entry */
/* to this block in a half constructed set of blocks */
/*-----------------------------------------------------------------*/
int
otherPathsPresent (eBBlock ** ebbs, eBBlock * this)
{
int i;
/* for all blocks preceding this block */
for (i = 0; i < this->bbnum; i++)
{
iCode *ic;
/* if there is a reference to the entry label of this block */
for (ic = ebbs[i]->sch; ic; ic = ic->next)
{
switch (ic->op)
{
case GOTO:
if (IC_LABEL (ic)->key == this->entryLabel->key)
return 1;
break;
case IFX:
if (IC_TRUE (ic))
{
if (IC_TRUE (ic)->key == this->entryLabel->key)
return 1;
}
else if (IC_FALSE (ic)->key == this->entryLabel->key)
return 1;
break;
}
}
}
/* comes here means we have not found it yet */
/* in this case check if the previous block */
/* ends in a goto if it does then we have no */
/* path else we have a path */
if (this->bbnum && ebbs[this->bbnum - 1]->ech &&
ebbs[this->bbnum - 1]->ech->op == GOTO)
return 0;
else
return 1;
}