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;
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;
+
+ 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 ;
+ /* 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)) ||*/
remiCodeFromeBBlock(ebp,ic);
return 1;
-
}
/** Scanning backwards looks for first assig found.
/* 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;
goto accuse ;
return ;
accuse:
- OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+ OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_A;
+}
+
+static void packRegsForHLUse (iCode *ic)
+{
+ iCode *uic;
+
+ if (IS_GB)
+ return;
+
+ /* has only one definition */
+ if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* has only one use */
+ if (bitVectnBitsOn(OP_USES(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey(iCodehTab,
+ bitVectFirstBit(OP_USES(IC_RESULT(ic))))))
+ return ;
+
+ if (ic->next != uic)
+ return ;
+
+ if (ic->op == ADDRESS_OF && uic->op == IPUSH)
+ goto hluse;
+ if (ic->op == CALL && IC_LEFT(ic)->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
+ goto hluse;
+ return;
+ hluse:
+ OP_SYMBOL(IC_RESULT(ic))->accuse = ACCUSE_HL;
}
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 TRUE;
+ return FALSE;
+ /* PENDING: check this rule */
if (getSize(operandType(IC_RESULT(uic))) > 1) {
return FALSE;
}
- if (uic->op != '=' &&
- !IS_ARITHMETIC_OP(uic) &&
+ /*
+ Bad:
+ !IS_ARITHMETIC_OP(uic) (sub requires A)
+ */
+ if (
+ uic->op != '+' &&
!IS_BITWISE_OP(uic) &&
+ uic->op != '=' &&
uic->op != EQ_OP &&
- uic->op != LEFT_OP &&
!POINTER_GET(uic) &&
- uic->op != RIGHT_OP ) {
+ /*
+ uic->op != LEFT_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.
+ be able to be stored in the accumulator.
+
+ 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)) &&
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 (IS_ITEMP(IC_RESULT(ic))) {
+ packRegsForHLUse(ic);
+ }
#if 0
if ((IS_ARITHMETIC_OP(ic)
|| IS_BITWISE_OP(ic)
getSize(operandType(IC_RESULT(ic))) <= 2)
packRegsForAccUse (ic);
#else
- if (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. */