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.
#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 */
/* some routines are non-processor specific & can be reused when */
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;
#define DEBUG_FAKE_EXTRA_REGS 0
static regs _gbz80_regs[] = {
- { REG_GPR, C_IDX , "b", 1 },
- { REG_GPR, B_IDX , "c", 1 },
+ { REG_GPR, C_IDX , "c", 1 },
+ { REG_GPR, B_IDX , "b", 1 },
{ REG_CND, CND_IDX, "c", 1}
};
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;
}
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);
*/
static void freeReg (regs *reg)
{
- assert(!reg->isFree);
+ wassert(!reg->isFree);
reg->isFree = 1;
+ D(D_ALLOC, ("freeReg: freed %zr\n", reg));
}
{
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 */
-/*-----------------------------------------------------------------*/
-static 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;
}
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 */
!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;
}
}
}
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);
*/
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);
+ wassert(sym->nRegs == 2);
for ( i = 0 ; i < _nRegs ; i+=2 ) {
if ((regsZ80[i].isFree)&&(regsZ80[i+1].isFree)) {
regsZ80[i].isFree = 0;
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;
}
/* 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 {
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;
/*-----------------------------------------------------------------*/
/* regTypeNum - computes the type & number of registers required */
/*-----------------------------------------------------------------*/
-static 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");
{
int i;
+ D(D_ALLOC, ("freeAllRegs: running.\n"));
+
for (i=0;i< _nRegs;i++ )
regsZ80[i].isFree = 1;
}
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)) ||*/
dic = NULL;
break;
}
+#if 0
if (POINTER_SET(dic) &&
IC_RESULT(dic)->key == IC_RESULT(ic)->key ) {
dic = NULL ;
break;
}
+#endif
}
if (!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 */
+ 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;
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 */
- if (IC_LEFT(ic) == NULL ||
- IC_RIGHT(ic) == NULL)
- return TRUE;
+ /* PENDING: check */
+ if (IC_LEFT(uic) == NULL ||
+ IC_RIGHT(uic) == NULL)
+ return FALSE;
- if (uic->op != '=' &&
- !IS_ARITHMETIC_OP(uic) &&
+ /* 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 ) {
+ uic->op != RIGHT_OP &&*/
+ 1
+ ) {
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.
*/
{
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 (!IS_GB) {
- /* if pointer set & left has a size more than
+ /* if pointer set & left has a size more than
one and right is not in far space */
- if (POINTER_SET(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);
-
- /* if pointer get */
- if (POINTER_GET(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);
- }
-
+ if (POINTER_SET(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);
+
+ /* if pointer get */
+ if (POINTER_GET(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);
/* 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
getSize(operandType(IC_RESULT(ic))) <= 2)
packRegsForAccUse (ic);
#else
- if ((POINTER_GET(ic) ||
- IS_ARITHMETIC_OP(ic) ||
- IS_BITWISE_OP(ic) ||
- ic->op == LEFT_OP ||
- ic->op == RIGHT_OP
- ) &&
- IS_ITEMP(IC_RESULT(ic)) &&
+ 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;
+ stackExtend = dataExtend = 0;
if (IS_GB) {
/* DE is required for the code gen. */