* Added z80 blurb.
[fw/sdcc] / src / z80 / ralloc.c
index 62d3349441981b82e711341b571145a3fe74f170..02a2fc90cc64b471ee0c0f5aa97a211ceb802e08 100644 (file)
@@ -7,8 +7,9 @@
     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      */
@@ -76,16 +74,21 @@ bitVect *regAssigned = NULL;
 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 },
@@ -105,12 +108,13 @@ regs regsZ80[] =
     { 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
@@ -118,20 +122,22 @@ void spillThis (symbol *);
 
     @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", &regsZ80[i]));
            return &regsZ80[i];
        }
     }
+    D(D_ALLOC, ("allocReg: No free.\n"));
     return NULL;
 }
 
@@ -141,10 +147,10 @@ regs *regWithIdx (int idx)
 {
     int i;
     
-    for (i=0;i < nRegs;i++)
+    for (i=0;i < _nRegs;i++)
        if (regsZ80[i].rIdx == idx)
            return &regsZ80[i];
-
+    
     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
           "regWithIdx not found");
     exit(1);
@@ -152,21 +158,22 @@ regs *regWithIdx (int idx)
 
 /** 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++;
@@ -176,7 +183,7 @@ int nFreeRegs (int type)
 
 /** Free registers with type.
  */
-int nfreeRegsType (int type)
+static int nfreeRegsType (int type)
 {
     int nfr ;
     if (type == REG_PTR) {
@@ -188,10 +195,11 @@ int nfreeRegsType (int type)
 }
 
 
+#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 ;
 
@@ -211,11 +219,12 @@ bool allDefsOutOfRange (bitVect *defs,int fseq, int toseq)
     
     return TRUE;
 }
+#endif
   
 /*-----------------------------------------------------------------*/
 /* computeSpillable - given a point find the spillable live ranges */
 /*-----------------------------------------------------------------*/
-bitVect *computeSpillable (iCode *ic)
+static bitVect *computeSpillable (iCode *ic)
 {
     bitVect *spillable ;
 
@@ -240,7 +249,7 @@ bitVect *computeSpillable (iCode *ic)
 /*-----------------------------------------------------------------*/
 /* 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);
 }
@@ -248,66 +257,25 @@ int noSpilLoc (symbol *sym, eBBlock *ebp,iCode *ic)
 /*-----------------------------------------------------------------*/
 /* 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;
 }
@@ -379,18 +347,16 @@ symbol *leastUsedLR (set *sset)
 /*-----------------------------------------------------------------*/
 /* 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;
 }
 
@@ -421,14 +387,6 @@ DEFSETFUNC(isFree)
     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        */
 /*-----------------------------------------------------------------*/
@@ -436,6 +394,8 @@ symbol *createStackSpil (symbol *sym)
 {
     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)) {
@@ -444,6 +404,7 @@ symbol *createStackSpil (symbol *sym)
        sym->stackSpil= 1;
        sloc->isFree = 0;
        addSetHead(&sloc->usl.itmpStack,sym);
+       D(D_ALLOC, ("createStackSpil: found existing\n"));
        return sym;
     }
 
@@ -485,6 +446,8 @@ symbol *createStackSpil (symbol *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;
 }
 
@@ -517,15 +480,17 @@ bool isSpiltOnStack (symbol *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;
@@ -533,21 +498,16 @@ void spillThis (symbol *sym)
        
     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;
@@ -561,12 +521,13 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
     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);
     }
@@ -622,7 +583,7 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
 
     /* 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;
@@ -632,6 +593,7 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
        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;
@@ -640,6 +602,7 @@ symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym)
     
     /* 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;
    
@@ -653,6 +616,8 @@ bool spilSomething (iCode *ic, eBBlock *ebp, symbol *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);
     
@@ -668,7 +633,6 @@ bool spilSomething (iCode *ic, eBBlock *ebp, symbol *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 */
@@ -704,6 +668,8 @@ bool spilSomething (iCode *ic, eBBlock *ebp, symbol *forSym)
     }
 #endif
 
+    D(D_ALLOC, ("spilSomething: done.\n"));
+
     if (ssym == forSym )
        return FALSE ;
     else
@@ -716,18 +682,19 @@ regs *getRegGpr (iCode *ic, eBBlock *ebp,symbol *sym)
 {
     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  */
@@ -750,7 +717,7 @@ static bool symHasReg(symbol *sym,regs *reg)
 /** 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;
@@ -787,6 +754,8 @@ void deassignLRs (iCode *ic, eBBlock *ebp)
            !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;
            
@@ -815,15 +784,23 @@ void deassignLRs (iCode *ic, eBBlock *ebp)
                ((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++) {
@@ -832,6 +809,7 @@ void deassignLRs (iCode *ic, eBBlock *ebp)
                        freeReg(sym->regs[i]);
                } else
                    freeReg(sym->regs[i]);
+               //              sym->regs[i] = NULL;
            }
        }
     }
@@ -840,11 +818,13 @@ void deassignLRs (iCode *ic, eBBlock *ebp)
 
 /** 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);
@@ -859,7 +839,7 @@ void reassignLR (operand *op)
 
 /** 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 */
@@ -876,30 +856,32 @@ int willCauseSpill ( int nr, int rt)
 */
 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.
@@ -907,8 +889,8 @@ static void positionRegs (symbol *result, symbol *opsym, int lineno)
 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] = &regsZ80[i];
