summaryrefslogtreecommitdiff
path: root/src/SDCClrange.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCClrange.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCClrange.c')
-rw-r--r--src/SDCClrange.c1248
1 files changed, 1248 insertions, 0 deletions
diff --git a/src/SDCClrange.c b/src/SDCClrange.c
new file mode 100644
index 0000000..13b20ee
--- /dev/null
+++ b/src/SDCClrange.c
@@ -0,0 +1,1248 @@
+/*-------------------------------------------------------------------------
+
+ SDCClrange.c - source file for live range computations
+
+ 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"
+#include "limits.h"
+
+int iCodeSeq = 0;
+hTab *liveRanges = NULL;
+hTab *iCodehTab = NULL;
+hTab *iCodeSeqhTab = NULL;
+
+/* all symbols, for which the previous definition is searched
+ and warning is emitted if there's none. */
+#define IS_AUTOSYM(op) (IS_ITEMP(op) || \
+ (IS_SYMOP(op) && IS_AUTO(OP_SYMBOL (op)) && !IS_PARM(op)))
+
+/*-----------------------------------------------------------------*/
+/* hashiCodeKeys - add all iCodes to the hash table */
+/*-----------------------------------------------------------------*/
+void
+hashiCodeKeys (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ hTabAddItem (&iCodehTab, ic->key, ic);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* sequenceiCode - creates a sequence number for the iCode & add */
+/*-----------------------------------------------------------------*/
+static void
+sequenceiCode (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+
+ iCode *ic;
+ ebbs[i]->fSeq = iCodeSeq + 1;
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ ic->seq = ++iCodeSeq;
+ ic->depth = ebbs[i]->depth;
+ //hTabAddItem (&iCodehTab, ic->key, ic);
+ hTabAddItem (&iCodeSeqhTab, ic->seq, ic);
+ }
+ ebbs[i]->lSeq = iCodeSeq;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* setFromRange - sets the from range of a given operand */
+/*-----------------------------------------------------------------*/
+#if 0
+static void
+setFromRange (operand * op, int from)
+{
+ /* only for compiler defined temporaries */
+ if (!IS_ITEMP (op))
+ return;
+
+ hTabAddItemIfNotP (&liveRanges, op->key, OP_SYMBOL (op));
+
+ if (op->isaddr)
+ OP_SYMBOL (op)->isptr = 1;
+
+ if (!OP_LIVEFROM (op) ||
+ OP_LIVEFROM (op) > from)
+ OP_LIVEFROM (op) = from;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* setToRange - set the range to for an operand */
+/*-----------------------------------------------------------------*/
+void
+setToRange (operand * op, int to, bool check)
+{
+ /* only for compiler defined temps */
+ if (!IS_ITEMP (op))
+ return;
+
+ OP_SYMBOL (op)->key = op->key;
+ hTabAddItemIfNotP (&liveRanges, op->key, OP_SYMBOL (op));
+
+ if (op->isaddr)
+ OP_SYMBOL (op)->isptr = 1;
+
+ if (check)
+ if (!OP_LIVETO (op))
+ OP_LIVETO (op) = to;
+ else;
+ else
+ OP_LIVETO (op) = to;
+}
+
+/*-----------------------------------------------------------------*/
+/* setFromRange - sets the from range of a given operand */
+/*-----------------------------------------------------------------*/
+static void
+setLiveFrom (symbol * sym, int from)
+{
+ if (!sym->liveFrom || sym->liveFrom > from)
+ sym->liveFrom = from;
+}
+
+/*-----------------------------------------------------------------*/
+/* setToRange - set the range to for an operand */
+/*-----------------------------------------------------------------*/
+static void
+setLiveTo (symbol *sym, int to)
+{
+ if (!sym->liveTo || sym->liveTo < to)
+ sym->liveTo = to;
+}
+
+/*-----------------------------------------------------------------*/
+/* markLiveRanges - for each operand mark the liveFrom & liveTo */
+/*-----------------------------------------------------------------*/
+static void
+markLiveRanges (eBBlock **ebbs, int count)
+{
+ int i, key;
+ symbol *sym;
+
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ if (ic->op == CALL || ic->op == PCALL)
+ if (bitVectIsZero (OP_SYMBOL (IC_RESULT (ic))->uses))
+ bitVectUnSetBit (ebbs[i]->defSet, ic->key);
+
+ /* for all iTemps alive at this iCode */
+ for (key = 1; key < ic->rlive->size; key++)
+ {
+ if (!bitVectBitValue(ic->rlive, key))
+ continue;
+
+ sym = hTabItemWithKey(liveRanges, key);
+ setLiveTo(sym, ic->seq);
+ setLiveFrom(sym, ic->seq);
+ }
+
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* markAlive - marks the operand as alive between sic and eic */
+/*-----------------------------------------------------------------*/
+static void
+markAlive (iCode * sic, iCode * eic, int key)
+{
+ iCode *dic;
+
+ for (dic = sic; dic != eic->next; dic = dic->next)
+ {
+ dic->rlive = bitVectSetBit (dic->rlive, key);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* findNextUseSym - finds the next use of the symbol and marks it */
+/* alive in between */
+/* Return 0 iff there is no next use. */
+/*-----------------------------------------------------------------*/
+static int
+findNextUseSym (eBBlock *ebp, iCode *ic, symbol * sym)
+{
+ int retval = 0;
+ iCode *uic;
+ eBBlock *succ;
+
+ hTabAddItemIfNotP (&liveRanges, sym->key, sym);
+
+ if (!ic)
+ goto check_successors;
+
+ /* if we check a complete block and the symbol */
+ /* is alive at the beginning of the block */
+ /* and not defined in the first instructions */
+ /* then a next use exists (return 1) */
+ if ((ic == ebp->sch) && bitVectBitValue(ic->rlive, sym->key))
+ {
+ /* check if the first instruction is a def of this op */
+ if (ic->op == JUMPTABLE || ic->op == IFX || SKIP_IC2(ic))
+ return 1;
+
+ if (IS_ITEMP(IC_RESULT(ic)))
+ if (IC_RESULT(ic)->key == sym->key)
+ return 0;
+
+ return 1;
+ }
+
+ if (ebp->visited)
+ return 0;
+
+ if (ic == ebp->sch)
+ ebp->visited = 1;
+
+ /* for all remaining instructions in current block */
+ for (uic = ic; uic; uic = uic->next)
+ {
+
+ if (SKIP_IC2(uic))
+ continue;
+
+ if (uic->op == JUMPTABLE)
+ {
+ if (IS_ITEMP(IC_JTCOND(uic)) && IC_JTCOND(uic)->key == sym->key)
+ {
+ markAlive(ic, uic, sym->key);
+ return 1;
+ }
+ continue;
+ }
+
+ if (uic->op == IFX)
+ {
+ if (IS_ITEMP(IC_COND(uic)) && IC_COND(uic)->key == sym->key)
+ {
+ markAlive(ic, uic, sym->key);
+ return 1;
+ }
+ continue;
+ }
+
+ if (IS_ITEMP (IC_LEFT (uic)))
+ if (IC_LEFT (uic)->key == sym->key)
+ {
+ markAlive(ic, uic, sym->key);
+ return 1;
+ }
+
+ if (IS_ITEMP (IC_RIGHT (uic)))
+ if (IC_RIGHT (uic)->key == sym->key)
+ {
+ markAlive (ic, uic, sym->key);
+ return 1;
+ }
+
+ if (IS_ITEMP (IC_RESULT (uic)))
+ if (IC_RESULT (uic)->key == sym->key)
+ {
+ if (POINTER_SET (uic))
+ {
+ markAlive (ic, uic, sym->key);
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ }
+
+ /* check all successors */
+check_successors:
+
+ succ = setFirstItem (ebp->succList);
+ for (; succ; succ = setNextItem (ebp->succList))
+ {
+ retval += findNextUseSym (succ, succ->sch, sym);
+ }
+
+ if (retval)
+ {
+ if (ic) markAlive (ic, ebp->ech, sym->key);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* findNextUse - finds the next use of the operand and marks it */
+/* alive in between */
+/* Return 0 iff there is no next use. */
+/*-----------------------------------------------------------------*/
+static int
+findNextUse (eBBlock *ebp, iCode *ic, operand *op)
+{
+ if (op->isaddr)
+ OP_SYMBOL (op)->isptr = 1;
+
+ OP_SYMBOL (op)->key = op->key;
+
+ return findNextUseSym (ebp, ic, OP_SYMBOL(op));
+}
+
+/*-----------------------------------------------------------------*/
+/* unvisitBlocks - clears visited in all blocks */
+/*-----------------------------------------------------------------*/
+static void
+unvisitBlocks (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ ebbs[i]->visited = 0;
+}
+
+/*------------------------------------------------------------------*/
+/* markWholeLoop - mark the symbol 'key' alive in all blocks */
+/* included by the outermost loop */
+/*------------------------------------------------------------------*/
+static void
+markWholeLoop (eBBlock *ebp, int key)
+{
+ eBBlock *ebpi;
+
+ /* avoid endless loops */
+ ebp->visited = 1;
+
+ /* recurse through all predecessors */
+ for (ebpi = setFirstItem (ebp->predList);
+ ebpi;
+ ebpi = setNextItem (ebp->predList))
+ {
+ if (ebpi->visited)
+ continue;
+ /* is the predecessor still in the loop? */
+ if (ebpi->depth == 0)
+ continue;
+ markWholeLoop (ebpi, key);
+ }
+
+ /* recurse through all successors */
+ for (ebpi = setFirstItem (ebp->succList);
+ ebpi;
+ ebpi = setNextItem (ebp->succList))
+ {
+ if (ebpi->visited)
+ continue;
+ if (ebpi->depth == 0)
+ continue;
+ markWholeLoop (ebpi, key);
+ }
+
+ markAlive (ebp->sch, ebp->ech, key);
+}
+
+/*------------------------------------------------------------------*/
+/* findPrevUseSym - search for a previous definition of a symbol in */
+/* - the previous icodes */
+/* - all branches of predecessors */
+/*------------------------------------------------------------------*/
+static bool
+findPrevUseSym (eBBlock *ebp, iCode *ic, symbol * sym)
+{
+ eBBlock * pred;
+ iCode * uic;
+
+ if (ebp->visited)
+ {
+ /* already visited: this branch must have been succesfull, */
+ /* because otherwise the search would have been aborted. */
+ return TRUE;
+ }
+ ebp->visited = 1;
+
+ /* search backward in the current block */
+ for (uic = ic; uic; uic = uic->prev)
+ {
+ if (!POINTER_SET (uic) && IS_AUTOSYM (IC_RESULT (uic)))
+ {
+ if (IC_RESULT (uic)->key == sym->key)
+ {
+ /* Ok, found a definition */
+ return TRUE;
+ }
+ }
+ /* address taken from symbol? */
+ if (uic->op == ADDRESS_OF && IS_AUTOSYM (IC_LEFT (uic)))
+ {
+ if (IC_LEFT (uic)->key == sym->key)
+ {
+ /* Ok, found a definition */
+ return TRUE;
+ }
+ }
+ }
+
+ /* There's no definition in this bblock, */
+ /* let's have a look at all predecessors. */
+ pred = setFirstItem (ebp->predList);
+ if (!pred)
+ {
+ /* no more predecessors and nothing found yet :-( */
+ return FALSE;
+ }
+ for (; pred; pred = setNextItem (ebp->predList))
+ {
+ /* recurse into all predecessors */
+ if (!findPrevUseSym (pred, pred->ech, sym))
+ {
+ /* found nothing: abort */
+ return FALSE;
+ }
+ }
+
+ /* Success! Went through all branches with no abort: */
+ /* all branches end with a definition */
+ return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/* findPrevUse - search for a previous definition of an operand */
+/* If there's no definition let's: */
+/* - emit a warning */
+/* - fix the life range, if the symbol is used in */
+/* a loop */
+/*------------------------------------------------------------------*/
+static void
+findPrevUse (eBBlock *ebp, iCode *ic, operand *op,
+ eBBlock ** ebbs, int count,
+ bool emitWarnings)
+{
+ unvisitBlocks (ebbs, count);
+
+ if (op->isaddr)
+ OP_SYMBOL (op)->isptr = 1;
+ OP_SYMBOL (op)->key = op->key;
+
+ /* There must be a definition in each branch of predecessors */
+ if (!findPrevUseSym (ebp, ic->prev, OP_SYMBOL(op)))
+ {
+ /* computeLiveRanges() is called at least twice */
+ if (emitWarnings)
+ {
+ if (IS_ITEMP (op))
+ {
+ if (OP_SYMBOL (op)->prereqv)
+ {
+ werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT,
+ OP_SYMBOL (op)->prereqv->name);
+ OP_SYMBOL (op)->prereqv->reqv = NULL;
+ OP_SYMBOL (op)->prereqv->allocreq = 1;
+ }
+ }
+ else
+ {
+ werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT,
+ OP_SYMBOL (op)->name);
+ }
+ }
+ /* is this block part of a loop? */
+ if (IS_ITEMP (op) && ebp->depth != 0)
+ {
+ /* extend the life range to the outermost loop */
+ unvisitBlocks(ebbs, count);
+ markWholeLoop (ebp, op->key);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* incUsed - increment a symbol's usage count */
+/*-----------------------------------------------------------------*/
+static void
+incUsed (iCode *ic, operand *op)
+{
+ if (ic->depth)
+ OP_SYMBOL (op)->used += (((unsigned int) 1 << ic->depth) + 1);
+ else
+ OP_SYMBOL (op)->used += 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* rliveClear - clears the rlive bitVectors */
+/*-----------------------------------------------------------------*/
+static void
+rliveClear (eBBlock **ebbs, int count)
+{
+ int i;
+
+ /* for all blocks do */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ /* for all instructions in this block do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ freeBitVect (ic->rlive);
+ ic->rlive = NULL;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* rlivePoint - for each point compute the ranges that are alive */
+/* The live range is only stored for ITEMPs; the same code is used */
+/* to find use of unitialized AUTOSYMs (an ITEMP is an AUTOSYM). */
+/* also, update funcUsesVolatile flag for current function */
+/*-----------------------------------------------------------------*/
+static void
+rlivePoint (eBBlock ** ebbs, int count, bool emitWarnings)
+{
+ int i, key;
+ eBBlock *succ;
+ bitVect *alive;
+
+ bool uses_volatile = false;
+
+ /* for all blocks do */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ /* for all instructions in this block do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ uses_volatile |= POINTER_GET (ic) && IS_VOLATILE (operandType (IC_LEFT(ic))->next) || IS_OP_VOLATILE (IC_LEFT(ic)) || IS_OP_VOLATILE (IC_RIGHT(ic));
+ uses_volatile |= POINTER_SET (ic) && IS_VOLATILE (operandType (IC_RESULT(ic))->next) || IS_OP_VOLATILE (IC_RESULT(ic));
+
+ if (!ic->rlive)
+ ic->rlive = newBitVect (operandKey);
+
+ if (SKIP_IC2(ic))
+ continue;
+
+ if (ic->op == JUMPTABLE && IS_SYMOP(IC_JTCOND(ic)))
+ {
+ incUsed (ic, IC_JTCOND(ic));
+
+ if (!IS_AUTOSYM(IC_JTCOND(ic)))
+ continue;
+
+ findPrevUse (ebbs[i], ic, IC_JTCOND(ic), ebbs, count, emitWarnings);
+ if (IS_ITEMP(IC_JTCOND(ic)))
+ {
+ unvisitBlocks(ebbs, count);
+ ic->rlive = bitVectSetBit (ic->rlive, IC_JTCOND(ic)->key);
+ findNextUse (ebbs[i], ic->next, IC_JTCOND(ic));
+ }
+
+ continue;
+ }
+
+ if (ic->op == IFX && IS_SYMOP(IC_COND(ic)))
+ {
+ incUsed (ic, IC_COND(ic));
+
+ if (!IS_AUTOSYM(IC_COND(ic)))
+ continue;
+
+ findPrevUse (ebbs[i], ic, IC_COND(ic), ebbs, count, emitWarnings);
+ if (IS_ITEMP(IC_COND(ic)))
+ {
+ unvisitBlocks (ebbs, count);
+ ic->rlive = bitVectSetBit (ic->rlive, IC_COND(ic)->key);
+ findNextUse (ebbs[i], ic->next, IC_COND(ic));
+ }
+
+ continue;
+ }
+
+ if (IS_SYMOP(IC_LEFT(ic)))
+ {
+ incUsed (ic, IC_LEFT(ic));
+ if (IS_AUTOSYM(IC_LEFT(ic)) &&
+ ic->op != ADDRESS_OF)
+ {
+ findPrevUse (ebbs[i], ic, IC_LEFT(ic), ebbs, count, emitWarnings);
+ if (IS_ITEMP(IC_LEFT(ic)))
+ {
+ unvisitBlocks(ebbs, count);
+ ic->rlive = bitVectSetBit (ic->rlive, IC_LEFT(ic)->key);
+ findNextUse (ebbs[i], ic->next, IC_LEFT(ic));
+
+ /* if this is a send extend the LR to the call */
+ if (ic->op == SEND)
+ {
+ iCode *lic;
+ for (lic = ic; lic; lic = lic->next)
+ {
+ if (lic->op == CALL || lic->op == PCALL)
+ {
+ markAlive (ic, lic->prev, IC_LEFT (ic)->key);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (IS_SYMOP(IC_RIGHT(ic)))
+ {
+ incUsed (ic, IC_RIGHT(ic));
+ if (IS_AUTOSYM(IC_RIGHT(ic)))
+ {
+ findPrevUse (ebbs[i], ic, IC_RIGHT(ic), ebbs, count, emitWarnings);
+ if (IS_ITEMP(IC_RIGHT(ic)))
+ {
+ unvisitBlocks(ebbs, count);
+ ic->rlive = bitVectSetBit (ic->rlive, IC_RIGHT(ic)->key);
+ findNextUse (ebbs[i], ic->next, IC_RIGHT(ic));
+ }
+ }
+ }
+
+ if (POINTER_SET(ic) && IS_SYMOP(IC_RESULT(ic)))
+ incUsed (ic, IC_RESULT(ic));
+
+ if (IS_AUTOSYM(IC_RESULT(ic)))
+ {
+ if (POINTER_SET(ic))
+ {
+ findPrevUse (ebbs[i], ic, IC_RESULT(ic), ebbs, count, emitWarnings);
+ }
+ if (IS_ITEMP(IC_RESULT(ic)))
+ {
+ unvisitBlocks(ebbs, count);
+ ic->rlive = bitVectSetBit (ic->rlive, IC_RESULT(ic)->key);
+ findNextUse (ebbs[i], ic->next, IC_RESULT(ic));
+ /* findNextUse sometimes returns 0 here, which means that ic is
+ dead code. Something should be done about this dead code since
+ e.g. register allocation suffers. */
+ }
+ }
+
+ if (!POINTER_SET(ic) && IC_RESULT(ic))
+ ic->defKey = IC_RESULT(ic)->key;
+
+ }
+
+ /* check all symbols that are alive in the last instruction */
+ /* but are not alive in all successors */
+
+ succ = setFirstItem (ebbs[i]->succList);
+ if (!succ)
+ continue;
+
+ alive = succ->sch->rlive;
+ while ((succ = setNextItem (ebbs[i]->succList)))
+ {
+ if (succ->sch)
+ alive = bitVectIntersect (alive, succ->sch->rlive);
+ }
+
+ if (ebbs[i]->ech)
+ alive = bitVectCplAnd ( bitVectCopy (ebbs[i]->ech->rlive), alive);
+
+ if(!alive)
+ continue;
+ for (key = 1; key < alive->size; key++)
+ {
+ if (!bitVectBitValue (alive, key))
+ continue;
+
+ unvisitBlocks(ebbs, count);
+ findNextUseSym (ebbs[i], NULL, hTabItemWithKey (liveRanges, key));
+ }
+
+ }
+
+ if(currFunc)
+ currFunc->funcUsesVolatile = uses_volatile;
+}
+
+/*-----------------------------------------------------------------*/
+/* computeClash - find out which live ranges collide with others */
+/*-----------------------------------------------------------------*/
+static void
+computeClash (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ /* for all blocks do */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ /* for every iCode do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ symbol *sym1, *sym2;
+ int key1, key2;
+
+ /* for all iTemps alive at this iCode */
+ for (key1 = 1; key1 < ic->rlive->size; key1++)
+ {
+ if (!bitVectBitValue(ic->rlive, key1))
+ continue;
+
+ sym1 = hTabItemWithKey(liveRanges, key1);
+
+ if (!sym1->isitmp)
+ continue;
+
+ /* for all other iTemps alive at this iCode */
+ for (key2 = key1+1; key2 < ic->rlive->size; key2++)
+ {
+ if (!bitVectBitValue(ic->rlive, key2))
+ continue;
+
+ sym2 = hTabItemWithKey(liveRanges, key2);
+
+ if (!sym2->isitmp)
+ continue;
+
+ /* if the result and left or right is an iTemp */
+ /* than possibly the iTemps do not clash */
+ if ((ic->op != JUMPTABLE) && (ic->op != IFX) &&
+ IS_ITEMP(IC_RESULT(ic)) &&
+ (IS_ITEMP(IC_LEFT(ic)) || IS_ITEMP(IC_RIGHT(ic))))
+ {
+ if (OP_SYMBOL(IC_RESULT(ic))->key == key1
+ && sym1->liveFrom == ic->seq
+ && sym2->liveTo == ic->seq)
+ {
+ if (IS_SYMOP(IC_LEFT(ic)))
+ if (OP_SYMBOL(IC_LEFT(ic))->key == key2)
+ continue;
+ if (IS_SYMOP(IC_RIGHT(ic)))
+ if (OP_SYMBOL(IC_RIGHT(ic))->key == key2)
+ continue;
+ }
+
+ if (OP_SYMBOL(IC_RESULT(ic))->key == key2
+ && sym2->liveFrom == ic->seq
+ && sym1->liveTo == ic->seq)
+ {
+ if (IS_SYMOP(IC_LEFT(ic)))
+ if (OP_SYMBOL(IC_LEFT(ic))->key == key1)
+ continue;
+ if (IS_SYMOP(IC_RIGHT(ic)))
+ if (OP_SYMBOL(IC_RIGHT(ic))->key == key1)
+ continue;
+ }
+ }
+
+ /* the iTemps do clash. set the bits in clashes */
+ sym1->clashes = bitVectSetBit (sym1->clashes, key2);
+ sym2->clashes = bitVectSetBit (sym2->clashes, key1);
+
+ /* check if they share the same spill location */
+ /* what is this good for? */
+ if (SYM_SPIL_LOC(sym1) && SYM_SPIL_LOC(sym2) &&
+ SYM_SPIL_LOC(sym1) == SYM_SPIL_LOC(sym2))
+ {
+ if (sym1->reqv && !sym2->reqv) SYM_SPIL_LOC(sym2)=NULL;
+ else if (sym2->reqv && !sym1->reqv) SYM_SPIL_LOC(sym1)=NULL;
+ else if (sym1->used > sym2->used) SYM_SPIL_LOC(sym2)=NULL;
+ else SYM_SPIL_LOC(sym1)=NULL;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* allDefsOutOfRange - all definitions are out of a range */
+/*-----------------------------------------------------------------*/
+bool
+allDefsOutOfRange (bitVect * defs, int fseq, int toseq)
+{
+ int i;
+
+ if (!defs)
+ return TRUE;
+
+ for (i = 0; i < defs->size; i++)
+ {
+ iCode *ic;
+
+ if (bitVectBitValue (defs, i) &&
+ (ic = hTabItemWithKey (iCodehTab, i)) &&
+ (ic->seq >= fseq && ic->seq <= toseq))
+ return FALSE;
+
+ }
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* notUsedInBlock - not used in this block */
+/*-----------------------------------------------------------------*/
+int
+notUsedInBlock (symbol * sym, eBBlock * ebp, iCode *ic)
+{
+ return (!bitVectBitsInCommon (sym->defs, ebp->usesDefs) &&
+ allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq) &&
+ allDefsOutOfRange (sym->uses, ebp->fSeq, ebp->lSeq));
+}
+
+/*-----------------------------------------------------------------*/
+/* adjustIChain - correct the sch and ech pointers */
+/*-----------------------------------------------------------------*/
+void
+adjustIChain (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath)
+ continue;
+
+ ic = ebbs[i]->sch;
+
+ /* is there any code for this eBBlock? (e.g. ROM assignment) */
+ if(!ic)continue;
+
+ while (ic->prev)
+ ic = ic->prev;
+ ebbs[i]->sch = ic;
+
+ ic = ebbs[i]->ech;
+ while (ic->next)
+ ic = ic->next;
+ ebbs[i]->ech = ic;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* computeLiveRanges - computes the live ranges for variables */
+/*-----------------------------------------------------------------*/
+void
+computeLiveRanges (eBBlock **ebbs, int count, bool emitWarnings)
+{
+ /* first look through all blocks and adjust the
+ sch and ech pointers */
+ adjustIChain (ebbs, count);
+
+ /* sequence the code the live ranges are computed
+ in terms of this sequence additionally the
+ routine will also create a hashtable of instructions */
+ iCodeSeq = 0;
+ setToNull ((void *) &iCodehTab);
+ iCodehTab = newHashTable (iCodeKey);
+ hashiCodeKeys (ebbs, count);
+ setToNull ((void *) &iCodeSeqhTab);
+ iCodeSeqhTab = newHashTable (iCodeKey);
+ sequenceiCode (ebbs, count);
+
+ /* mark the ranges live for each point */
+ setToNull ((void *) &liveRanges);
+ rlivePoint (ebbs, count, emitWarnings);
+
+ /* mark the from & to live ranges for variables used */
+ markLiveRanges (ebbs, count);
+
+ /* compute which overlaps with what */
+ computeClash(ebbs, count);
+}
+
+/*-----------------------------------------------------------------*/
+/* recomputeLiveRanges - recomputes the live ranges for variables */
+/*-----------------------------------------------------------------*/
+void
+recomputeLiveRanges (eBBlock **ebbs, int count, bool emitWarnings)
+{
+ symbol * sym;
+ int key;
+
+ /* clear all rlive bitVectors */
+ rliveClear (ebbs, count);
+
+ sym = hTabFirstItem (liveRanges, &key);
+ if (sym)
+ {
+ do {
+ sym->used = 0;
+ sym->liveFrom = 0;
+ sym->liveTo = 0;
+ freeBitVect (sym->clashes);
+ sym->clashes = NULL;
+ } while ( (sym = hTabNextItem (liveRanges, &key)));
+ }
+
+ /* do the LR computation again */
+ computeLiveRanges (ebbs, count, emitWarnings);
+}
+
+/*-----------------------------------------------------------------*/
+/* dump icode->rlive in all blocks */
+/*-----------------------------------------------------------------*/
+#if 0
+void
+dumpIcRlive (eBBlock ** ebbs, int count)
+{
+ int i, j;
+ iCode *ic;
+
+ /* for all blocks do */
+ for (i = 0; i < count; i++)
+ {
+ printf ("bb %d %s alive symbols:\n", i, ebbs[i]->entryLabel->name);
+ /* for all instructions in this block do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ printf ("\tic->key %d\n", ic->key);
+
+ if (!ic->rlive)
+ continue;
+ /* for all live Ranges alive at this point */
+ for (j = 1; j < ic->rlive->size; j++)
+ {
+ symbol *sym;
+
+ if (!bitVectBitValue (ic->rlive, j))
+ continue;
+
+ /* find the live range we are interested in */
+ if ((sym = hTabItemWithKey (liveRanges, j)))
+ printf ("\t\tsym->key %2d: %s\n", sym->key, sym->rname[0] ? sym->rname : sym->name);
+ }
+ }
+ }
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* Visit all iCodes reachable from ic */
+/*-----------------------------------------------------------------*/
+static void visit (set **visited, iCode *ic, const int key)
+{
+ symbol *lbl;
+
+ while (ic && !isinSet (*visited, ic) && bitVectBitValue (ic->rlive, key))
+ {
+ addSet (visited, ic);
+
+ switch (ic->op)
+ {
+ case GOTO:
+ ic = hTabItemWithKey (labelDef, (IC_LABEL (ic))->key);
+ break;
+ case RETURN:
+ ic = hTabItemWithKey (labelDef, returnLabel->key);
+ break;
+ case JUMPTABLE:
+ for (lbl = setFirstItem (IC_JTLABELS (ic)); lbl; lbl = setNextItem (IC_JTLABELS (ic)))
+ visit (visited, hTabItemWithKey (labelDef, lbl->key), key);
+ break;
+ case IFX:
+ visit (visited, hTabItemWithKey (labelDef, (IC_TRUE(ic) ? IC_TRUE (ic) : IC_FALSE (ic))->key), key);
+ ic = ic->next;
+ break;
+ default:
+ ic = ic->next;
+ if (!POINTER_SET (ic) && IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL_CONST (IC_RESULT (ic))->key == key)
+ {
+ addSet (visited, ic);
+ return;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* Split temporaries that have non-connected live ranges */
+/* Such temporaries can result from GCSE and losrpe, */
+/* And can confuse register allocation and rematerialization. */
+/*-----------------------------------------------------------------*/
+int
+separateLiveRanges (iCode *sic, ebbIndex *ebbi)
+{
+ set *candidates = 0;
+ symbol *sym;
+ int num_separated = 0;
+
+ // printf("separateLiveRanges()\n");
+
+ for (iCode *ic = sic; ic; ic = ic->next)
+ {
+ if (ic->op == IFX || ic->op == GOTO || ic->op == JUMPTABLE || !IC_RESULT (ic) || !IS_ITEMP (IC_RESULT (ic)) || bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) <= 1 || isinSet (candidates, OP_SYMBOL (IC_RESULT (ic))))
+ continue;
+
+ addSet (&candidates, OP_SYMBOL (IC_RESULT (ic)));
+ }
+
+ if (!candidates)
+ return (0);
+
+ for(sym = setFirstItem (candidates); sym; sym = setNextItem (candidates))
+ {
+ // printf("Looking at %s, %d definitions\n", sym->name, bitVectnBitsOn (sym->defs));
+
+ set *defs = 0;
+ set *uses = 0;
+ bool skip_uses = false;
+
+ for (int i = 0; i < sym->defs->size; i++)
+ {
+ if (bitVectBitValue (sym->defs, i))
+ {
+ iCode *dic;
+ if(dic = hTabItemWithKey (iCodehTab, i))
+ addSet (&defs, dic);
+ else
+ {
+ werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Definition not found");
+ return (num_separated);
+ }
+ }
+ if (bitVectBitValue (sym->uses, i))
+ {
+ iCode *uic;
+ if(uic = hTabItemWithKey (iCodehTab, i))
+ addSet (&uses, uic);
+ else
+ skip_uses = true; // werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Use not found"); // return (num_separated); seems too harsh.
+ }
+ }
+ do
+ {
+ set *visited = 0;
+ set *newdefs = 0;
+ int oldsize;
+
+ wassert (defs);
+ wassert (setFirstItem (defs));
+
+ // printf("Looking at def at %d now\n", ((iCode *)(setFirstItem (defs)))->key);
+
+ if (!bitVectBitValue (((iCode *)(setFirstItem (defs)))->rlive, sym->key))
+ {
+ werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Variable is not alive at one of its definitions");
+ break;
+ }
+
+ visit (&visited, setFirstItem (defs), sym->key);
+ addSet (&newdefs, setFirstItem (defs));
+
+ do
+ {
+ oldsize = elementsInSet(visited);
+ setFirstItem (defs);
+ for(iCode *ic = setNextItem (defs); ic; ic = setNextItem (defs))
+ {
+ // printf("Looking at other def at %d now\n", ic->key);
+ set *visited2 = 0;
+ set *intersection = 0;
+ visit (&visited2, ic, sym->key);
+ intersection = intersectSets (visited, visited2, THROW_NONE);
+ intersection = subtractFromSet (intersection, defs, THROW_DEST);
+ if (intersection)
+ {
+ visited = unionSets (visited, visited2, THROW_DEST);
+ addSet (&newdefs, ic);
+ }
+ deleteSet (&intersection);
+ deleteSet (&visited2);
+ }
+ }
+ while (oldsize < elementsInSet(visited));
+
+ defs = subtractFromSet (defs, newdefs, THROW_DEST);
+
+ if (newdefs && defs)
+ {
+ operand *tmpop = newiTempOperand (operandType (IC_RESULT ((iCode *)(setFirstItem (newdefs)))), TRUE);
+
+ // printf("Splitting %s from %s, using def at %d, op %d\n", OP_SYMBOL_CONST(tmpop)->name, sym->name, ((iCode *)(setFirstItem (newdefs)))->key, ((iCode *)(setFirstItem (newdefs)))->op);
+
+ for (iCode *ic = setFirstItem (visited); ic; ic = setNextItem (visited))
+ {
+ if (IC_LEFT (ic) && IS_ITEMP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic)) == sym)
+ IC_LEFT (ic) = operandFromOperand (tmpop);
+ if (IC_RIGHT (ic) && IS_ITEMP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic)) == sym)
+ IC_RIGHT (ic) = operandFromOperand (tmpop);
+ if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym && !POINTER_SET(ic) && ic->next && !isinSet (visited, ic->next))
+ continue;
+ if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym)
+ {
+ bool pset = POINTER_SET(ic);
+ IC_RESULT (ic) = operandFromOperand (tmpop);
+ if (pset)
+ IC_RESULT(ic)->isaddr = TRUE;
+ else
+ bitVectUnSetBit (sym->defs, ic->key);
+ }
+ bitVectUnSetBit (sym->uses, ic->key);
+
+ skip_uses = true;
+ num_separated++;
+ }
+ }
+ else if (!skip_uses)
+ {
+ set *undefined_uses = 0;
+ undefined_uses = subtractFromSet (uses, visited, THROW_NONE);
+
+ // Eliminate uses of undefined variables.
+ for (iCode *ic = setFirstItem (undefined_uses); ic; ic = setNextItem (undefined_uses))
+ {
+ iCode *prev = ic->prev;
+ iCode *next = ic->next;
+ if (prev && next)
+ {
+ prev->next = next;
+ next->prev = prev;
+ }
+
+ bitVectUnSetBit (sym->uses, ic->key);
+ if (IS_SYMOP (IC_RESULT (ic)))
+ bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key);
+ }
+
+ deleteSet (&undefined_uses);
+ }
+
+ deleteSet (&newdefs);
+ deleteSet (&visited);
+ }
+ while (elementsInSet(defs) > 1);
+
+ deleteSet (&defs);
+ deleteSet (&uses);
+ }
+
+ deleteSet (&candidates);
+
+ return (num_separated);
+}
+
+/*-----------------------------------------------------------------*/
+/* Shorten live ranges by swapping order of operations */
+/*-----------------------------------------------------------------*/
+int
+shortenLiveRanges (iCode *sic, ebbIndex *ebbi)
+{
+ int change = 0;
+
+ for (iCode *ic = sic; ic; ic = ic->next)
+ {
+ iCode *ifx = 0;
+
+ iCode *pic = ic->prev;
+ iCode *nic = ic->next;
+
+ if (!pic || !nic)
+ continue;
+
+ if (ic->op == IFX || nic->op == IFX)
+ continue;
+
+ if (nic->op == IPUSH || nic->op == SEND)
+ continue;
+
+ if (pic->op != '=' || !IS_ITEMP (IC_RESULT (pic)) || bitVectnBitsOn (OP_DEFS (IC_RESULT (pic))) != 1)
+ continue;
+
+ if (IC_LEFT (nic) != IC_RESULT (pic) && IC_RIGHT (nic) != IC_RESULT (pic) || bitVectnBitsOn (OP_USES (IC_RESULT (pic))) != 1)
+ continue;
+
+ if (IS_OP_VOLATILE (IC_RIGHT (pic)) || IS_OP_VOLATILE (IC_LEFT (nic)) || IS_OP_VOLATILE (IC_RIGHT (nic)) || IS_OP_VOLATILE (IC_RESULT (nic)))
+ continue;
+
+ if (isOperandEqual (IC_RESULT (pic), IC_LEFT (ic)) || isOperandEqual (IC_RESULT (pic), IC_RIGHT (ic)))
+ continue;
+
+ if (isOperandEqual (IC_RESULT (ic), IC_LEFT (nic)) || isOperandEqual (IC_RESULT (ic), IC_RIGHT (nic)))
+ continue;
+
+ if ((POINTER_SET (nic) || isOperandGlobal (IC_RESULT (nic))) && (POINTER_GET (ic) || isOperandGlobal (IC_LEFT (ic)) || isOperandGlobal (IC_RIGHT (ic))) ||
+ (POINTER_GET (nic) || isOperandGlobal (IC_LEFT (nic)) || isOperandGlobal (IC_RIGHT (nic))) && (POINTER_SET (ic) || POINTER_SET (nic) && isOperandGlobal (IC_RESULT (ic))))
+ continue;
+
+ if (isOperandGlobal (IC_RIGHT (pic))) // Might result in too many global operands per op for backend.
+ continue;
+
+ if (ifx = ifxForOp (IC_RESULT (nic), nic))
+ {
+ const symbol *starget = IC_TRUE (ifx) ? IC_TRUE (ifx) : IC_FALSE (ifx);
+ const iCode *itarget = eBBWithEntryLabel(ebbi, starget)->sch;
+
+ if (nic->next != ifx || bitVectBitValue(itarget->rlive, IC_RESULT (ic)->key))
+ continue;
+ }
+
+ if (IC_LEFT (nic) == IC_RESULT (pic))
+ IC_LEFT (nic) = IC_RIGHT (pic);
+ if (IC_RIGHT (nic) == IC_RESULT (pic))
+ IC_RIGHT (nic) = IC_RIGHT (pic);
+ bitVectUnSetBit (OP_USES (IC_RESULT (pic)), nic->key);
+ if (IS_SYMOP (IC_RIGHT (pic)))
+ bitVectSetBit (OP_USES (IC_RIGHT (pic)), nic->key);
+
+ // Assignment to self will get optimized out later
+ IC_LEFT (pic) = IC_RESULT (pic);
+ bitVectSetBit (OP_USES (IC_RESULT (pic)), pic->key);
+
+ pic->next = nic;
+ nic->prev = pic;
+ ic->prev = nic;
+ ic->next = nic->next;
+ nic->next = ic;
+ if (ic->next)
+ ic->next->prev = ic;
+
+ if (ifx) // Move calculation beyond ifx.
+ {
+ ifx->prev = ic->prev;
+ ic->next = ifx->next;
+ ifx->next = ic;
+ ic->prev = ifx;
+
+ ifx->prev->next = ifx;
+ if (ic->next)
+ ic->next->prev = ic;
+ }
+
+ change++;
+ }
+
+ return (change);
+}
+