+
+ return rmask;
+}
+
+/*-----------------------------------------------------------------*/
+/* mcs51_allBitregs :- returns bit vector of all bit registers */
+/*-----------------------------------------------------------------*/
+bitVect *
+mcs51_allBitregs (void)
+{
+ return _G.allBitregs;
+}
+
+/*-----------------------------------------------------------------*/
+/* rUmaskForOp :- returns register mask for an operand */
+/*-----------------------------------------------------------------*/
+bitVect *
+mcs51_rUmaskForOp (operand * op)
+{
+ bitVect *rumask;
+ symbol *sym;
+ int j;
+
+ /* only temporaries are assigned registers */
+ if (!IS_ITEMP (op))
+ return NULL;
+
+ sym = OP_SYMBOL (op);
+
+ /* if spilt or no registers assigned to it
+ then nothing */
+ if (sym->isspilt || !sym->nRegs)
+ return NULL;
+
+ rumask = newBitVect (mcs51_nRegs);
+
+ for (j = 0; j < sym->nRegs; j++)
+ {
+ if (sym->regs[j]) /* EEP - debug */
+ rumask = bitVectSetBit (rumask, sym->regs[j]->rIdx);
+ }
+
+ return rumask;
+}
+
+/*-----------------------------------------------------------------*/
+/* regsUsedIniCode :- returns bit vector of registers used in iCode */
+/*-----------------------------------------------------------------*/
+static bitVect *
+regsUsedIniCode (iCode * ic)
+{
+ bitVect *rmask = newBitVect (mcs51_nRegs);
+
+ /* do the special cases first */
+ if (ic->op == IFX)
+ {
+ rmask = bitVectUnion (rmask,
+ mcs51_rUmaskForOp (IC_COND (ic)));
+ goto ret;
+ }
+
+ /* for the jumptable */
+ if (ic->op == JUMPTABLE)
+ {
+ rmask = bitVectUnion (rmask,
+ mcs51_rUmaskForOp (IC_JTCOND (ic)));
+
+ goto ret;
+ }
+
+ /* of all other cases */
+ if (IC_LEFT (ic))
+ rmask = bitVectUnion (rmask,
+ mcs51_rUmaskForOp (IC_LEFT (ic)));
+
+
+ if (IC_RIGHT (ic))
+ rmask = bitVectUnion (rmask,
+ mcs51_rUmaskForOp (IC_RIGHT (ic)));
+
+ if (IC_RESULT (ic))
+ rmask = bitVectUnion (rmask,
+ mcs51_rUmaskForOp (IC_RESULT (ic)));
+
+ret:
+ return rmask;
+}
+
+/*-----------------------------------------------------------------*/
+/* createRegMask - for each instruction will determine the regsUsed */
+/*-----------------------------------------------------------------*/
+static void
+createRegMask (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ /* for all blocks */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath &&
+ (ebbs[i]->entryLabel != entryLabel &&
+ ebbs[i]->entryLabel != returnLabel))
+ continue;
+
+ /* for all instructions */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+
+ int j;
+
+ if (SKIP_IC2 (ic) || !ic->rlive)
+ continue;
+
+ /* first mark the registers used in this
+ instruction */
+ ic->rUsed = regsUsedIniCode (ic);
+ _G.funcrUsed = bitVectUnion (_G.funcrUsed, ic->rUsed);
+
+ /* now create the register mask for those
+ registers that are in use : this is a
+ super set of ic->rUsed */
+ ic->rMask = newBitVect (mcs51_nRegs + 1);
+
+ /* for all live Ranges alive at this point */
+ for (j = 1; j < ic->rlive->size; j++)
+ {
+ symbol *sym;
+ int k;
+
+ /* if not alive then continue */
+ if (!bitVectBitValue (ic->rlive, j))
+ continue;
+
+ /* find the live range we are interested in */
+ if (!(sym = hTabItemWithKey (liveRanges, j)))
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "createRegMask cannot find live range");
+ fprintf(stderr, "\tmissing live range: key=%d\n", j);
+ exit (0);
+ }
+
+ /* if no register assigned to it */
+ if (!sym->nRegs || sym->isspilt)
+ continue;
+
+ /* for all the registers allocated to it */
+ for (k = 0; k < sym->nRegs; k++)
+ if (sym->regs[k])
+ ic->rMask =
+ bitVectSetBit (ic->rMask, sym->regs[k]->rIdx);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* rematStr - returns the rematerialized string for a remat var */
+/*-----------------------------------------------------------------*/
+static char *
+rematStr (symbol * sym)
+{
+ iCode *ic = sym->rematiCode;
+ int offset = 0;
+
+ while (1)
+ {
+ /* if plus adjust offset to right hand side */
+ if (ic->op == '+')
+ {
+ offset += (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+
+ /* if minus adjust offset to right hand side */
+ if (ic->op == '-')
+ {
+ offset -= (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+
+ /* cast then continue */
+ if (IS_CAST_ICODE(ic)) {
+ ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+ continue;
+ }
+ /* we reached the end */
+ break;
+ }
+
+ if (offset)
+ {
+ SNPRINTF (buffer, sizeof(buffer),
+ "(%s %c 0x%04x)",
+ OP_SYMBOL (IC_LEFT (ic))->rname,
+ offset >= 0 ? '+' : '-',
+ abs (offset) & 0xffff);
+ }
+ else
+ {
+ strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
+ }
+ return buffer;
+}
+
+/*-----------------------------------------------------------------*/
+/* regTypeNum - computes the type & number of registers required */
+/*-----------------------------------------------------------------*/
+static void
+regTypeNum (eBBlock *ebbs)
+{
+ symbol *sym;
+ int k;
+ iCode *ic;
+
+ /* for each live range do */
+ for (sym = hTabFirstItem (liveRanges, &k); sym;
+ sym = hTabNextItem (liveRanges, &k))
+ {
+
+ /* if used zero times then no registers needed */
+ if ((sym->liveTo - sym->liveFrom) == 0)
+ continue;
+
+
+ /* if the live range is a temporary */
+ if (sym->isitmp)
+ {
+
+ /* if the type is marked as a conditional */
+ if (sym->regType == REG_CND)
+ continue;
+
+ /* if used in return only then we don't
+ need registers */
+ if (sym->ruonly || sym->accuse)
+ {
+ if (IS_AGGREGATE (sym->type) || sym->isptr)
+ sym->type = aggrToPtr (sym->type, FALSE);
+ else if (IS_BIT(sym->type))
+ sym->regType = REG_CND;
+ continue;
+ }
+
+ /* if the symbol has only one definition &
+ that definition is a get_pointer */
+ if (bitVectnBitsOn (sym->defs) == 1 &&
+ (ic = hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (sym->defs))) &&
+ POINTER_GET (ic) &&
+ !IS_BITVAR (sym->etype) &&
+ (aggrToPtrDclType (operandType (IC_LEFT (ic)), FALSE) == POINTER))
+ {
+
+ if (ptrPseudoSymSafe (sym, ic))
+ {
+ ptrPseudoSymConvert (sym, ic, rematStr (OP_SYMBOL (IC_LEFT (ic))));
+ continue;
+ }
+
+ /* if in data space or idata space then try to
+ allocate pointer register */
+
+ }
+
+ /* if not then we require registers */
+ sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ?
+ getSize (sym->type = aggrToPtr (sym->type, FALSE)) :
+ getSize (sym->type));
+
+ if (sym->nRegs > 4)
+ {
+ fprintf (stderr, "allocated more than 4 or 0 registers for type ");
+ printTypeChain (sym->type, stderr);
+ fprintf (stderr, "\n");
+ }
+
+ /* determine the type of register required */
+ if (sym->nRegs == 1 && IS_PTR (sym->type) && sym->uptr)
+ sym->regType = REG_PTR;
+ else if (IS_BIT(sym->type))
+ sym->regType = REG_BIT;
+ else
+ sym->regType = REG_GPR;
+ }
+ else
+ /* for the first run we don't provide */
+ /* registers for true symbols we will */
+ /* see how things go */
+ sym->nRegs = 0;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAllRegs - mark all registers as free */
+/*-----------------------------------------------------------------*/
+static void
+freeAllRegs ()
+{
+ int i;
+
+ for (i = 0; i < mcs51_nRegs; i++)
+ regs8051[i].isFree = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* deallocStackSpil - this will set the stack pointer back */
+/*-----------------------------------------------------------------*/
+static
+DEFSETFUNC (deallocStackSpil)
+{
+ symbol *sym = item;
+
+ deallocLocal (sym);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* farSpacePackable - returns the packable icode for far variables */
+/*-----------------------------------------------------------------*/
+static iCode *
+farSpacePackable (iCode * ic)
+{
+ iCode *dic;
+
+ /* go thru till we find a definition for the
+ symbol on the right */
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+ /* if the definition is a call then no */
+ if ((dic->op == CALL || dic->op == PCALL) &&
+ IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ {
+ return NULL;
+ }
+
+ /* if shift by unknown amount then not */
+ if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) &&
+ IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ return NULL;
+
+ /* if pointer get and size > 1 */
+ if (POINTER_GET (dic) &&
+ getSize (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)) > 1)
+ return NULL;
+
+ if (POINTER_SET (dic) &&
+ getSize (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)) > 1)
+ return NULL;
+
+ if (dic->op == IFX)
+ {
+ if (IC_COND (dic) &&
+ IS_TRUE_SYMOP (IC_COND (dic)) &&
+ isOperandInFarSpace (IC_COND (dic)))
+ return NULL;
+ }
+ else if (dic->op == JUMPTABLE)
+ {
+ if (IC_JTCOND (dic) &&
+ IS_TRUE_SYMOP (IC_JTCOND (dic)) &&
+ isOperandInFarSpace (IC_JTCOND (dic)))
+ return NULL;
+ }
+ else
+ {
+ /* if any tree is a true symbol in far space */
+ if (IC_RESULT (dic) &&
+ IS_TRUE_SYMOP (IC_RESULT (dic)) &&
+ isOperandInFarSpace (IC_RESULT (dic)))
+ return NULL;
+
+ if (IC_RIGHT (dic) &&
+ IS_TRUE_SYMOP (IC_RIGHT (dic)) &&
+ isOperandInFarSpace (IC_RIGHT (dic)) &&
+ !isOperandEqual (IC_RIGHT (dic), IC_RESULT (ic)))
+ return NULL;
+
+ if (IC_LEFT (dic) &&
+ IS_TRUE_SYMOP (IC_LEFT (dic)) &&
+ isOperandInFarSpace (IC_LEFT (dic)) &&
+ !isOperandEqual (IC_LEFT (dic), IC_RESULT (ic)))
+ return NULL;
+ }
+
+ if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (dic)))
+ {
+ if ((dic->op == LEFT_OP ||
+ dic->op == RIGHT_OP ||
+ dic->op == '-') &&
+ IS_OP_LITERAL (IC_RIGHT (dic)))
+ return NULL;
+ else
+ return dic;
+ }
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegsForAssign - register reduction for assignment */
+/*-----------------------------------------------------------------*/
+static int
+packRegsForAssign (iCode * ic, eBBlock * ebp)
+{
+ iCode *dic, *sic;
+
+ if (!IS_ITEMP (IC_RIGHT (ic)) ||
+ OP_SYMBOL (IC_RIGHT (ic))->isind ||
+ OP_LIVETO (IC_RIGHT (ic)) > ic->seq)
+ {
+ return 0;
+ }
+
+ /* if the true symbol is defined in far space or on stack
+ then we should not since this will increase register pressure */
+ if (isOperandInFarSpace(IC_RESULT(ic)) && !farSpacePackable(ic)) {
+ return 0;
+ }
+
+ /* find the definition of iTempNN scanning backwards if we find a
+ a use of the true symbol in before we find the definition then
+ we cannot */
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+ int crossedCall = 0;
+
+ /* We can pack across a function call only if it's a local */
+ /* variable or our parameter. Never pack global variables */
+ /* or parameters to a function we call. */
+ if ((dic->op == CALL || dic->op == PCALL))
+ {
+ if (!OP_SYMBOL (IC_RESULT (ic))->ismyparm
+ && !OP_SYMBOL (IC_RESULT (ic))->islocal)
+ {
+ crossedCall = 1;
+ }
+ }
+
+ /* Don't move an assignment out of a critical block */
+ if (dic->op == CRITICAL)
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (SKIP_IC2 (dic))
+ continue;
+
+ if (dic->op == IFX)
+ {
+ if (IS_SYMOP (IC_COND (dic)) &&
+ (IC_COND (dic)->key == IC_RESULT (ic)->key ||
+ IC_COND (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+ }
+ else
+ {
+ if (IS_TRUE_SYMOP (IC_RESULT (dic)) &&
+ IS_OP_VOLATILE (IC_RESULT (dic)))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_RESULT (dic)) &&
+ IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ {
+ if (POINTER_SET (dic))
+ dic = NULL;
+
+ break;
+ }
+
+ if (IS_SYMOP (IC_RIGHT (dic)) &&
+ (IC_RIGHT (dic)->key == IC_RESULT (ic)->key ||
+ IC_RIGHT (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_LEFT (dic)) &&
+ (IC_LEFT (dic)->key == IC_RESULT (ic)->key ||
+ IC_LEFT (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_RESULT (dic)) &&
+ IC_RESULT (dic)->key == IC_RESULT (ic)->key)
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (crossedCall)
+ {
+ dic = NULL;
+ break;
+ }
+
+ }
+ }
+
+ if (!dic)
+ return 0; /* did not find */
+
+ /* if assignment then check that right is not a bit */
+ if (ASSIGNMENT (ic) && !POINTER_SET (ic))
+ {
+ sym_link *etype = operandType (IC_RESULT (dic));
+ if (IS_BITFIELD (etype))
+ {
+ /* if result is a bit too then it's ok */
+ etype = operandType (IC_RESULT (ic));
+ if (!IS_BITFIELD (etype))
+ {
+ return 0;
+ }
+ }
+ }
+
+ /* if the result is on stack or iaccess then it must be
+ the same atleast one of the operands */
+ if (OP_SYMBOL (IC_RESULT (ic))->onStack ||
+ OP_SYMBOL (IC_RESULT (ic))->iaccess)
+ {
+
+ /* the operation has only one symbol
+ operator then we can pack */
+ if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) ||
+ (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic))))
+ goto pack;
+
+ if (!((IC_LEFT (dic) &&
+ IC_RESULT (ic)->key == IC_LEFT (dic)->key) ||
+ (IC_RIGHT (dic) &&
+ IC_RESULT (ic)->key == IC_RIGHT (dic)->key)))
+ return 0;
+ }
+pack:
+ /* found the definition */
+ /* replace the result with the result of */
+ /* this assignment and remove this assignment */
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+ ReplaceOpWithCheaperOp(&IC_RESULT (dic), IC_RESULT (ic));
+
+ if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq)
+ {
+ OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq;
+ }
+ // TODO: and the otherway around?
+
+ /* delete from liverange table also
+ delete from all the points inbetween and the new
+ one */
+ for (sic = dic; sic != ic; sic = sic->next)
+ {
+ bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key);
+ if (IS_ITEMP (IC_RESULT (dic)))
+ bitVectSetBit (sic->rlive, IC_RESULT (dic)->key);
+ }
+
+ remiCodeFromeBBlock (ebp, ic);
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key);
+ hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
+ OP_DEFS(IC_RESULT (dic))=bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
+ return 1;
+}
+
+/*------------------------------------------------------------------*/
+/* findAssignToSym : scanning backwards looks for first assig found */
+/*------------------------------------------------------------------*/
+static iCode *
+findAssignToSym (operand * op, iCode * ic)
+{
+ iCode *dic;
+
+ /* This routine is used to find sequences like
+ iTempAA = FOO;
+ ...; (intervening ops don't use iTempAA or modify FOO)
+ blah = blah + iTempAA;
+
+ and eliminate the use of iTempAA, freeing up its register for
+ other uses.
+ */
+
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+
+ /* if definition by assignment */
+ if (dic->op == '=' &&
+ !POINTER_SET (dic) &&
+ IC_RESULT (dic)->key == op->key
+/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */
+ )
+ break; /* found where this temp was defined */
+
+ /* if we find an usage then we cannot delete it */
+
+ if (dic->op == IFX)
+ {
+ if (IC_COND (dic) && IC_COND (dic)->key == op->key)
+ return NULL;
+ }
+ else if (dic->op == JUMPTABLE)
+ {
+ if (IC_JTCOND (dic) && IC_JTCOND (dic)->key == op->key)
+ return NULL;
+ }
+ else
+ {
+ if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key)
+ return NULL;
+
+ if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key)
+ return NULL;
+
+ if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key)
+ return NULL;
+ }
+ }
+
+ if (!dic)
+ return NULL; /* didn't find any assignment to op */
+
+ /* we are interested only if defined in far space */
+ /* or in stack space in case of + & - */
+
+ /* if assigned to a non-symbol then don't repack regs */
+ if (!IS_SYMOP (IC_RIGHT (dic)))
+ return NULL;
+
+ /* if the symbol is volatile then we should not */
+ if (isOperandVolatile (IC_RIGHT (dic), TRUE))
+ return NULL;
+ /* XXX TODO --- should we be passing FALSE to isOperandVolatile()?
+ What does it mean for an iTemp to be volatile, anyway? Passing
+ TRUE is more cautious but may prevent possible optimizations */
+
+ /* if the symbol is in far space then we should not */
+ if (isOperandInFarSpace (IC_RIGHT (dic)))
+ return NULL;
+
+ /* for + & - operations make sure that
+ if it is on the stack it is the same
+ as one of the three operands */
+ if ((ic->op == '+' || ic->op == '-') &&
+ OP_SYMBOL (IC_RIGHT (dic))->onStack)
+ {
+
+ if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key &&
+ IC_LEFT (ic)->key != IC_RIGHT (dic)->key &&
+ IC_RIGHT (ic)->key != IC_RIGHT (dic)->key)
+ return NULL;
+ }
+
+ /* now make sure that the right side of dic
+ is not defined between ic & dic */
+ if (dic)
+ {
+ iCode *sic = dic->next;
+
+ for (; sic != ic; sic = sic->next)
+ if (IC_RESULT (sic) &&
+ IC_RESULT (sic)->key == IC_RIGHT (dic)->key)
+ return NULL;
+ }
+
+ return dic;
+}
+
+/*-----------------------------------------------------------------*/
+/* reassignAliasedSym - used by packRegsForSupport to replace */
+/* redundant iTemp with equivalent symbol */
+/*-----------------------------------------------------------------*/
+static void
+reassignAliasedSym (eBBlock *ebp, iCode *assignment, iCode *use, operand *op)
+{
+ iCode *ic;
+ unsigned oldSymKey, newSymKey;
+
+ oldSymKey = op->key;
+ newSymKey = IC_RIGHT(assignment)->key;
+
+ /* only track live ranges of compiler-generated temporaries */
+ if (!IS_ITEMP(IC_RIGHT(assignment)))
+ newSymKey = 0;
+
+ /* update the live-value bitmaps */
+ for (ic = assignment; ic != use; ic = ic->next) {
+ bitVectUnSetBit (ic->rlive, oldSymKey);
+ if (newSymKey != 0)
+ ic->rlive = bitVectSetBit (ic->rlive, newSymKey);
+ }
+
+ /* update the sym of the used operand */
+ OP_SYMBOL(op) = OP_SYMBOL(IC_RIGHT(assignment));
+ op->key = OP_SYMBOL(op)->key;
+ OP_SYMBOL(op)->accuse = 0;
+
+ /* update the sym's liverange */
+ if ( OP_LIVETO(op) < ic->seq )
+ setToRange(op, ic->seq, FALSE);
+
+ /* remove the assignment iCode now that its result is unused */
+ remiCodeFromeBBlock (ebp, assignment);
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(assignment))->defs, assignment->key);
+ hTabDeleteItem (&iCodehTab, assignment->key, assignment, DELETE_ITEM, NULL);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* packRegsForSupport :- reduce some registers for support calls */
+/*-----------------------------------------------------------------*/
+static int
+packRegsForSupport (iCode * ic, eBBlock * ebp)
+{
+ iCode *dic;
+
+ /* for the left & right operand :- look to see if the
+ left was assigned a true symbol in far space in that
+ case replace them */
+
+ if (IS_ITEMP (IC_LEFT (ic)) &&
+ OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq)
+ {
+ dic = findAssignToSym (IC_LEFT (ic), ic);
+
+ if (dic)
+ {
+ /* found it we need to remove it from the block */
+ reassignAliasedSym (ebp, dic, ic, IC_LEFT(ic));
+ return 1;
+ }
+ }
+
+ /* do the same for the right operand */
+ if (IS_ITEMP (IC_RIGHT (ic)) &&
+ OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq)
+ {
+ iCode *dic = findAssignToSym (IC_RIGHT (ic), ic);
+
+ if (dic)
+ {
+ /* if this is a subtraction & the result
+ is a true symbol in far space then don't pack */
+ if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic)))
+ {
+ sym_link *etype = getSpec (operandType (IC_RESULT (dic)));
+ if (IN_FARSPACE (SPEC_OCLS (etype)))
+ return 0;
+ }
+ /* found it we need to remove it from the
+ block */
+ reassignAliasedSym (ebp, dic, ic, IC_RIGHT(ic));
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
+
+
+/*-----------------------------------------------------------------*/
+/* packRegsForOneuse : - will reduce some registers for single Use */
+/*-----------------------------------------------------------------*/
+static iCode *
+packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
+{
+ iCode *dic, *sic;
+
+ /* if returning a literal then do nothing */
+ if (!IS_ITEMP (op))
+ return NULL;
+
+ /* if rematerializable or already return use then do nothing */
+ if (OP_SYMBOL(op)->remat || OP_SYMBOL(op)->ruonly)
+ return NULL;
+
+ /* only upto 2 bytes since we cannot predict
+ the usage of b, & acc */
+ if (getSize (operandType (op)) > (fReturnSizeMCS51 - 2))
+ return NULL;
+
+ if (ic->op != RETURN &&
+ ic->op != SEND &&
+ !POINTER_SET (ic) &&
+ !POINTER_GET (ic))
+ return NULL;
+
+ if (ic->op == SEND && ic->argreg != 1) return NULL;
+
+ /* this routine will mark the symbol as used in one
+ instruction use only && if the definition is local
+ (ie. within the basic block) && has only one definition &&
+ that definition is either a return value from a
+ function or does not contain any variables in
+ far space */
+ if (bitVectnBitsOn (OP_USES (op)) > 1)
+ return NULL;
+
+ /* if it has only one definition */
+ if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+ return NULL; /* has more than one definition */
+
+ /* get that definition */
+ if (!(dic =
+ hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (OP_DEFS (op)))))
+ return NULL;
+
+ /* if that only usage is a cast */
+ if (dic->op == CAST) {
+ /* to a bigger type */
+ if (getSize(OP_SYM_TYPE(IC_RESULT(dic))) >
+ getSize(OP_SYM_TYPE(IC_RIGHT(dic)))) {
+ /* than we can not, since we cannot predict the usage of b & acc */
+ return NULL;
+ }
+ }
+
+ /* found the definition now check if it is local */
+ if (dic->seq < ebp->fSeq ||
+ dic->seq > ebp->lSeq)
+ return NULL; /* non-local */
+
+ /* now check if it is the return from
+ a function call */
+ if (dic->op == CALL || dic->op == PCALL)
+ {
+ if (ic->op != SEND && ic->op != RETURN &&
+ !POINTER_SET(ic) && !POINTER_GET(ic))
+ {
+ OP_SYMBOL (op)->ruonly = 1;
+ return dic;
+ }
+ }
+ else
+ {
+ /* otherwise check that the definition does
+ not contain any symbols in far space */
+ if (isOperandInFarSpace (IC_LEFT (dic)) ||
+ isOperandInFarSpace (IC_RIGHT (dic)) ||
+ IS_OP_RUONLY (IC_LEFT (ic)) ||
+ IS_OP_RUONLY (IC_RIGHT (ic)))
+ {
+ return NULL;
+ }
+
+ /* if pointer set then make sure the pointer
+ is one byte */
+ if (POINTER_SET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+ }
+
+ /* Make sure no overlapping liverange is already assigned to DPTR */
+ if (OP_SYMBOL(op)->clashes)
+ {
+ symbol *sym;
+ int i;
+
+ for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ )
+ {
+ if (bitVectBitValue(OP_SYMBOL(op)->clashes,i))
+ {
+ sym = hTabItemWithKey(liveRanges,i);
+ if (sym->ruonly)
+ return NULL ;
+ }
+ }
+ }
+
+ sic = dic;
+
+ /* also make sure the intervening instructions
+ don't have anything in far space */
+ for (dic = dic->next; dic && dic != ic && sic != ic; dic = dic->next)
+ {
+ /* if there is an intervening function call then no */
+ if (dic->op == CALL || dic->op == PCALL)
+ return NULL;
+ /* if pointer set then make sure the pointer
+ is one byte */
+ if (POINTER_SET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+
+ /* if address of & the result is remat the okay */
+ if (dic->op == ADDRESS_OF &&
+ OP_SYMBOL (IC_RESULT (dic))->remat)
+ continue;
+
+ /* if operand has size of three or more & this
+ operation is a '*','/' or '%' then 'b' may
+ cause a problem */
+ if ((dic->op == '%' || dic->op == '/' || dic->op == '*') &&
+ getSize (operandType (op)) >= 3)
+ return NULL;
+
+ /* if left or right or result is in far space */
+ if (isOperandInFarSpace (IC_LEFT (dic)) ||
+ isOperandInFarSpace (IC_RIGHT (dic)) ||
+ isOperandInFarSpace (IC_RESULT (dic)) ||
+ IS_OP_RUONLY (IC_LEFT (dic)) ||
+ IS_OP_RUONLY (IC_RIGHT (dic)) ||
+ IS_OP_RUONLY (IC_RESULT (dic)))
+ {
+ return NULL;
+ }
+ /* if left or right or result is on stack */
+ if (isOperandOnStack(IC_LEFT(dic)) ||
+ isOperandOnStack(IC_RIGHT(dic)) ||
+ isOperandOnStack(IC_RESULT(dic))) {
+ return NULL;
+ }
+ }
+
+ OP_SYMBOL (op)->ruonly = 1;
+ return sic;