@@ -920,9 +902,11 @@ bool tryAllocatingRegPair(symbol *sym)
                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;
 }
 
@@ -930,7 +914,7 @@ bool tryAllocatingRegPair(symbol *sym)
     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;
 
@@ -949,8 +933,10 @@ void serialRegAssign (eBBlock **ebbs, int count)
         
            /* 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 &&
@@ -977,19 +963,24 @@ void serialRegAssign (eBBlock **ebbs, int count)
                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 ;
                }
@@ -1002,6 +993,7 @@ void serialRegAssign (eBBlock **ebbs, int count)
                if ( sym->remat ||                  
                    (willCS  && bitVectIsZero(spillable) ) ) {
 
+                   D(D_ALLOC, ("serialRegAssign: \"remat spill\"\n"));
                    spillThis (sym) ;
                    continue ;
 
@@ -1028,6 +1020,7 @@ void serialRegAssign (eBBlock **ebbs, int count)
 
                /* 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 {
@@ -1078,11 +1071,10 @@ bitVect *rUmaskForOp (operand *op)
     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;
@@ -1092,7 +1084,7 @@ bitVect *rUmaskForOp (operand *op)
  */
 bitVect *regsUsedIniCode (iCode *ic)
 {
-    bitVect *rmask = newBitVect(nRegs);
+    bitVect *rmask = newBitVect(_nRegs);
 
     /* do the special cases first */
     if (ic->op == IFX ) {
@@ -1129,7 +1121,7 @@ bitVect *regsUsedIniCode (iCode *ic)
 
 /** For each instruction will determine the regsUsed.
  */
-void createRegMask (eBBlock **ebbs, int count)
+static void createRegMask (eBBlock **ebbs, int count)
 {
     int i;
 
@@ -1158,7 +1150,7 @@ void createRegMask (eBBlock **ebbs, int count)
            /* 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++ ) {
@@ -1218,7 +1210,7 @@ char *rematStr (symbol *sym)
 /*-----------------------------------------------------------------*/
 /* regTypeNum - computes the type & number of registers required   */
 /*-----------------------------------------------------------------*/
-void regTypeNum ()
+static void regTypeNum (void)
 {
     symbol *sym;
     int k;
@@ -1231,6 +1223,8 @@ void regTypeNum ()
        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) {
 
@@ -1251,6 +1245,8 @@ void regTypeNum ()
                          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");
@@ -1271,11 +1267,13 @@ void regTypeNum ()
 
 /** 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;
 }
 
@@ -1292,13 +1290,15 @@ DEFSETFUNC(deallocStackSpil)
 
 /** 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;
@@ -1318,7 +1318,6 @@ int packRegsForAssign (iCode *ic,eBBlock *ebp)
        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) &&
@@ -1329,13 +1328,10 @@ int packRegsForAssign (iCode *ic,eBBlock *ebp)
        }
 
        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;          
        }
 
@@ -1352,6 +1348,7 @@ int packRegsForAssign (iCode *ic,eBBlock *ebp)
            dic = NULL;
            break;
        }
+#if 0
        if (POINTER_SET(dic) && 
            IC_RESULT(dic)->key == IC_RESULT(ic)->key ) {
            dic = NULL ;
@@ -1367,7 +1364,7 @@ int packRegsForAssign (iCode *ic,eBBlock *ebp)
        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))) ||
@@ -1477,12 +1474,14 @@ iCode *findAssignToSym (operand *op,iCode *ic)
 /*-----------------------------------------------------------------*/
 /* 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);
@@ -1538,6 +1537,8 @@ static iCode *packRegsForOneuse (iCode *ic, operand *op , eBBlock *ebp)
     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;
@@ -1661,11 +1662,23 @@ static bool isBitwiseOptimizable (iCode *ic)
     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;
     
@@ -1789,14 +1802,263 @@ void packRegsForAccUse (iCode *ic)
     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 */
@@ -1815,6 +2077,9 @@ void packRegisters (eBBlock *ebp)
        /* 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)) &&
@@ -1870,43 +2135,44 @@ void packRegisters (eBBlock *ebp)
            !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
     }
 }
   
@@ -1918,11 +2184,20 @@ void z80_assignRegisters (eBBlock **ebbs, int count)
     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 */