*/
#include "z80.h"
+#include "SDCCicode.h"
/* Flags to turn off optimisations.
*/
{
DISABLE_PACK_ACC = 0,
DISABLE_PACK_ASSIGN = 0,
- /* Pack for one use is quite broken. */
- DISABLE_PACK_ONE_USE = 1,
+ DISABLE_PACK_ONE_USE = 0,
DISABLE_PACK_HL = 0,
+ DISABLE_PACK_IY = 0
};
/* Flags to turn on debugging code.
D_ALLOC = 0,
D_ALLOC2 = 0,
D_ACCUSE2 = 0,
- D_ACCUSE2_VERBOSE = 0
+ D_ACCUSE2_VERBOSE = 0,
+ D_HLUSE = 0,
+ D_HLUSE2 = 0,
+ D_HLUSE2_VERBOSE = 0,
+ D_FILL_GAPS = 0,
+ D_PACK_IY = 0,
+ D_PACK_HLUSE3 = 0
};
#if 1
bitVect *spiltSet;
set *stackSpil;
bitVect *regAssigned;
+ bitVect *totRegAssigned; /* final set of LRs that got into registers */
short blockSpil;
int slocNum;
/* registers used in a function */
#define GBZ80_MAX_REGS ((sizeof(_gbz80_regs)/sizeof(_gbz80_regs[0]))-1)
static void spillThis (symbol *);
+static void freeAllRegs ();
/** Allocates register of given type.
'type' is not used on the z80 version. It was used to select
return nFreeRegs (type);
}
+/*-----------------------------------------------------------------*/
+/* useReg - marks a register as used */
+/*-----------------------------------------------------------------*/
+static void
+useReg (regs * reg)
+{
+ reg->isFree = 0;
+}
#if 0
/*-----------------------------------------------------------------*/
for (sym = setFirstItem (itmpStack); sym;
sym = setNextItem (itmpStack))
{
+ if (bitVectBitValue(sym->clashes,fsym->key))
+ return 0;
+#if 0
// if sym starts before (or on) our end point
// and ends after (or on) our start point,
// it is an overlap.
{
return 0;
}
+#endif
}
return 1;
}
sloc->type = copyLinkChain (sym->type);
sloc->etype = getSpec (sloc->type);
SPEC_SCLS (sloc->etype) = S_AUTO;
+ SPEC_EXTR (sloc->etype) = 0;
+ SPEC_STAT (sloc->etype) = 0;
+ SPEC_VOLATILE(sloc->etype) = 0;
allocLocal (sloc);
}
/* mark it has spilt & put it in the spilt set */
- sym->isspilt = 1;
+ sym->isspilt = sym->spillA = 1;
_G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key);
bitVectUnSetBit (_G.regAssigned, sym->key);
+ bitVectUnSetBit (_G.totRegAssigned, sym->key);
for (i = 0; i < sym->nRegs; i++)
{
if (sym->usl.spillLoc && !sym->remat)
{
- sym->usl.spillLoc->allocreq = 1;
+ sym->usl.spillLoc->allocreq++;
}
return;
}
sym->usl.spillLoc->name));
sym->spildir = 1;
/* mark it as allocation required */
- sym->usl.spillLoc->allocreq = 1;
+ sym->usl.spillLoc->allocreq++;
return sym;
}
sym = leastUsedLR (selectS);
/* mark this as allocation required */
- sym->usl.spillLoc->allocreq = 1;
+ sym->usl.spillLoc->allocreq++;
return sym;
}
#endif
{
D (D_ALLOC, ("selectSpil: using with spill.\n"));
sym = leastUsedLR (selectS);
- sym->usl.spillLoc->allocreq = 1;
+ sym->usl.spillLoc->allocreq++;
return sym;
}
D (D_ALLOC, ("selectSpil: creating new spill.\n"));
/* return a created spil location */
sym = createStackSpil (leastUsedLR (selectS));
- sym->usl.spillLoc->allocreq = 1;
+ sym->usl.spillLoc->allocreq++;
return sym;
}
ssym = selectSpil (ic, ebp, forSym);
/* mark it as spilt */
- ssym->isspilt = 1;
+ ssym->isspilt = ssym->spillA = 1;
_G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key);
/* mark it as not register assigned &
take it away from the set */
bitVectUnSetBit (_G.regAssigned, ssym->key);
+ bitVectUnSetBit (_G.totRegAssigned, ssym->key);
/* mark the registers as free */
for (i = 0; i < ssym->nRegs; i++)
goto tryAgain;
}
+static regs *getRegGprNoSpil()
+{
+ regs *reg;
+
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ {
+ D (D_ALLOC, ("getRegGprNoSpil: got a reg.\n"));
+ return reg;
+ }
+ assert(0);
+}
+
/** Symbol has a given register.
*/
static bool
}
_G.regAssigned = bitVectSetBit (_G.regAssigned, result->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, result->key);
}
/* free the remaining */
D (D_ALLOC, ("reassingLR: on sym %p\n", sym));
/* not spilt any more */
- sym->isspilt = sym->blockSpil = sym->remainSpil = 0;
+ sym->isspilt = sym->spillA = sym->blockSpil = sym->remainSpil = 0;
bitVectUnSetBit (_G.spiltSet, sym->key);
_G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
_G.blockSpil--;
if this happens make sure they are in the same position as the operand
otherwise chaos results.
*/
-static void
-positionRegs (symbol * result, symbol * opsym, int lineno)
+static int
+positionRegs (symbol * result, symbol * opsym)
{
int count = min (result->nRegs, opsym->nRegs);
int i, j = 0, shared = 0;
+ int change = 0;
D (D_ALLOC, ("positionRegs: on result %p opsum %p line %u\n", result, opsym, lineno));
/* if the result has been spilt then cannot share */
if (opsym->isspilt)
- return;
+ return 0;
again:
shared = 0;
/* first make sure that they actually share */
regs *tmp = result->regs[i];
result->regs[i] = result->regs[j];
result->regs[j] = tmp;
+ change ++;
goto again;
}
+ return change ;
}
/** Try to allocate a pair of registers to the symbol.
sym->regs[0] = ®sZ80[i];
regsZ80[i + 1].isFree = 0;
sym->regs[1] = ®sZ80[i + 1];
+ sym->regType = REG_PAIR;
+
if (currFunc)
{
currFunc->regsUsed =
/* if result is present && is a true symbol */
if (IC_RESULT (ic) && ic->op != IFX &&
IS_TRUE_SYMOP (IC_RESULT (ic)))
- OP_SYMBOL (IC_RESULT (ic))->allocreq = 1;
+ OP_SYMBOL (IC_RESULT (ic))->allocreq++;
/* take away registers from live
ranges that end at this instruction */
/* if none of the liveRanges have a spillLocation then better
to spill this one than anything else already assigned to registers */
if (liveRangesWith(spillable,noSpilLoc,ebbs[i],ic)) {
+ /* if this is local to this block then we might find a block spil */
+ if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq)) {
spillThis (sym);
continue;
+ }
}
}
}
/* else we assign registers to it */
_G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
/* Special case: Try to fit into a reg pair if
available */
if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) &&
OP_SYMBOL (IC_LEFT (ic))->nRegs && ic->op != '=')
positionRegs (OP_SYMBOL (IC_RESULT (ic)),
- OP_SYMBOL (IC_LEFT (ic)), ic->lineno);
+ OP_SYMBOL (IC_LEFT (ic)));
/* do the same for the right operand */
if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) &&
OP_SYMBOL (IC_RIGHT (ic))->nRegs)
positionRegs (OP_SYMBOL (IC_RESULT (ic)),
- OP_SYMBOL (IC_RIGHT (ic)), ic->lineno);
+ OP_SYMBOL (IC_RIGHT (ic)));
}
}
}
}
+/*-----------------------------------------------------------------*/
+/* fillGaps - Try to fill in the Gaps left by Pass1 */
+/*-----------------------------------------------------------------*/
+static void fillGaps()
+{
+ symbol *sym =NULL;
+ int key =0;
+
+ if (getenv("DISABLE_FILL_GAPS")) return;
+
+ /* look for livernages that was spilt by the allocator */
+ for (sym = hTabFirstItem(liveRanges,&key) ; sym ;
+ sym = hTabNextItem(liveRanges,&key)) {
+
+ int i;
+ int pdone = 0;
+
+ if (!sym->spillA || !sym->clashes || sym->remat) continue ;
+
+ /* find the liveRanges this one clashes with, that are
+ still assigned to registers & mark the registers as used*/
+ for ( i = 0 ; i < sym->clashes->size ; i ++) {
+ int k;
+ symbol *clr;
+
+ if (bitVectBitValue(sym->clashes,i) == 0 || /* those that clash with this */
+ bitVectBitValue(_G.totRegAssigned,i) == 0) /* and are still assigned to registers */
+ continue ;
+
+ assert (clr = hTabItemWithKey(liveRanges,i));
+
+ /* mark these registers as used */
+ for (k = 0 ; k < clr->nRegs ; k++ )
+ useReg(clr->regs[k]);
+ }
+
+ if (willCauseSpill(sym->nRegs,sym->regType)) {
+ /* NOPE :( clear all registers & and continue */
+ freeAllRegs();
+ continue ;
+ }
+
+ /* THERE IS HOPE !!!! */
+ for (i=0; i < sym->nRegs ; i++ ) {
+ sym->regs[i] = getRegGprNoSpil ();
+ }
+
+ /* for all its definitions check if the registers
+ allocated needs positioning NOTE: we can position
+ only ONCE if more than One positioning required
+ then give up */
+ sym->isspilt = 0;
+ for (i = 0 ; i < sym->defs->size ; i++ ) {
+ if (bitVectBitValue(sym->defs,i)) {
+ iCode *ic;
+ if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+ if (SKIP_IC(ic)) continue;
+ assert(isSymbolEqual(sym,OP_SYMBOL(IC_RESULT(ic)))); /* just making sure */
+ /* if left is assigned to registers */
+ if (IS_SYMOP(IC_LEFT(ic)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_LEFT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_LEFT(ic)));
+ }
+ if (IS_SYMOP(IC_RIGHT(ic)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RIGHT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_RIGHT(ic)));
+ }
+ if (pdone > 1) break;
+ }
+ }
+ for (i = 0 ; i < sym->uses->size ; i++ ) {
+ if (bitVectBitValue(sym->uses,i)) {
+ iCode *ic;
+ if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+ if (SKIP_IC(ic)) continue;
+ if (!IS_ASSIGN_ICODE(ic)) continue ;
+
+ /* if result is assigned to registers */
+ if (IS_SYMOP(IC_RESULT(ic)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RESULT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_RESULT(ic)));
+ }
+ if (pdone > 1) break;
+ }
+ }
+ /* had to position more than once GIVE UP */
+ if (pdone > 1) {
+ /* UNDO all the changes we made to try this */
+ sym->isspilt = 1;
+ for (i=0; i < sym->nRegs ; i++ ) {
+ sym->regs[i] = NULL;
+ }
+ freeAllRegs();
+ D(D_FILL_GAPS,("Fill Gap gave up due to positioning for %s in function %s\n",sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+ continue ;
+ }
+ D(D_FILL_GAPS,("FILLED GAP for %s in function %s\n",sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+ _G.totRegAssigned = bitVectSetBit(_G.totRegAssigned,sym->key);
+ sym->isspilt = sym->spillA = 0 ;
+ sym->usl.spillLoc->allocreq--;
+ freeAllRegs();
+ }
+}
+
/*-----------------------------------------------------------------*/
/* rUmaskForOp :- returns register mask for an operand */
/*-----------------------------------------------------------------*/
return 0;
}
-#if 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)))
- {
- if ((dic = farSpacePackable (ic)))
- goto pack;
- else
- return 0;
- }
-#endif
-
/* 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)
{
- /* if there is a function call and this is
- a parameter & not my parameter then don't pack it */
- if ((dic->op == CALL || dic->op == PCALL) &&
- (OP_SYMBOL (IC_RESULT (ic))->_isparm &&
- !OP_SYMBOL (IC_RESULT (ic))->ismyparm))
+ /* PENDING: Don't pack across function calls. */
+ if (dic->op == CALL || dic->op == PCALL)
{
dic = NULL;
break;
dic = NULL;
break;
}
-#if 0
- if (POINTER_SET (dic) &&
- IC_RESULT (dic)->key == IC_RESULT (ic)->key)
- {
- dic = NULL;
- break;
- }
-#endif
}
if (!dic)
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))) ||
/* 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);
IC_RESULT (dic) = IC_RESULT (ic);
if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq)
remiCodeFromeBBlock (ebp, ic);
// PENDING: Check vs mcs51
+ 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;
}
IC_RIGHT (dic)->operand.symOperand;
IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
remiCodeFromeBBlock (ebp, dic);
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+ hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
// PENDING: Check vs mcs51
change++;
}
IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
remiCodeFromeBBlock (ebp, dic);
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+ hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
// PENDING: vs mcs51
change++;
}
/* only upto 2 bytes since we cannot predict
the usage of b, & acc */
- if (getSize (operandType (op)) > 2 &&
- ic->op != RETURN &&
+ if (getSize (operandType (op)) > 2)
+ return NULL;
+
+ if (ic->op != RETURN &&
ic->op != SEND)
return NULL;
/* 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)
+ if (ic->op != SEND && ic->op != RETURN &&
+ !POINTER_SET(ic) && !POINTER_GET(ic))
{
OP_SYMBOL (op)->ruonly = 1;
return dic;
{
iCode *uic;
+ /* if this is an aggregate, e.g. a one byte char array */
+ if (IS_AGGREGATE(operandType(IC_RESULT(ic)))) {
+ return;
+ }
+
/* if + or - then it has to be one byte result */
if ((ic->op == '+' || ic->op == '-')
&& getSize (operandType (IC_RESULT (ic))) > 1)
{
iCode *uic;
- if (IS_GB)
- return;
+ /* PENDING: Could do IFX */
+ if (ic->op == IFX)
+ {
+ return;
+ }
/* has only one definition */
if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
- return;
+ {
+ D (D_HLUSE, (" + Dropping as has more than one def\n"));
+ return;
+ }
/* has only one use */
if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1)
- return;
+ {
+ D (D_HLUSE, (" + Dropping as has more than one use\n"));
+ return;
+ }
/* and the usage immediately follows this iCode */
if (!(uic = hTabItemWithKey (iCodehTab,
bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
- return;
+ {
+ D (D_HLUSE, (" + Dropping as usage isn't in this block\n"));
+ return;
+ }
if (ic->next != uic)
- return;
+ {
+ D (D_HLUSE, (" + Dropping as usage doesn't follow this\n"));
+ return;
+ }
+
+ if (uic->op ==IFX)
+ {
+ return;
+ }
+
+ if (getSize (operandType (IC_RESULT (ic))) != 2 ||
+ (IC_LEFT(uic) && getSize (operandType (IC_LEFT (uic))) != 2) ||
+ (IC_RIGHT(uic) && getSize (operandType (IC_RIGHT (uic))) != 2))
+ {
+ D (D_HLUSE, (" + Dropping as the result size is not 2\n"));
+ return;
+ }
- if (ic->op == CAST && uic->op == IPUSH)
- goto hluse;
- if (ic->op == ADDRESS_OF && uic->op == IPUSH)
- goto hluse;
- if (ic->op == CALL && ic->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
- goto hluse;
+ if (IS_Z80)
+ {
+ if (ic->op == CAST && uic->op == IPUSH)
+ goto hluse;
+ if (ic->op == ADDRESS_OF && uic->op == IPUSH)
+ goto hluse;
+ if (ic->op == ADDRESS_OF && POINTER_GET (uic) && IS_ITEMP( IC_RESULT (uic)))
+ goto hluse;
+ if (ic->op == CALL && ic->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
+ goto hluse;
+ }
+ else if (IS_GB)
+ {
+ /* Case of assign a constant to offset in a static array. */
+ if (ic->op == '+' && IS_VALOP (IC_RIGHT (ic)))
+ {
+ if (uic->op == '=' && POINTER_SET (uic))
+ {
+ goto hluse;
+ }
+ else if (uic->op == IPUSH && getSize (operandType (IC_LEFT (uic))) == 2)
+ {
+ goto hluse;
+ }
+ }
+ }
+
+ D (D_HLUSE, (" + Dropping as it's a bad op\n"));
return;
hluse:
- OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_HL;
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_SCRATCH;
+}
+
+static iCode *
+packRegsForHLUse3 (iCode * lic, operand * op, eBBlock * ebp)
+{
+ int i, key;
+ symbol *sym;
+ iCode *ic, *dic;
+ bool isFirst = TRUE;
+
+ D (D_PACK_HLUSE3, ("Checking HL on %p lic key %u first def %u line %u:\n", OP_SYMBOL(op), lic->key, bitVectFirstBit(OP_DEFS(op)), lic->lineno));
+ if (D_PACK_HLUSE3)
+ piCode(lic, NULL);
+
+ if ( OP_SYMBOL(op)->accuse)
+ {
+ return NULL;
+ }
+
+ if (OP_SYMBOL(op)->remat)
+ {
+ return NULL;
+ }
+
+ /* Only defined once */
+ if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+ return NULL;
+
+ if (getSize (operandType (op)) > 2)
+ return NULL;
+
+ /* And this is the definition */
+ if (bitVectFirstBit (OP_DEFS (op)) != lic->key)
+ return NULL;
+
+ /* first check if any overlapping liverange has already been
+ assigned to DPTR */
+ if (OP_SYMBOL(op)->clashes)
+ {
+ for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ )
+ {
+ if (bitVectBitValue(OP_SYMBOL(op)->clashes,i))
+ {
+ sym = hTabItemWithKey(liveRanges,i);
+ if (sym->accuse == ACCUSE_SCRATCH)
+ {
+ return NULL;
+ }
+ }
+ }
+ }
+
+ /* Nothing else that clashes with this is using the scratch
+ register. Scan through all of the intermediate instructions and
+ see if any of them could nuke HL.
+ */
+ dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom);
+
+ for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
+ ic = hTabNextItem(iCodeSeqhTab, &key))
+ {
+ if (D_PACK_HLUSE3)
+ piCode(ic, NULL);
+ D (D_PACK_HLUSE3, ("(On %p: op: %u next: %p)\n", ic, ic->op, ic->next));
+
+ if (isFirst)
+ {
+ isFirst = FALSE;
+ if (ic->op == ADDRESS_OF)
+ continue;
+ if (POINTER_GET (ic))
+ continue;
+ if (ic->op == '=' && !POINTER_SET(ic))
+ continue;
+ }
+
+ if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic))
+ && isOperandInDirSpace (IC_RESULT (ic)))
+ return NULL;
+
+ if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic))
+ && isOperandInDirSpace (IC_LEFT (ic)))
+ return NULL;
+
+ if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic))
+ && isOperandInDirSpace (IC_RIGHT (ic)))
+ return NULL;
+
+ /* Handle the non left/right/result ones first */
+ if (ic->op == IFX)
+ continue;
+ if (ic->op == JUMPTABLE)
+ return NULL;
+
+ if (SKIP_IC2(ic))
+ continue;
+
+ if (ic->op == CAST)
+ continue;
+
+ if (ic->op == IPUSH && isOperandEqual (op, IC_LEFT (ic)))
+ continue;
+
+ if (ic->op == SEND && isOperandEqual (op, IC_LEFT (ic)))
+ continue;
+
+ if (ic->op == CALL && isOperandEqual (op, IC_RESULT (ic)))
+ continue;
+
+ if (ic->op == LEFT_OP && isOperandLiteral (IC_RIGHT (ic)))
+ continue;
+
+ if ((ic->op == '=' && !POINTER_SET(ic)) ||
+ ic->op == UNARYMINUS ||
+ ic->op == '+' ||
+ ic->op == '-' ||
+ ic->op == '>' ||
+ ic->op == '<' ||
+ ic->op == EQ_OP ||
+ 0)
+ continue;
+
+ if (ic->op == '*' && isOperandEqual (op, IC_LEFT (ic)))
+ continue;
+
+ if (POINTER_SET (ic) && isOperandEqual (op, IC_RESULT (ic)))
+ continue;
+
+ if (POINTER_GET (ic) && isOperandEqual (op, IC_LEFT (ic)))
+ continue;
+
+ if (IS_VALOP (IC_RIGHT (ic)) &&
+ (ic->op == EQ_OP ||
+ 0))
+ {
+ continue;
+ }
+
+ /* By default give up */
+ return NULL;
+ }
+
+ D (D_PACK_HLUSE3, ("Succeeded!\n"))
+
+ OP_SYMBOL (op)->accuse = ACCUSE_SCRATCH;
+ return dic;
+}
+
+static iCode *
+packRegsForIYUse (iCode * lic, operand * op, eBBlock * ebp)
+{
+ int i, key;
+ symbol *sym;
+ iCode *ic, *dic;
+ bitVect *uses;
+
+ D (D_PACK_IY, ("Checking IY on %p lic key %u first def %u line %u:\n", OP_SYMBOL(op), lic->key, bitVectFirstBit(OP_DEFS(op)), lic->lineno));
+ if (D_PACK_IY)
+ piCode(lic, NULL);
+
+ if ( OP_SYMBOL(op)->accuse)
+ {
+ return NULL;
+ }
+
+ if (OP_SYMBOL(op)->remat)
+ {
+ return NULL;
+ }
+
+ /* Only defined once */
+ if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+ return NULL;
+
+ /* And this is the definition */
+ if (bitVectFirstBit (OP_DEFS (op)) != lic->key)
+ return NULL;
+
+ /* first check if any overlapping liverange has already been
+ assigned to DPTR */
+ if (OP_SYMBOL(op)->clashes)
+ {
+ for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ )
+ {
+ if (bitVectBitValue(OP_SYMBOL(op)->clashes,i))
+ {
+ sym = hTabItemWithKey(liveRanges,i);
+ if (sym->accuse == ACCUSE_IY)
+ {
+ return NULL;
+ }
+ }
+ }
+ }
+
+ /* Only a few instructions can load into IY */
+ if (lic->op != '=')
+ {
+ return NULL;
+ }
+
+ if (getSize (operandType (op)) != 2)
+ {
+ D (D_ACCUSE2, (" + Dropping as operation has size is too big\n"));
+ return FALSE;
+ }
+
+ /* Nothing else that clashes with this is using the scratch
+ register. Scan through all of the intermediate instructions and
+ see if any of them could nuke HL.
+ */
+ dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom);
+ uses = OP_USES(op);
+
+ for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
+ ic = hTabNextItem(iCodeSeqhTab,&key))
+ {
+ if (D_PACK_IY)
+ piCode(ic, NULL);
+
+ if (ic->op == PCALL ||
+ ic->op == CALL ||
+ ic->op == JUMPTABLE
+ )
+ return NULL;
+
+ if (SKIP_IC2(ic))
+ continue;
+
+ /* Be pessamistic. */
+ if (ic->op == IFX)
+ return NULL;
+
+ D (D_PACK_IY, (" op: %u uses %u result: %d left: %d right: %d\n", ic->op, bitVectBitValue(uses, ic->key),
+ IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) ? isOperandInDirSpace(IC_RESULT(ic)) : -1,
+ IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) ? isOperandInDirSpace(IC_LEFT(ic)) : -1,
+ IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) ? isOperandInDirSpace(IC_RIGHT(ic)) : -1
+ ));
+
+ if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) &&
+ isOperandInDirSpace(IC_RESULT(ic)))
+ return NULL;
+
+ if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) &&
+ isOperandInDirSpace(IC_RIGHT(ic)))
+ return NULL;
+
+ if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) &&
+ isOperandInDirSpace(IC_LEFT(ic)))
+ return NULL;
+
+ /* Only certain rules will work against IY. Check if this iCode uses
+ this symbol. */
+ if (bitVectBitValue(uses, ic->key) != 0)
+ {
+ if (ic->op == '=' &&
+ isOperandEqual(IC_RESULT(ic), op))
+ continue;
+
+ if (ic->op == GET_VALUE_AT_ADDRESS &&
+ isOperandEqual(IC_LEFT(ic), op))
+ continue;
+
+ if (isOperandEqual(IC_RESULT(ic), IC_LEFT(ic)) == FALSE)
+ return NULL;
+
+ if (IC_RIGHT (ic) && IS_VALOP (IC_RIGHT (ic)))
+ {
+ if (ic->op == '+' ||
+ ic->op == '-')
+ {
+ /* Only works if the constant is small */
+ if (operandLitValue (IC_RIGHT (ic)) < 4)
+ continue;
+ }
+ }
+
+ return NULL;
+ }
+ else
+ {
+ /* This iCode doesn't use the sym. See if this iCode preserves IY.
+ */
+ continue;
+ }
+
+ /* By default give up */
+ return NULL;
+ }
+
+ D (D_PACK_IY, ("Succeeded IY!\n"));
+
+ OP_SYMBOL (op)->accuse = ACCUSE_IY;
+ return dic;
}
+/** Returns TRUE if this operation can use acc and if it preserves the value.
+ */
static bool
-opPreservesA (iCode * ic, iCode * uic)
+opPreservesA (iCode * uic)
{
if (uic->op == IFX)
{
return FALSE;
}
+/** Returns true if this operand preserves the value of A.
+ */
static bool
opIgnoresA (iCode * ic, iCode * uic)
{
return TRUE;
}
}
+ else if (uic->op == '=' && !POINTER_SET (uic))
+ {
+ /* If they are equal and get optimised out then things are OK. */
+ if (isOperandEqual (IC_RESULT (uic), IC_RIGHT (uic)))
+ {
+ /* Straight assign is OK. */
+ return TRUE;
+ }
+ }
return FALSE;
}
{
iCode *uic;
- D (D_ALLOC, ("packRegsForAccUse2: running on ic %p\n", ic));
+ D (D_ACCUSE2, ("packRegsForAccUse2: running on ic %p line %u\n", ic, ic->lineno));
+ if (D_ACCUSE2)
+ piCode (ic, NULL);
/* Filter out all but those 'good' commands */
if (
!POINTER_GET (ic) &&
ic->op != '+' &&
+ ic->op != '-' &&
!IS_BITWISE_OP (ic) &&
ic->op != '=' &&
ic->op != EQ_OP &&
+ ic->op != '<' &&
+ ic->op != '>' &&
ic->op != CAST &&
+ ic->op != GETHBIT &&
1)
{
D (D_ACCUSE2, (" + Dropping as not a 'good' source command\n"));
bitVectUnSetBit (uses, setBit);
/* Still contigous. */
- if (!opPreservesA (ic, next))
+ if (!opPreservesA (next))
{
D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A\n"));
return;
{
if (next->prev == NULL)
{
- if (!opPreservesA (ic, next))
+ if (!opPreservesA (next))
{
D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A #2\n"));
return;
OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
return;
}
-
- /* OLD CODE FOLLOWS */
- /* if it is a conditional branch then we definitely can
- MLH: Depends.
- */
-#if 0
- if (uic->op == IFX)
- goto accuse;
-
- /* MLH: Depends. */
- if (uic->op == JUMPTABLE)
- return;
-#endif
-
- /* if the usage is not is an assignment or an
- arithmetic / bitwise / shift operation then not.
- MLH: Pending: Invalid. Our pointer sets are always peechy.
- */
-#if 0
- if (POINTER_SET (uic) &&
- getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
- {
- printf ("e5 %u\n", getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)));
- return;
- }
-#endif
-
- printf ("1\n");
- if (uic->op != '=' &&
- !IS_ARITHMETIC_OP (uic) &&
- !IS_BITWISE_OP (uic) &&
- uic->op != LEFT_OP &&
- uic->op != RIGHT_OP)
- {
- printf ("e6\n");
- return;
- }
-
- /* if used in ^ operation then make sure right is not a
- literl */
- if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic)))
- return;
-
- /* if shift operation make sure right side is not a literal */
- if (uic->op == RIGHT_OP &&
- (isOperandLiteral (IC_RIGHT (uic)) ||
- getSize (operandType (IC_RESULT (uic))) > 1))
- return;
-
- if (uic->op == LEFT_OP &&
- (isOperandLiteral (IC_RIGHT (uic)) ||
- getSize (operandType (IC_RESULT (uic))) > 1))
- return;
-
-#if 0
- /* make sure that the result of this icode is not on the
- stack, since acc is used to compute stack offset */
- if (IS_TRUE_SYMOP (IC_RESULT (uic)) &&
- OP_SYMBOL (IC_RESULT (uic))->onStack)
- return;
-#endif
-
-#if 0
- /* if either one of them in far space then we cannot */
- if ((IS_TRUE_SYMOP (IC_LEFT (uic)) &&
- isOperandInFarSpace (IC_LEFT (uic))) ||
- (IS_TRUE_SYMOP (IC_RIGHT (uic)) &&
- isOperandInFarSpace (IC_RIGHT (uic))))
- return;
-#endif
-
- /* if the usage has only one operand then we can */
- if (IC_LEFT (uic) == NULL ||
- IC_RIGHT (uic) == NULL)
- goto accuse;
-
- /* make sure this is on the left side if not
- a '+' since '+' is commutative */
- if (ic->op != '+' &&
- IC_LEFT (uic)->key != IC_RESULT (ic)->key)
- return;
-
- /* if one of them is a literal then we can */
- if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) ||
- (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
- {
- goto accuse;
- return;
- }
-
-/** This is confusing :) Guess for now */
- if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
- (IS_ITEMP (IC_RIGHT (uic)) ||
- (IS_TRUE_SYMOP (IC_RIGHT (uic)))))
- goto accuse;
-
- if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
- (IS_ITEMP (IC_LEFT (uic)) ||
- (IS_TRUE_SYMOP (IC_LEFT (uic)))))
- goto accuse;
- return;
-accuse:
- printf ("acc ok!\n");
- OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
}
/** Does some transformations to reduce register pressure.
packRegsForSupport (ic, ebp);
#endif
+ /* some cases the redundant moves can
+ can be eliminated for return statements */
+ if (ic->op == RETURN || ic->op == SEND)
+ {
+ packRegsForOneuse (ic, IC_LEFT (ic), ebp);
+ }
+
/* if pointer set & left has a size more than
one and right is not in far space */
if (!DISABLE_PACK_ONE_USE &&
if (!DISABLE_PACK_HL && IS_ITEMP (IC_RESULT (ic)))
{
- packRegsForHLUse (ic);
+ if (IS_GB)
+ packRegsForHLUse (ic);
+ else
+ packRegsForHLUse3 (ic, IC_RESULT (ic), ebp);
+ }
+
+ if (!DISABLE_PACK_IY && IS_ITEMP (IC_RESULT (ic)) && IS_Z80)
+ {
+ packRegsForIYUse (ic, IC_RESULT (ic), ebp);
}
if (!DISABLE_PACK_ACC && IS_ITEMP (IC_RESULT (ic)) &&
}
}
+/** Joins together two byte constant pushes into one word push.
+ */
+static iCode *
+joinPushes (iCode *lic)
+{
+ iCode *ic, *uic;
+
+ for (ic = lic; ic; ic = ic->next)
+ {
+ int first, second;
+ value *val;
+
+ uic = ic->next;
+
+ /* Anything past this? */
+ if (uic == NULL)
+ {
+ continue;
+ }
+ /* This and the next pushes? */
+ if (ic->op != IPUSH || uic->op != IPUSH)
+ {
+ continue;
+ }
+ /* Both literals? */
+ if ( !IS_OP_LITERAL (IC_LEFT (ic)) || !IS_OP_LITERAL (IC_LEFT (uic)))
+ {
+ continue;
+ }
+ /* Both characters? */
+ if ( getSize (operandType (IC_LEFT (ic))) != 1 || getSize (operandType (IC_LEFT (uic))) != 1)
+ {
+ continue;
+ }
+ /* Pull out the values, make a new type, and create the new iCode for it.
+ */
+ first = (int)operandLitValue ( IC_LEFT (ic));
+ second = (int)operandLitValue ( IC_LEFT (uic));
+
+ sprintf (buffer, "%u", ((first << 8) | (second & 0xFF)) & 0xFFFFU);
+ val = constVal (buffer);
+ SPEC_NOUN (val->type) = V_INT;
+ IC_LEFT (ic)->operand.valOperand = val;
+
+ /* Now remove the second one from the list. */
+ ic->next = uic->next;
+ if (uic->next)
+ {
+ /* Patch up the reverse link */
+ uic->next->prev = ic;
+ }
+ }
+
+ return lic;
+}
+
/*-----------------------------------------------------------------*/
/* assignRegisters - assigns registers to each live range as need */
/*-----------------------------------------------------------------*/
D (D_ALLOC, ("\n-> z80_assignRegisters: entered.\n"));
setToNull ((void *) &_G.funcrUsed);
+ setToNull ((void *) &_G.totRegAssigned);
_G.stackExtend = _G.dataExtend = 0;
if (IS_GB)
/* and serially allocate registers */
serialRegAssign (ebbs, count);
+ freeAllRegs ();
+ fillGaps();
+
/* if stack was extended then tell the user */
if (_G.stackExtend)
{
/* now get back the chain */
ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
+ ic = joinPushes (ic);
+
/* redo that offsets for stacked automatic variables */
redoStackOffsets ();