hardware. It allocates based on usage and how long the varible
lives into registers or temporary memory on the stack.
- On the Z80 hl, ix, iy, and a are reserved for the code generator,
- leaving bc and de for allocation. The extra register pressure
+ On the Z80 hl and ix and a are reserved for the code generator,
+ leaving bc and de for allocation. iy is unusable due to currently
+ as it's only adressable as a pair. The extra register pressure
from reserving hl is made up for by how much easier the sub
operations become. You could swap hl for iy if the undocumented
iyl/iyh instructions are available.
software-hoarding!
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include "SDCCglobl.h"
-#include "SDCCast.h"
-#include "SDCCmem.h"
-#include "SDCCy.h"
-#include "SDCChasht.h"
-#include "SDCCbitv.h"
-#include "SDCCset.h"
-#include "SDCCicode.h"
-#include "SDCClabel.h"
-#include "SDCCBBlock.h"
-#include "SDCCloop.h"
-#include "SDCCcse.h"
-#include "SDCCcflow.h"
-#include "SDCCdflow.h"
-#include "SDCClrange.h"
-#include "ralloc.h"
+#include "z80.h"
+
+enum {
+ DISABLE_PACK_ACC = 0,
+ DISABLE_PACK_ASSIGN = 0,
+ LIMITED_PACK_ACC = 1
+};
+
+#define D_ALLOC 1
+
+#if 0
+#define D(_a, _s) if (_a) { printf _s; fflush(stdout); }
+#else
+#define D(_a, _s)
+#endif
/*-----------------------------------------------------------------*/
/* At this point we start getting processor specific although */
short blockSpil = 0;
int slocNum = 0 ;
extern void genZ80Code(iCode *);
-int ptrRegReq = 0; /* one byte pointer register required */
bitVect *funcrUsed = NULL; /* registers used in a function */
int stackExtend = 0;
int dataExtend = 0;
+int _nRegs;
/** Set to help debug register pressure related problems */
#define DEBUG_FAKE_EXTRA_REGS 0
-regs regsZ80[] =
-{
+static regs _gbz80_regs[] = {
+ { REG_GPR, C_IDX , "c", 1 },
+ { REG_GPR, B_IDX , "b", 1 },
+ { REG_CND, CND_IDX, "c", 1}
+};
+
+static regs _z80_regs[] = {
{ REG_GPR, C_IDX , "c", 1 },
{ REG_GPR, B_IDX , "b", 1 },
{ REG_GPR, E_IDX , "e", 1 },
{ REG_CND, CND_IDX, "c", 1}
};
-/** Number of usable registers (all but C) */
-#define MAX_REGS ((sizeof(regsZ80)/sizeof(regs))-1)
+regs *regsZ80;
-int nRegs = MAX_REGS;
+/** Number of usable registers (all but C) */
+#define Z80_MAX_REGS ((sizeof(_z80_regs)/sizeof(_z80_regs[0]))-1)
+#define GBZ80_MAX_REGS ((sizeof(_gbz80_regs)/sizeof(_gbz80_regs[0]))-1)
-void spillThis (symbol *);
+static void spillThis (symbol *);
/** Allocates register of given type.
'type' is not used on the z80 version. It was used to select
@return Pointer to the newly allocated register.
*/
-regs *allocReg (short type)
+static regs *allocReg (short type)
{
int i;
- for ( i = 0 ; i < nRegs ; i++ ) {
+ for ( i = 0 ; i < _nRegs ; i++ ) {
/* For now we allocate from any free */
if (regsZ80[i].isFree ) {
regsZ80[i].isFree = 0;
if (currFunc)
currFunc->regsUsed =
bitVectSetBit(currFunc->regsUsed,i);
+ D(D_ALLOC, ("allocReg: alloced %zr\n", ®sZ80[i]));
return ®sZ80[i];
}
}
+ D(D_ALLOC, ("allocReg: No free.\n"));
return NULL;
}
{
int i;
- for (i=0;i < nRegs;i++)
+ for (i=0;i < _nRegs;i++)
if (regsZ80[i].rIdx == idx)
return ®sZ80[i];
-
+
werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
"regWithIdx not found");
exit(1);
/** Frees a register.
*/
-void freeReg (regs *reg)
+static void freeReg (regs *reg)
{
- assert(!reg->isFree);
+ wassert(!reg->isFree);
reg->isFree = 1;
+ D(D_ALLOC, ("freeReg: freed %zr\n", reg));
}
/** Returns number of free registers.
*/
-int nFreeRegs (int type)
+static int nFreeRegs (int type)
{
int i;
int nfr=0;
- for (i = 0 ; i < nRegs; i++ ) {
+ for (i = 0 ; i < _nRegs; i++ ) {
/* For now only one reg type */
if (regsZ80[i].isFree)
nfr++;
/** Free registers with type.
*/
-int nfreeRegsType (int type)
+static int nfreeRegsType (int type)
{
int nfr ;
if (type == REG_PTR) {
}
+#if 0
/*-----------------------------------------------------------------*/
/* allDefsOutOfRange - all definitions are out of a range */
/*-----------------------------------------------------------------*/
-bool allDefsOutOfRange (bitVect *defs,int fseq, int toseq)
+static bool allDefsOutOfRange (bitVect *defs,int fseq, int toseq)
{
int i ;
return TRUE;
}
+#endif
/*-----------------------------------------------------------------*/
/* computeSpillable - given a point find the spillable live ranges */
/*-----------------------------------------------------------------*/
-bitVect *computeSpillable (iCode *ic)
+static bitVect *computeSpillable (iCode *ic)
{
bitVect *spillable ;
/*-----------------------------------------------------------------*/
/* noSpilLoc - return true if a variable has no spil location */
/*-----------------------------------------------------------------*/
-int noSpilLoc (symbol *sym, eBBlock *ebp,iCode *ic)
+static int noSpilLoc (symbol *sym, eBBlock *ebp,iCode *ic)
{
return (sym->usl.spillLoc ? 0 : 1);
}
/*-----------------------------------------------------------------*/
/* hasSpilLoc - will return 1 if the symbol has spil location */
/*-----------------------------------------------------------------*/
-int hasSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic)
+static int hasSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic)
{
return (sym->usl.spillLoc ? 1 : 0);
}
-/*-----------------------------------------------------------------*/
-/* directSpilLoc - will return 1 if the splilocation is in direct */
-/*-----------------------------------------------------------------*/
-int directSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic)
-{
- /* No such thing as direct space */
- return 0;
-}
-
-/*-----------------------------------------------------------------*/
-/* hasSpilLocnoUptr - will return 1 if the symbol has spil location*/
-/* but is not used as a pointer */
-/*-----------------------------------------------------------------*/
-int hasSpilLocnoUptr (symbol *sym, eBBlock *ebp, iCode *ic)
-{
-#if 0
- return sym->usl.spillLoc ? 1:0;
-#else
- return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0);
-#endif
-}
-
/** Will return 1 if the remat flag is set.
A symbol is rematerialisable if it doesnt need to be allocated
into registers at creation as it can be re-created at any time -
i.e. it's constant in some way.
*/
-int rematable (symbol *sym, eBBlock *ebp, iCode *ic)
+static int rematable (symbol *sym, eBBlock *ebp, iCode *ic)
{
return sym->remat;
}
-/*-----------------------------------------------------------------*/
-/* 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));
-/* return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs)); */
-}
-
-/*-----------------------------------------------------------------*/
-/* notUsedInRemaining - not used or defined in remain of the block */
-/*-----------------------------------------------------------------*/
-int notUsedInRemaining (symbol *sym, eBBlock *ebp, iCode *ic)
-{
- return ((usedInRemaining (operandFromSymbol(sym),ic) ? 0 : 1) &&
- allDefsOutOfRange (sym->defs,ic->seq,ebp->lSeq));
-}
-
/*-----------------------------------------------------------------*/
/* allLRs - return true for all */
/*-----------------------------------------------------------------*/
-int allLRs (symbol *sym, eBBlock *ebp, iCode *ic)
+static int allLRs (symbol *sym, eBBlock *ebp, iCode *ic)
{
return 1;
}
/*-----------------------------------------------------------------*/
/* noOverLap - will iterate through the list looking for over lap */
/*-----------------------------------------------------------------*/
-int noOverLap (set *itmpStack, symbol *fsym)
+static int noOverLap (set *itmpStack, symbol *fsym)
{
symbol *sym;
-
for (sym = setFirstItem(itmpStack); sym;
sym = setNextItem(itmpStack)) {
if (sym->liveTo > fsym->liveFrom )
return 0;
}
-
return 1;
}
return 0;
}
-/*-----------------------------------------------------------------*/
-/* spillLRWithPtrReg :- will spil those live ranges which use PTR */
-/*-----------------------------------------------------------------*/
-void spillLRWithPtrReg (symbol *forSym)
-{
- /* Always just return */
-}
-
/*-----------------------------------------------------------------*/
/* createStackSpil - create a location on the stack to spil */
/*-----------------------------------------------------------------*/
{
symbol *sloc= NULL;
+ D(D_ALLOC, ("createStackSpil: for sym %zs\n", sym));
+
/* first go try and find a free one that is already
existing on the stack */
if (applyToSet(stackSpil,isFree,&sloc, sym)) {
sym->stackSpil= 1;
sloc->isFree = 0;
addSetHead(&sloc->usl.itmpStack,sym);
+ D(D_ALLOC, ("createStackSpil: found existing\n"));
return sym;
}
/* add it to the set of itempStack set
of the spill location */
addSetHead(&sloc->usl.itmpStack,sym);
+
+ D(D_ALLOC, ("createStackSpil: created new\n"));
return sym;
}
/*-----------------------------------------------------------------*/
/* spillThis - spils a specific operand */
/*-----------------------------------------------------------------*/
-void spillThis (symbol *sym)
+static void spillThis (symbol *sym)
{
int i;
+
+ D(D_ALLOC, ("spillThis: spilling %zs\n", sym));
+
/* if this is rematerializable or has a spillLocation
we are okay, else we need to create a spillLocation
for it */
if (!(sym->remat || sym->usl.spillLoc))
createStackSpil (sym);
-
/* mark it has spilt & put it in the spilt set */
sym->isspilt = 1;
bitVectUnSetBit(regAssigned,sym->key);
- for (i = 0 ; i < sym->nRegs ; i++)
-
+ for (i = 0 ; i < sym->nRegs ; i++) {
if (sym->regs[i]) {
freeReg(sym->regs[i]);
sym->regs[i] = NULL;
}
+ }
/* if spilt on stack then free up r0 & r1
if they could have been assigned to some
LIVE ranges */
- if (!ptrRegReq && isSpiltOnStack(sym)) {
- ptrRegReq++ ;
- spillLRWithPtrReg(sym);
- }
-
if (sym->usl.spillLoc && !sym->remat)
sym->usl.spillLoc->allocreq = 1;
return;
set *selectS ;
symbol *sym;
+ D(D_ALLOC, ("selectSpil: finding spill for ic %zi\n", ic));
/* get the spillable live ranges */
lrcs = computeSpillable (ic);
/* get all live ranges that are rematerizable */
if ((selectS = liveRangesWith(lrcs,rematable,ebp,ic))) {
-
+ D(D_ALLOC, ("selectSpil: using remat.\n"));
/* return the least used of these */
return leastUsedLR(selectS);
}
/* find live ranges with spillocation */
if ((selectS = liveRangesWith(lrcs,hasSpilLoc,ebp,ic))) {
-
+ D(D_ALLOC, ("selectSpil: using with spill.\n"));
sym = leastUsedLR(selectS);
sym->usl.spillLoc->allocreq = 1;
return sym;
location on the stack , for which one? the least
used ofcourse */
if ((selectS = liveRangesWith(lrcs,noSpilLoc,ebp,ic))) {
+ D(D_ALLOC, ("selectSpil: creating new spill.\n"));
/* return a created spil location */
sym = createStackSpil(leastUsedLR(selectS));
sym->usl.spillLoc->allocreq = 1;
/* this is an extreme situation we will spill
this one : happens very rarely but it does happen */
+ D(D_ALLOC, ("selectSpil: using spillThis.\n"));
spillThis ( forSym );
return forSym;
symbol *ssym;
int i ;
+ D(D_ALLOC, ("spilSomething: spilling on ic %zi\n", ic));
+
/* get something we can spil */
ssym = selectSpil(ic,ebp,forSym);
for (i = 0 ; i < ssym->nRegs ;i++ )
if (ssym->regs[i])
freeReg(ssym->regs[i]);
-
#if 0
/* if spilt on stack then free up r0 & r1
if they could have been assigned to as gprs */
}
#endif
+ D(D_ALLOC, ("spilSomething: done.\n"));
+
if (ssym == forSym )
return FALSE ;
else
{
regs *reg;
+ D(D_ALLOC, ("getRegGpr: on ic %zi\n"));
tryAgain:
/* try for gpr type */
- if ((reg = allocReg(REG_GPR)))
+ if ((reg = allocReg(REG_GPR))) {
+ D(D_ALLOC, ("getRegGpr: got a reg.\n"));
return reg;
-
- if (!ptrRegReq)
- if ((reg = allocReg(REG_PTR)))
- return reg ;
+ }
/* we have to spil */
- if (!spilSomething (ic,ebp,sym))
+ if (!spilSomething (ic,ebp,sym)) {
+ D(D_ALLOC, ("getRegGpr: have to spill.\n"));
return NULL ;
+ }
/* this looks like an infinite loop but
in really selectSpil will abort */
/** Check the live to and if they have registers & are not spilt then
free up the registers
*/
-void deassignLRs (iCode *ic, eBBlock *ebp)
+static void deassignLRs (iCode *ic, eBBlock *ebp)
{
symbol *sym;
int k;
!OP_SYMBOL(IC_LEFT(ic->prev))->isspilt)
psym = OP_SYMBOL(IC_LEFT(ic->prev));
+ D(D_ALLOC, ("deassignLRs: in loop on sym %zs", sym));
+
if (sym->nRegs) {
int i = 0;
((nfreeRegsType(result->regType) +
sym->nRegs) >= result->nRegs)
) {
-
- for (i = 0 ; i < max(sym->nRegs,result->nRegs) ; i++)
+ for (i = 0 ; i < max(sym->nRegs,result->nRegs) ; i++) {
if (i < sym->nRegs )
result->regs[i] = sym->regs[i] ;
else
result->regs[i] = getRegGpr (ic,ebp,result);
+
+ /* if the allocation falied which means
+ this was spilt then break */
+ if (!result->regs[i]) {
+ wassert(0);
+ assert(0);
+ break;
+ }
+ }
regAssigned = bitVectSetBit(regAssigned,result->key);
- }
+ }
/* free the remaining */
for (; i < sym->nRegs ; i++) {
freeReg(sym->regs[i]);
} else
freeReg(sym->regs[i]);
+ // sym->regs[i] = NULL;
}
}
}
/** Reassign this to registers.
*/
-void reassignLR (operand *op)
+static void reassignLR (operand *op)
{
symbol *sym = OP_SYMBOL(op);
int i;
+ D(D_ALLOC, ("reassingLR: on sym %zs\n", sym));
+
/* not spilt any more */
sym->isspilt = sym->blockSpil = sym->remainSpil = 0;
bitVectUnSetBit(spiltSet,sym->key);
/** Determines if allocating will cause a spill.
*/
-int willCauseSpill ( int nr, int rt)
+static int willCauseSpill ( int nr, int rt)
{
/* first check if there are any avlb registers
of te type required */
*/
static void positionRegs (symbol *result, symbol *opsym, int lineno)
{
- int count = min(result->nRegs,opsym->nRegs);
- int i , j = 0, shared = 0;
+ int count = min(result->nRegs,opsym->nRegs);
+ int i , j = 0, shared = 0;
- /* if the result has been spilt then cannot share */
- if (opsym->isspilt)
- return ;
+ D(D_ALLOC, ("positionRegs: on result %zs opsum %zs line %u\n", result, opsym, lineno));
+
+ /* if the result has been spilt then cannot share */
+ if (opsym->isspilt)
+ return ;
again:
- shared = 0;
- /* first make sure that they actually share */
- for ( i = 0 ; i < count; i++ ) {
- for (j = 0 ; j < count ; j++ ) {
- if (result->regs[i] == opsym->regs[j] && i !=j) {
- shared = 1;
- goto xchgPositions;
- }
- }
+ shared = 0;
+ /* first make sure that they actually share */
+ for ( i = 0 ; i < count; i++ ) {
+ for (j = 0 ; j < count ; j++ ) {
+ if (result->regs[i] == opsym->regs[j] && i !=j) {
+ shared = 1;
+ goto xchgPositions;
+ }
}
+ }
xchgPositions:
- if (shared) {
- regs *tmp = result->regs[i];
- result->regs[i] = result->regs[j];
- result->regs[j] = tmp;
- goto again;
- }
+ if (shared) {
+ regs *tmp = result->regs[i];
+ result->regs[i] = result->regs[j];
+ result->regs[j] = tmp;
+ goto again;
+ }
}
/** Try to allocate a pair of registers to the symbol.
bool tryAllocatingRegPair(symbol *sym)
{
int i;
- assert(sym->nRegs == 2);
- for ( i = 0 ; i < nRegs ; i+=2 ) {
+ wassert(sym->nRegs == 2);
+ for ( i = 0 ; i < _nRegs ; i+=2 ) {
if ((regsZ80[i].isFree)&&(regsZ80[i+1].isFree)) {
regsZ80[i].isFree = 0;
sym->regs[0] = ®sZ80[i];
currFunc->regsUsed =
bitVectSetBit(currFunc->regsUsed,i+1);
}
+ D(D_ALLOC, ("tryAllocRegPair: succeded for sym %zs\n", sym));
return TRUE;
}
}
+ D(D_ALLOC, ("tryAllocRegPair: failed on sym %zs\n", sym));
return FALSE;
}
This is the main register allocation function. It is called after
packing.
*/
-void serialRegAssign (eBBlock **ebbs, int count)
+static void serialRegAssign (eBBlock **ebbs, int count)
{
int i;
/* if this is an ipop that means some live
range will have to be assigned again */
- if (ic->op == IPOP)
+ if (ic->op == IPOP) {
+ wassert(0);
reassignLR (IC_LEFT(ic));
+ }
/* if result is present && is a true symbol */
if (IC_RESULT(ic) && ic->op != IFX &&
int willCS ;
int j;
+ D(D_ALLOC, ("serialRegAssign: in loop on result %zs\n", sym));
+
/* if it does not need or is spilt
or is already assigned to registers
or will not live beyond this instructions */
if (!sym->nRegs ||
sym->isspilt ||
bitVectBitValue(regAssigned,sym->key) ||
- sym->liveTo <= ic->seq)
+ sym->liveTo <= ic->seq) {
+ D(D_ALLOC, ("serialRegAssign: wont live long enough.\n"));
continue ;
+ }
/* if some liverange has been spilt at the block level
and this one live beyond this block then spil this
to be safe */
if (blockSpil && sym->liveTo > ebbs[i]->lSeq) {
+ D(D_ALLOC, ("serialRegAssign: \"spilling to be safe.\"\n"));
spillThis (sym);
continue ;
}
if ( sym->remat ||
(willCS && bitVectIsZero(spillable) ) ) {
+ D(D_ALLOC, ("serialRegAssign: \"remat spill\"\n"));
spillThis (sym) ;
continue ;
/* Special case: Try to fit into a reg pair if
available */
+ D(D_ALLOC, ("serialRegAssign: actually allocing regs!\n"));
if ((sym->nRegs == 2)&&tryAllocatingRegPair(sym)) {
}
else {
if (sym->isspilt || !sym->nRegs)
return NULL;
- rumask = newBitVect(nRegs);
+ rumask = newBitVect(_nRegs);
for (j = 0; j < sym->nRegs; j++) {
- rumask = bitVectSetBit(rumask,
- sym->regs[j]->rIdx);
+ rumask = bitVectSetBit(rumask, sym->regs[j]->rIdx);
}
return rumask;
*/
bitVect *regsUsedIniCode (iCode *ic)
{
- bitVect *rmask = newBitVect(nRegs);
+ bitVect *rmask = newBitVect(_nRegs);
/* do the special cases first */
if (ic->op == IFX ) {
/** For each instruction will determine the regsUsed.
*/
-void createRegMask (eBBlock **ebbs, int count)
+static void createRegMask (eBBlock **ebbs, int count)
{
int i;
/* now create the register mask for those
registers that are in use : this is a
super set of ic->rUsed */
- ic->rMask = newBitVect(nRegs+1);
+ ic->rMask = newBitVect(_nRegs+1);
/* for all live Ranges alive at this point */
for (j = 1; j < ic->rlive->size; j++ ) {
/*-----------------------------------------------------------------*/
/* regTypeNum - computes the type & number of registers required */
/*-----------------------------------------------------------------*/
-void regTypeNum ()
+static void regTypeNum (void)
{
symbol *sym;
int k;
if ((sym->liveTo - sym->liveFrom) == 0)
continue ;
+ D(D_ALLOC, ("regTypeNum: loop on sym %zs\n", sym));
+
/* if the live range is a temporary */
if (sym->isitmp) {
getSize(sym->type = aggrToPtr(sym->type,FALSE)) :
getSize(sym->type));
+ D(D_ALLOC, ("regTypeNum: setup to assign regs sym %zs\n", sym));
+
if (sym->nRegs > 4) {
fprintf(stderr,"allocated more than 4 or 0 registers for type ");
printTypeChain(sym->type,stderr);fprintf(stderr,"\n");
/** Mark all registers as free.
*/
-void freeAllRegs()
+static void freeAllRegs()
{
int i;
- for (i=0;i< nRegs;i++ )
+ D(D_ALLOC, ("freeAllRegs: running.\n"));
+
+ for (i=0;i< _nRegs;i++ )
regsZ80[i].isFree = 1;
}
/** Register reduction for assignment.
*/
-int packRegsForAssign (iCode *ic,eBBlock *ebp)
+static int packRegsForAssign (iCode *ic,eBBlock *ebp)
{
iCode *dic, *sic;
+
+ D(D_ALLOC, ("packRegsForAssing: running on ic %zi\n", ic));
if (
- !IS_TRUE_SYMOP(IC_RESULT(ic)) ||
- !IS_ITEMP(IC_RIGHT(ic)) ||
+ /* !IS_TRUE_SYMOP(IC_RESULT(ic)) ||*/
+ !IS_ITEMP(IC_RIGHT(ic)) ||
OP_LIVETO(IC_RIGHT(ic)) > ic->seq ||
OP_SYMBOL(IC_RIGHT(ic))->isind)
return 0;
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) &&
}
if (SKIP_IC2(dic))
- continue;
+ continue;
-#if 0
if (IS_SYMOP(IC_RESULT(dic)) &&
IC_RESULT(dic)->key == IC_RIGHT(ic)->key) {
- if (POINTER_SET(dic))
- dic = NULL;
break;
}
dic = NULL;
break;
}
+#if 0
if (POINTER_SET(dic) &&
IC_RESULT(dic)->key == IC_RESULT(ic)->key ) {
dic = NULL ;
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))) ||
/*-----------------------------------------------------------------*/
/* packRegsForSupport :- reduce some registers for support calls */
/*-----------------------------------------------------------------*/
-int packRegsForSupport (iCode *ic, eBBlock *ebp)
+static int packRegsForSupport (iCode *ic, eBBlock *ebp)
{
int change = 0 ;
/* for the left & right operand :- look to see if the
left was assigned a true symbol in far space in that
case replace them */
+ D(D_ALLOC, ("packRegsForSupport: running on ic %zi\n", ic));
+
if (IS_ITEMP(IC_LEFT(ic)) &&
OP_SYMBOL(IC_LEFT(ic))->liveTo <= ic->seq) {
iCode *dic = findAssignToSym(IC_LEFT(ic),ic);
bitVect *uses ;
iCode *dic, *sic;
+ D(D_ALLOC, ("packRegsForOneUse: running on ic %zi\n", ic));
+
/* if returning a literal then do nothing */
if (!IS_SYMOP(op))
return NULL;
return FALSE;
}
+/** Optimisations:
+ Certian assignments involving pointers can be temporarly stored
+ in HL. Esp.
+genAssign
+ ld iy,#_Blah
+ ld bc,(iy)
+genAssign (ptr)
+ ld hl,bc
+ ld iy,#_Blah2
+ ld (iy),(hl)
+*/
+
/** Pack registers for acc use.
When the result of this operation is small and short lived it may
be able to be stored in the accumelator.
*/
-void packRegsForAccUse (iCode *ic)
+static void packRegsForAccUse (iCode *ic)
{
iCode *uic;
OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
}
+bool opPreservesA(iCode *ic, iCode *uic)
+{
+ /* if it is a conditional branch then we definitely can */
+ if (uic->op == IFX )
+ return FALSE;
+
+ if ( uic->op == JUMPTABLE )
+ return FALSE;
+
+ /* if the usage has only one operand then we can */
+ /* PENDING: check */
+ if (IC_LEFT(uic) == NULL ||
+ IC_RIGHT(uic) == NULL)
+ return FALSE;
+
+ /* PENDING: check this rule */
+ if (getSize(operandType(IC_RESULT(uic))) > 1) {
+ return FALSE;
+ }
+
+ /*
+ Bad:
+ !IS_ARITHMETIC_OP(uic) (sub requires A)
+ */
+ if (
+ uic->op != '+' &&
+ !IS_BITWISE_OP(uic) &&
+ uic->op != '=' &&
+ uic->op != EQ_OP &&
+ !POINTER_GET(uic) &&
+ /*
+ uic->op != LEFT_OP &&
+ uic->op != RIGHT_OP &&*/
+ 1
+ ) {
+ return FALSE;
+ }
+
+ /* PENDING */
+ if (!IC_LEFT(uic) || !IC_RESULT(ic))
+ return FALSE;
+
+ /** 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)))))
+ return TRUE;
+
+ if (IC_RIGHT(uic)->key == IC_RESULT(ic)->key &&
+ (IS_ITEMP(IC_LEFT(uic)) ||
+ (IS_TRUE_SYMOP(IC_LEFT(uic)))))
+ return TRUE;
+
+ return FALSE;
+}
+
+/** Pack registers for acc use.
+ When the result of this operation is small and short lived it may
+ be able to be stored in the accumelator.
+
+ Note that the 'A preserving' list is currently emperical :)e
+ */
+static void packRegsForAccUse2(iCode *ic)
+{
+ iCode *uic;
+
+ D(D_ALLOC, ("packRegsForAccUse2: running on ic %zi\n", ic));
+
+ /* Filter out all but those 'good' commands */
+ if (
+ !POINTER_GET(ic) &&
+ ic->op != '+' &&
+ !IS_BITWISE_OP(ic) &&
+ ic->op != '=' &&
+ ic->op != EQ_OP &&
+ ic->op != CAST &&
+ 1)
+ return;
+
+ /* if + or - then it has to be one byte result.
+ MLH: Ok.
+ */
+ if ((ic->op == '+' || ic->op == '-')
+ && getSize(operandType(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* if shift operation make sure right side is not a literal.
+ MLH: depends.
+ */
+#if 0
+ if (ic->op == RIGHT_OP &&
+ (isOperandLiteral(IC_RIGHT(ic)) ||
+ getSize(operandType(IC_RESULT(ic))) > 1))
+ return ;
+
+ if (ic->op == LEFT_OP &&
+ ( isOperandLiteral(IC_RIGHT(ic)) ||
+ getSize(operandType(IC_RESULT(ic))) > 1))
+ return ;
+#endif
+
+ /* has only one definition */
+ if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1) {
+ return;
+ }
+
+ /* Right. We may be able to propagate it through if:
+ For each in the chain of uses the intermediate is OK.
+ */
+ /* Get next with 'uses result' bit on
+ If this->next == next
+ Validate use of next
+ If OK, increase count
+ */
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey(iCodehTab,
+ bitVectFirstBit(OP_USES(IC_RESULT(ic)))))) {
+ return;
+ }
+
+ {
+ /* Create a copy of the OP_USES bit vect */
+ bitVect *uses = bitVectCopy(OP_USES(IC_RESULT(ic)));
+ int setBit;
+ iCode *scan = ic, *next;
+
+ do {
+ setBit = bitVectFirstBit(uses);
+ next = hTabItemWithKey(iCodehTab, setBit);
+ if (scan->next == next) {
+ bitVectUnSetBit(uses, setBit);
+ /* Still contigous. */
+ if (!opPreservesA(ic, next)) {
+ return;
+ }
+ scan = next;
+ }
+ else {
+ return;
+ }
+ } while (!bitVectIsZero(uses));
+ OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+ 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)))) {
+ OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+ 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 = 1;
+}
+
/** Does some transformations to reduce register pressure.
*/
-void packRegisters (eBBlock *ebp)
+static void packRegisters (eBBlock *ebp)
{
iCode *ic ;
int change = 0 ;
+
+ D(D_ALLOC, ("packRegisters: entered.\n"));
- while (1) {
+ while (1 && !DISABLE_PACK_ASSIGN) {
change = 0;
/* look for assignments of the form */
/* iTempNN = TRueSym (someoperation) SomeOperand */
/* Safe: address of a true sym is always constant. */
/* if this is an itemp & result of a address of a true sym
then mark this as rematerialisable */
+
+ D(D_ALLOC, ("packRegisters: looping on ic %zi\n", ic));
+
if (ic->op == ADDRESS_OF &&
IS_ITEMP(IC_RESULT(ic)) &&
IS_TRUE_SYMOP(IC_LEFT(ic)) &&
!options.model)
packRegsForOneuse (ic,IC_LEFT(ic),ebp);
#endif
-
-#if 0
/* if pointer set & left has a size more than
one and right is not in far space */
if (POINTER_SET(ic) &&
- !isOperandInFarSpace(IC_RIGHT(ic)) &&
+ /* MLH: no such thing.
+ !isOperandInFarSpace(IC_RIGHT(ic)) && */
!OP_SYMBOL(IC_RESULT(ic))->remat &&
!IS_OP_RUONLY(IC_RIGHT(ic)) &&
getSize(aggrToPtr(operandType(IC_RESULT(ic)),FALSE)) > 1 )
-
+
packRegsForOneuse (ic,IC_RESULT(ic),ebp);
-#endif
-
-#if 0
+
/* if pointer get */
if (POINTER_GET(ic) &&
- !isOperandInFarSpace(IC_RESULT(ic))&&
+ /* MLH: dont have far space
+ !isOperandInFarSpace(IC_RESULT(ic))&& */
!OP_SYMBOL(IC_LEFT(ic))->remat &&
!IS_OP_RUONLY(IC_RESULT(ic)) &&
getSize(aggrToPtr(operandType(IC_LEFT(ic)),FALSE)) > 1 )
-
packRegsForOneuse (ic,IC_LEFT(ic),ebp);
-#endif
-
/* pack registers for accumulator use, when the result of an
arithmetic or bit wise operation has only one use, that use is
immediately following the defintion and the using iCode has
only one operand or has two operands but one is literal & the
result of that operation is not on stack then we can leave the
result of this operation in acc:b combination */
+#if 0
if ((IS_ARITHMETIC_OP(ic)
- || IS_BITWISE_OP(ic)
+ || IS_BITWISE_OP(ic)
|| ic->op == LEFT_OP || ic->op == RIGHT_OP
) &&
IS_ITEMP(IC_RESULT(ic)) &&
getSize(operandType(IC_RESULT(ic))) <= 2)
packRegsForAccUse (ic);
+#else
+ if (!DISABLE_PACK_ACC && IS_ITEMP(IC_RESULT(ic)) &&
+ getSize(operandType(IC_RESULT(ic))) == 1)
+ packRegsForAccUse2(ic);
+#endif
}
}
iCode *ic;
int i ;
+ D(D_ALLOC, ("\n-> z80_assignRegisters: entered.\n"));
+
setToNull((void *)&funcrUsed);
- ptrRegReq = stackExtend = dataExtend = 0;
- /* if not register extentions then reduce number
- of registers */
- nRegs = MAX_REGS;
+ stackExtend = dataExtend = 0;
+
+ if (IS_GB) {
+ /* DE is required for the code gen. */
+ _nRegs = GBZ80_MAX_REGS;
+ regsZ80 = _gbz80_regs;
+ }
+ else {
+ _nRegs = Z80_MAX_REGS;
+ regsZ80 = _z80_regs;
+ }
/* change assignments this will remove some
live ranges reducing some register pressure */