* src/SDCCpeeph.c: made labelHashEntry global, made pcDistance, FBYNAME static,
[fw/sdcc] / src / z80 / ralloc.c
index bc1c337e98af9f7ed13a3c2ab9ab3af07b0b069b..b8ad485a655deca9ea0efc3ef4fc3a98e344b6dc 100644 (file)
@@ -44,6 +44,7 @@
 */
 
 #include "z80.h"
+#include "SDCCicode.h"
 
 /* Flags to turn off optimisations.
  */
@@ -51,9 +52,9 @@ enum
   {
     DISABLE_PACK_ACC = 0,
     DISABLE_PACK_ASSIGN = 0,
-    /* Pack for one use is quite broken. */
-    DISABLE_PACK_ONE_USE = 1,
-    DISABLE_PACK_HL = 0,
+    DISABLE_PACK_ONE_USE = 0,
+    DISABLE_PACK_HL = 1,
+    DISABLE_PACK_IY = 0
   };
 
 /* Flags to turn on debugging code.
@@ -63,7 +64,13 @@ enum
     D_ALLOC = 0,
     D_ALLOC2 = 0,
     D_ACCUSE2 = 0,
-    D_ACCUSE2_VERBOSE = 0
+    D_ACCUSE2_VERBOSE = 0,
+    D_HLUSE = 0,
+    D_HLUSE2 = 0,
+    D_HLUSE2_VERBOSE = 0,
+    D_FILL_GAPS = 0,
+    D_PACK_IY = 0,
+    D_PACK_HLUSE3 = 0
   };
 
 #if 1
@@ -83,6 +90,7 @@ static struct
   bitVect *spiltSet;
   set *stackSpil;
   bitVect *regAssigned;
+  bitVect *totRegAssigned;    /* final set of LRs that got into registers */
   short blockSpil;
   int slocNum;
   /* registers used in a function */
@@ -115,6 +123,7 @@ regs *regsZ80;
 #define GBZ80_MAX_REGS ((sizeof(_gbz80_regs)/sizeof(_gbz80_regs[0]))-1)
 
 static void spillThis (symbol *);
+static void freeAllRegs ();
 
 /** Allocates register of given type.
     'type' is not used on the z80 version.  It was used to select
@@ -211,34 +220,14 @@ nfreeRegsType (int type)
   return nFreeRegs (type);
 }
 
-
-#if 0
 /*-----------------------------------------------------------------*/
-/* allDefsOutOfRange - all definitions are out of a range          */
+/* useReg - marks a register  as used                              */
 /*-----------------------------------------------------------------*/
-static bool 
-allDefsOutOfRange (bitVect * defs, int fseq, int toseq)
+static void
+useReg (regs * reg)
 {
-  int i;
-
-  if (!defs)
-    return TRUE;
-
-  for (i = 0; i < defs->size; i++)
-    {
-      iCode *ic;
-
-      if (bitVectBitValue (defs, i) &&
-         (ic = hTabItemWithKey (iCodehTab, i)) &&
-         (ic->seq >= fseq && ic->seq <= toseq))
-
-       return FALSE;
-
-    }
-
-  return TRUE;
+  reg->isFree = 0;
 }
-#endif
 
 /*-----------------------------------------------------------------*/
 /* computeSpillable - given a point find the spillable live ranges */
@@ -367,7 +356,7 @@ leastUsedLR (set * sset)
 
     }
 
-  setToNull ((void **) &sset);
+  setToNull ((void *) &sset);
   sym->blockSpil = 0;
   return sym;
 }
@@ -382,6 +371,9 @@ noOverLap (set * itmpStack, symbol * fsym)
   for (sym = setFirstItem (itmpStack); sym;
        sym = setNextItem (itmpStack))
     {
+      if (bitVectBitValue(sym->clashes,fsym->key)) 
+        return 0;
+#if 0
             // if sym starts before (or on) our end point
             // and ends after (or on) our start point, 
             // it is an overlap.
@@ -390,6 +382,7 @@ noOverLap (set * itmpStack, symbol * fsym)
            {
                return 0;
            }
+#endif
     }
   return 1;
 }
@@ -456,6 +449,9 @@ createStackSpil (symbol * sym)
   sloc->type = copyLinkChain (sym->type);
   sloc->etype = getSpec (sloc->type);
   SPEC_SCLS (sloc->etype) = S_AUTO;
+  SPEC_EXTR (sloc->etype) = 0;
+  SPEC_STAT (sloc->etype) = 0;
+  SPEC_VOLATILE(sloc->etype) = 0;
 
   allocLocal (sloc);
 
@@ -504,10 +500,11 @@ spillThis (symbol * sym)
     }
 
   /* mark it has spilt & put it in the spilt set */
-  sym->isspilt = 1;
+  sym->isspilt = sym->spillA = 1;
   _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key);
 
   bitVectUnSetBit (_G.regAssigned, sym->key);
+  bitVectUnSetBit (_G.totRegAssigned, sym->key);
 
   for (i = 0; i < sym->nRegs; i++)
     {
@@ -520,7 +517,7 @@ spillThis (symbol * sym)
 
   if (sym->usl.spillLoc && !sym->remat)
     {
-      sym->usl.spillLoc->allocreq = 1;
+      sym->usl.spillLoc->allocreq++;
     }
   return;
 }
@@ -562,17 +559,6 @@ hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic)
   return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0);
 }
 
-/*-----------------------------------------------------------------*/
-/* notUsedInBlock - not used in this block                         */
-/*-----------------------------------------------------------------*/
-static 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 */
 /*-----------------------------------------------------------------*/
@@ -615,7 +601,7 @@ selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
                           sym->usl.spillLoc->name));
       sym->spildir = 1;
       /* mark it as allocation required */
-      sym->usl.spillLoc->allocreq = 1;
+      sym->usl.spillLoc->allocreq++;
       return sym;
     }
 
@@ -661,7 +647,7 @@ selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
 
       sym = leastUsedLR (selectS);
       /* mark this as allocation required */
-      sym->usl.spillLoc->allocreq = 1;
+      sym->usl.spillLoc->allocreq++;
       return sym;
     }
 #endif
@@ -671,7 +657,7 @@ selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
     {
       D (D_ALLOC, ("selectSpil: using with spill.\n"));
       sym = leastUsedLR (selectS);
-      sym->usl.spillLoc->allocreq = 1;
+      sym->usl.spillLoc->allocreq++;
       return sym;
     }
 
@@ -683,7 +669,7 @@ selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
       D (D_ALLOC, ("selectSpil: creating new spill.\n"));
       /* return a created spil location */
       sym = createStackSpil (leastUsedLR (selectS));
-      sym->usl.spillLoc->allocreq = 1;
+      sym->usl.spillLoc->allocreq++;
       return sym;
     }
 
@@ -710,12 +696,13 @@ spilSomething (iCode * ic, eBBlock * ebp, symbol * forSym)
   ssym = selectSpil (ic, ebp, forSym);
 
   /* mark it as spilt */
-  ssym->isspilt = 1;
+  ssym->isspilt = ssym->spillA = 1;
   _G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key);
 
   /* mark it as not register assigned &
      take it away from the set */
   bitVectUnSetBit (_G.regAssigned, ssym->key);
+  bitVectUnSetBit (_G.totRegAssigned, ssym->key);
 
   /* mark the registers as free */
   for (i = 0; i < ssym->nRegs; i++)
@@ -776,6 +763,7 @@ regs *
 getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym)
 {
   regs *reg;
+  int j;
 
   D (D_ALLOC, ("getRegGpr: on ic %p\n", ic));
 tryAgain:
@@ -792,12 +780,33 @@ tryAgain:
       D (D_ALLOC, ("getRegGpr: have to spill.\n"));
       return NULL;
     }
+  
+  /* make sure partially assigned registers aren't reused */
+  for (j=0; j<=sym->nRegs; j++)
+    if (sym->regs[j])
+      sym->regs[j]->isFree = 0;
 
   /* this looks like an infinite loop but 
      in really selectSpil will abort  */
   goto tryAgain;
 }
 
+static regs *getRegGprNoSpil()
+{
+  regs *reg;
+
+  /* try for gpr type */
+  if ((reg = allocReg (REG_GPR)))
+    {
+      D (D_ALLOC, ("getRegGprNoSpil: got a reg.\n"));
+      return reg;
+    }
+  assert(0);
+
+  /* just to make the compiler happy */
+  return 0;
+}
+
 /** Symbol has a given register.
  */
 static bool 
@@ -877,6 +886,7 @@ deassignLRs (iCode * ic, eBBlock * ebp)
              (result = OP_SYMBOL (IC_RESULT (ic))) &&  /* has a result */
              result->liveTo > ic->seq &&       /* and will live beyond this */
              result->liveTo <= ebp->lSeq &&    /* does not go beyond this block */
+             result->liveFrom == ic->seq &&    /* does not start before here */
              result->regType == sym->regType &&        /* same register types */
              result->nRegs &&  /* which needs registers */
              !result->isspilt &&       /* and does not already have them */
@@ -906,6 +916,7 @@ deassignLRs (iCode * ic, eBBlock * ebp)
                }
 
              _G.regAssigned = bitVectSetBit (_G.regAssigned, result->key);
+             _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, result->key);
            }
 
          /* free the remaining */
@@ -936,10 +947,11 @@ reassignLR (operand * op)
   D (D_ALLOC, ("reassingLR: on sym %p\n", sym));
 
   /* not spilt any more */
-  sym->isspilt = sym->blockSpil = sym->remainSpil = 0;
+  sym->isspilt = sym->spillA = sym->blockSpil = sym->remainSpil = 0;
   bitVectUnSetBit (_G.spiltSet, sym->key);
 
   _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+  _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
 
   _G.blockSpil--;
 
@@ -965,17 +977,18 @@ willCauseSpill (int nr, int rt)
     if this happens make sure they are in the same position as the operand
     otherwise chaos results.
 */
-static void 
-positionRegs (symbol * result, symbol * opsym, int lineno)
+static int
+positionRegs (symbol * result, symbol * opsym)
 {
   int count = min (result->nRegs, opsym->nRegs);
   int i, j = 0, shared = 0;
+  int change = 0;
 
   D (D_ALLOC, ("positionRegs: on result %p opsum %p line %u\n", result, opsym, lineno));
 
   /* if the result has been spilt then cannot share */
   if (opsym->isspilt)
-    return;
+    return 0;
 again:
   shared = 0;
   /* first make sure that they actually share */
@@ -996,8 +1009,10 @@ xchgPositions:
       regs *tmp = result->regs[i];
       result->regs[i] = result->regs[j];
       result->regs[j] = tmp;
+      change ++;
       goto again;
     }
+  return change ;
 }
 
 /** Try to allocate a pair of registers to the symbol.
@@ -1015,6 +1030,8 @@ tryAllocatingRegPair (symbol * sym)
          sym->regs[0] = &regsZ80[i];
          regsZ80[i + 1].isFree = 0;
          sym->regs[1] = &regsZ80[i + 1];
+          sym->regType = REG_PAIR;
+
          if (currFunc)
            {
              currFunc->regsUsed =
@@ -1030,6 +1047,31 @@ tryAllocatingRegPair (symbol * sym)
   return FALSE;
 }
 
+/*------------------------------------------------------------------*/
+/* verifyRegsAssigned - make sure an iTemp is properly initialized; */
+/* it should either have registers or have beed spilled. Otherwise, */
+/* there was an uninitialized variable, so just spill this to get   */
+/* the operand in a valid state.                                    */
+/*------------------------------------------------------------------*/
+static void
+verifyRegsAssigned (operand *op, iCode * ic)
+{
+  symbol * sym;
+  
+  if (!op) return;
+  if (!IS_ITEMP (op)) return;
+  
+  sym = OP_SYMBOL (op);
+  if (sym->isspilt) return;
+  if (!sym->nRegs) return;
+  if (sym->regs[0]) return;
+  
+  werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT, 
+           sym->prereqv ? sym->prereqv->name : sym->name);
+  spillThis (sym);
+}
+
+
 /** Serially allocate registers to the variables.
     This is the main register allocation function.  It is called after
     packing.
@@ -1065,7 +1107,7 @@ serialRegAssign (eBBlock ** ebbs, int count)
          /* if result is present && is a true symbol */
          if (IC_RESULT (ic) && ic->op != IFX &&
              IS_TRUE_SYMOP (IC_RESULT (ic)))
-           OP_SYMBOL (IC_RESULT (ic))->allocreq = 1;
+           OP_SYMBOL (IC_RESULT (ic))->allocreq++;
 
          /* take away registers from live
             ranges that end at this instruction */
@@ -1089,6 +1131,13 @@ serialRegAssign (eBBlock ** ebbs, int count)
              int j;
 
              D (D_ALLOC, ("serialRegAssign: in loop on result %p\n", sym));
+                
+             /* Make sure any spill location is definately allocated */
+             if (sym->isspilt && !sym->remat && sym->usl.spillLoc &&
+                 !sym->usl.spillLoc->allocreq)
+               {
+                 sym->usl.spillLoc->allocreq++;
+               }
 
              /* if it does not need or is spilt 
                 or is already assigned to registers
@@ -1127,6 +1176,17 @@ serialRegAssign (eBBlock ** ebbs, int count)
 
                }
 
+             /* If the live range preceeds the point of definition 
+                then ideally we must take into account registers that 
+                have been allocated after sym->liveFrom but freed
+                before ic->seq. This is complicated, so spill this
+                symbol instead and let fillGaps handle the allocation. */
+             if (sym->liveFrom < ic->seq)
+               {
+                   spillThis (sym);
+                   continue;                 
+               }
+
              /* if it has a spillocation & is used less than
                 all other live ranges then spill this */
              if (willCS) {
@@ -1141,14 +1201,18 @@ serialRegAssign (eBBlock ** ebbs, int count)
                              /* if none of the liveRanges have a spillLocation then better
                                 to spill this one than anything else already assigned to registers */
                              if (liveRangesWith(spillable,noSpilLoc,ebbs[i],ic)) {
+                                 /* if this is local to this block then we might find a block spil */
+                                 if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq)) {
                                      spillThis (sym);
                                      continue;
+                                 }
                              }
                      }
              }
 
              /* else we assign registers to it */
              _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+             _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
 
              /* Special case:  Try to fit into a reg pair if
                 available */
@@ -1176,15 +1240,154 @@ serialRegAssign (eBBlock ** ebbs, int count)
              if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) &&
                  OP_SYMBOL (IC_LEFT (ic))->nRegs && ic->op != '=')
                positionRegs (OP_SYMBOL (IC_RESULT (ic)),
-                             OP_SYMBOL (IC_LEFT (ic)), ic->lineno);
+                             OP_SYMBOL (IC_LEFT (ic)));
              /* do the same for the right operand */
              if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) &&
                  OP_SYMBOL (IC_RIGHT (ic))->nRegs)
                positionRegs (OP_SYMBOL (IC_RESULT (ic)),
-                             OP_SYMBOL (IC_RIGHT (ic)), ic->lineno);
+                             OP_SYMBOL (IC_RIGHT (ic)));
+
+           }
+       }
+    }
+
+    /* Check for and fix any problems with uninitialized operands */
+    for (i = 0; i < count; i++)
+      {
+       iCode *ic;
+
+       if (ebbs[i]->noPath &&
+           (ebbs[i]->entryLabel != entryLabel &&
+            ebbs[i]->entryLabel != returnLabel))
+           continue;
+
+       for (ic = ebbs[i]->sch; ic; ic = ic->next)
+         {
+           if (SKIP_IC2 (ic))
+             continue;
+
+           if (ic->op == IFX)
+             {
+               verifyRegsAssigned (IC_COND (ic), ic);
+               continue;
+             }
+
+           if (ic->op == JUMPTABLE)
+             {
+               verifyRegsAssigned (IC_JTCOND (ic), ic);
+               continue;
+             }
+
+           verifyRegsAssigned (IC_RESULT (ic), ic);
+           verifyRegsAssigned (IC_LEFT (ic), ic);
+           verifyRegsAssigned (IC_RIGHT (ic), ic);
+          }
+      }    
+
+}
+
+/*-----------------------------------------------------------------*/
+/* fillGaps - Try to fill in the Gaps left by Pass1                */
+/*-----------------------------------------------------------------*/
+static void fillGaps()
+{
+    symbol *sym =NULL;
+    int key =0;    
+    
+    if (getenv("DISABLE_FILL_GAPS")) return;
+    
+    /* look for livernages that was spilt by the allocator */
+    for (sym = hTabFirstItem(liveRanges,&key) ; sym ; 
+        sym = hTabNextItem(liveRanges,&key)) {
+
+       int i;
+       int pdone = 0;
+
+       if (!sym->spillA || !sym->clashes || sym->remat) continue ;
+
+       /* find the liveRanges this one clashes with, that are
+          still assigned to registers & mark the registers as used*/
+       for ( i = 0 ; i < sym->clashes->size ; i ++) {
+           int k;
+           symbol *clr;
+
+           if (bitVectBitValue(sym->clashes,i) == 0 ||    /* those that clash with this */
+               bitVectBitValue(_G.totRegAssigned,i) == 0) /* and are still assigned to registers */
+               continue ;
+
+           clr = hTabItemWithKey(liveRanges,i);
+           assert(clr);
+        
+           /* mark these registers as used */
+           for (k = 0 ; k < clr->nRegs ; k++ ) 
+               useReg(clr->regs[k]);
+       }
+
+       if (willCauseSpill(sym->nRegs,sym->regType)) {
+           /* NOPE :( clear all registers & and continue */
+           freeAllRegs();
+           continue ;
+       }
 
+       /* THERE IS HOPE !!!! */
+       for (i=0; i < sym->nRegs ; i++ ) {
+               sym->regs[i] = getRegGprNoSpil ();                
+       }
+
+       /* for all its definitions check if the registers
+          allocated needs positioning NOTE: we can position
+          only ONCE if more than One positioning required 
+          then give up */
+       sym->isspilt = 0;
+       for (i = 0 ; i < sym->defs->size ; i++ ) {
+           if (bitVectBitValue(sym->defs,i)) {
+               iCode *ic;
+               if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+               if (SKIP_IC(ic)) continue;
+               assert(isSymbolEqual(sym,OP_SYMBOL(IC_RESULT(ic)))); /* just making sure */
+               /* if left is assigned to registers */
+               if (IS_SYMOP(IC_LEFT(ic)) && 
+                   bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_LEFT(ic))->key)) {
+                   pdone += positionRegs(sym,OP_SYMBOL(IC_LEFT(ic)));
+               }
+               if (IS_SYMOP(IC_RIGHT(ic)) && 
+                   bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RIGHT(ic))->key)) {
+                   pdone += positionRegs(sym,OP_SYMBOL(IC_RIGHT(ic)));
+               }
+               if (pdone > 1) break;
            }
        }
+       for (i = 0 ; i < sym->uses->size ; i++ ) {
+           if (bitVectBitValue(sym->uses,i)) {
+               iCode *ic;
+               if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+               if (SKIP_IC(ic)) continue;
+               if (!IS_ASSIGN_ICODE(ic)) continue ;
+
+               /* if result is assigned to registers */
+               if (IS_SYMOP(IC_RESULT(ic)) && 
+                   bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RESULT(ic))->key)) {
+                   pdone += positionRegs(sym,OP_SYMBOL(IC_RESULT(ic)));
+               }
+               if (pdone > 1) break;
+           }
+       }
+       /* had to position more than once GIVE UP */
+       if (pdone > 1) {
+           /* UNDO all the changes we made to try this */
+           sym->isspilt = 1;
+           for (i=0; i < sym->nRegs ; i++ ) {
+               sym->regs[i] = NULL;
+           }
+           freeAllRegs();
+           D(D_FILL_GAPS,("Fill Gap gave up due to positioning for %s in function %s\n",sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+           continue ;      
+       }
+       D(D_FILL_GAPS,("FILLED GAP for %s in function %s\n",sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+       _G.totRegAssigned = bitVectSetBit(_G.totRegAssigned,sym->key);
+       sym->isspilt = sym->spillA = 0 ;
+       sym->usl.spillLoc->allocreq--;
+       freeAllRegs();
     }
 }
 
@@ -1335,33 +1538,57 @@ createRegMask (eBBlock ** ebbs, int count)
     }
 }
 
+#if 0
 /** Returns the rematerialized string for a remat var.
  */
-char *
+static char *
 rematStr (symbol * sym)
 {
-  char *s = buffer;
   iCode *ic = sym->rematiCode;
+  int offset = 0;
 
   while (1)
     {
+      /* if plus adjust offset to right hand side */
+      if (ic->op == '+')
+        {
+          offset += (int) operandLitValue (IC_RIGHT (ic));
+          ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+          continue;
+        }
 
-      /* if plus or minus print the right hand side */
-      if (ic->op == '+' || ic->op == '-')
+      /* if minus adjust offset to right hand side */
+      if (ic->op == '-')
        {
-         sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
-                  ic->op);
-         s += strlen (s);
+          offset -= (int) operandLitValue (IC_RIGHT (ic));
          ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
          continue;
        }
+
+      /* cast then continue */
+      if (IS_CAST_ICODE(ic)) {
+          ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+          continue;
+      }
       /* we reached the end */
-      sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
       break;
     }
 
+  if (offset)
+    {
+      SNPRINTF (buffer, sizeof(buffer),
+                "(%s %c 0x%04x)",
+                OP_SYMBOL (IC_LEFT (ic))->rname,
+                offset >= 0 ? '+' : '-',
+                abs (offset) & 0xffff);
+    }
+  else
+    {
+      strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
+    }
   return buffer;
 }
+#endif
 
 /*-----------------------------------------------------------------*/
 /* regTypeNum - computes the type & number of registers required   */
@@ -1473,28 +1700,13 @@ packRegsForAssign (iCode * ic, eBBlock * ebp)
       return 0;
     }
 
-#if 0
-  /* if the true symbol is defined in far space or on stack
-     then we should not since this will increase register pressure */
-  if (isOperandInFarSpace (IC_RESULT (ic)))
-    {
-      if ((dic = farSpacePackable (ic)))
-       goto pack;
-      else
-       return 0;
-    }
-#endif
-
   /* find the definition of iTempNN scanning backwards if we find a 
      a use of the true symbol in before we find the definition then 
      we cannot */
   for (dic = ic->prev; dic; dic = dic->prev)
     {
-      /* if there is a function call and this is
-         a parameter & not my parameter then don't pack it */
-      if ((dic->op == CALL || dic->op == PCALL) &&
-         (OP_SYMBOL (IC_RESULT (ic))->_isparm &&
-          !OP_SYMBOL (IC_RESULT (ic))->ismyparm))
+      /* PENDING: Don't pack across function calls. */
+      if (dic->op == CALL || dic->op == PCALL)
        {
          dic = NULL;
          break;
@@ -1503,46 +1715,83 @@ packRegsForAssign (iCode * ic, eBBlock * ebp)
       if (SKIP_IC2 (dic))
        continue;
 
-      if (IS_SYMOP (IC_RESULT (dic)) &&
-         IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
-       {
-         break;
-       }
+      if (dic->op == IFX)
+        {
+          if (IS_SYMOP (IC_COND (dic)) &&
+             (IC_COND (dic)->key == IC_RESULT (ic)->key ||
+              IC_COND (dic)->key == IC_RIGHT (ic)->key))
+           {
+             dic = NULL;
+             break;
+           }
+        }
+      else
+        {
+          if (IS_TRUE_SYMOP (IC_RESULT (dic)) &&
+             IS_OP_VOLATILE (IC_RESULT (dic)))
+           {
+             dic = NULL;
+             break;
+           }
 
-      if (IS_SYMOP (IC_RIGHT (dic)) &&
-         (IC_RIGHT (dic)->key == IC_RESULT (ic)->key ||
-          IC_RIGHT (dic)->key == IC_RIGHT (ic)->key))
-       {
-         dic = NULL;
-         break;
-       }
+          if (IS_SYMOP (IC_RESULT (dic)) &&
+             IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+           {
+             if (POINTER_SET (dic))
+               dic = NULL;
 
-      if (IS_SYMOP (IC_LEFT (dic)) &&
-         (IC_LEFT (dic)->key == IC_RESULT (ic)->key ||
-          IC_LEFT (dic)->key == IC_RIGHT (ic)->key))
-       {
-         dic = NULL;
-         break;
-       }
-#if 0
-      if (POINTER_SET (dic) &&
-         IC_RESULT (dic)->key == IC_RESULT (ic)->key)
-       {
-         dic = NULL;
-         break;
+             break;
+           }
+
+          if (IS_SYMOP (IC_RIGHT (dic)) &&
+             (IC_RIGHT (dic)->key == IC_RESULT (ic)->key ||
+              IC_RIGHT (dic)->key == IC_RIGHT (ic)->key))
+           {
+             dic = NULL;
+             break;
+           }
+
+          if (IS_SYMOP (IC_LEFT (dic)) &&
+             (IC_LEFT (dic)->key == IC_RESULT (ic)->key ||
+              IC_LEFT (dic)->key == IC_RIGHT (ic)->key))
+           {
+             dic = NULL;
+             break;
+           }
+
+          if (IS_SYMOP (IC_RESULT (dic)) &&
+             IC_RESULT (dic)->key == IC_RESULT (ic)->key)
+           {
+             dic = NULL;
+             break;
+           }
+           
        }
-#endif
     }
 
   if (!dic)
     return 0;                  /* did not find */
 
+  /* if assignment then check that right is not a bit */
+  if (ASSIGNMENT (ic) && !POINTER_SET (ic))
+    {
+      sym_link *etype = operandType (IC_RESULT (dic));
+      if (IS_BITFIELD (etype))
+        {
+          /* if result is a bit too then it's ok */
+          etype = operandType (IC_RESULT (ic));
+          if (!IS_BITFIELD (etype))
+            {
+              return 0;
+            }
+       }
+    }
+
   /* if the result is on stack or iaccess then it must be
      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))) ||
@@ -1559,6 +1808,7 @@ pack:
   /* found the definition */
   /* replace the result with the result of */
   /* this assignment and remove this assignment */
+  bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
   IC_RESULT (dic) = IC_RESULT (ic);
 
   if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq)
@@ -1577,6 +1827,9 @@ pack:
 
   remiCodeFromeBBlock (ebp, ic);
   // PENDING: Check vs mcs51
+  bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key);
+  hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
+  OP_DEFS(IC_RESULT (dic))=bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
   return 1;
 }
 
@@ -1688,6 +1941,8 @@ packRegsForSupport (iCode * ic, eBBlock * ebp)
        IC_RIGHT (dic)->operand.symOperand;
       IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
       remiCodeFromeBBlock (ebp, dic);
+      bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+      hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
       // PENDING: Check vs mcs51
       change++;
     }
@@ -1713,6 +1968,8 @@ right:
       IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
 
       remiCodeFromeBBlock (ebp, dic);
+      bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+      hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
       // PENDING: vs mcs51
       change++;
     }
@@ -1740,8 +1997,10 @@ packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
 
   /* only upto 2 bytes since we cannot predict
      the usage of b, & acc */
-  if (getSize (operandType (op)) > 2 &&
-      ic->op != RETURN &&
+  if (getSize (operandType (op)) > 2)
+    return NULL;
+
+  if (ic->op != RETURN &&
       ic->op != SEND)
     return NULL;
 
@@ -1774,7 +2033,8 @@ packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
   /* now check if it is the return from a function call */
   if (dic->op == CALL || dic->op == PCALL)
     {
-      if (ic->op != SEND && ic->op != RETURN)
+      if (ic->op != SEND && ic->op != RETURN &&
+         !POINTER_SET(ic) && !POINTER_GET(ic))
        {
          OP_SYMBOL (op)->ruonly = 1;
          return dic;
@@ -1887,6 +2147,11 @@ packRegsForAccUse (iCode * ic)
 {
   iCode *uic;
 
+  /* if this is an aggregate, e.g. a one byte char array */
+  if (IS_AGGREGATE(operandType(IC_RESULT(ic)))) {
+    return;
+  }
+
   /* if + or - then it has to be one byte result */
   if ((ic->op == '+' || ic->op == '-')
       && getSize (operandType (IC_RESULT (ic))) > 1)
@@ -2017,38 +2282,384 @@ packRegsForHLUse (iCode * ic)
 {
   iCode *uic;
 
-  if (IS_GB)
-    return;
+  /* PENDING: Could do IFX */
+  if (ic->op == IFX)
+    {
+      return;
+    }
 
   /* has only one definition */
   if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
-    return;
+    {
+      D (D_HLUSE, ("  + Dropping as has more than one def\n"));
+      return;
+    }
 
   /* has only one use */
   if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1)
-    return;
+    {
+      D (D_HLUSE, ("  + Dropping as has more than one use\n"));
+      return;
+    }
 
   /* and the usage immediately follows this iCode */
   if (!(uic = hTabItemWithKey (iCodehTab,
                               bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
-    return;
+    {
+      D (D_HLUSE, ("  + Dropping as usage isn't in this block\n"));
+      return;
+    }
 
   if (ic->next != uic)
-    return;
+    {
+      D (D_HLUSE, ("  + Dropping as usage doesn't follow this\n"));
+      return;
+    }
+
+  if (uic->op ==IFX)
+    {
+      return;
+    }
+
+  if (getSize (operandType (IC_RESULT (ic))) != 2 ||
+      (IC_LEFT(uic) && getSize (operandType (IC_LEFT (uic))) != 2) ||
+      (IC_RIGHT(uic) && getSize (operandType (IC_RIGHT (uic))) != 2))
+    {
+      D (D_HLUSE, ("  + Dropping as the result size is not 2\n"));
+      return;
+    }
+
+  if (IS_Z80)
+    {
+      if (ic->op == CAST && uic->op == IPUSH)
+        goto hluse;
+      if (ic->op == ADDRESS_OF && uic->op == IPUSH)
+        goto hluse;
+      if (ic->op == ADDRESS_OF && POINTER_GET (uic) && IS_ITEMP( IC_RESULT (uic)))
+        goto hluse;
+      if (ic->op == CALL && ic->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
+        goto hluse;
+    }
+  else if (IS_GB)
+    {
+      /* Case of assign a constant to offset in a static array. */
+      if (ic->op == '+' && IS_VALOP (IC_RIGHT (ic)))
+        {
+          if (uic->op == '=' && POINTER_SET (uic))
+            {
+              goto hluse;
+            }
+          else if (uic->op == IPUSH && getSize (operandType (IC_LEFT (uic))) == 2)
+            {
+              goto hluse;
+            }
+        }
+    }
 
-  if (ic->op == CAST && uic->op == IPUSH)
-    goto hluse;
-  if (ic->op == ADDRESS_OF && uic->op == IPUSH)
-    goto hluse;
-  if (ic->op == CALL && ic->parmBytes == 0 && (uic->op == '-' || uic->op == '+'))
-    goto hluse;
+  D (D_HLUSE, ("  + Dropping as it's a bad op\n"));
   return;
 hluse:
-  OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_HL;
+  OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_SCRATCH;
 }
 
+static iCode *
+packRegsForHLUse3 (iCode * lic, operand * op, eBBlock * ebp)
+{
+  int i, key;
+  symbol *sym;
+  iCode *ic, *dic;
+  bool isFirst = TRUE;
+
+  D (D_PACK_HLUSE3, ("Checking HL on %p lic key %u first def %u line %u:\n", OP_SYMBOL(op), lic->key, bitVectFirstBit(OP_DEFS(op)), lic->lineno));
+  if (D_PACK_HLUSE3)
+    piCode(lic, NULL);
+
+  if ( OP_SYMBOL(op)->accuse)
+    {
+      return NULL;
+    }
+
+  if (OP_SYMBOL(op)->remat)
+    {
+      return NULL; 
+    }
+
+  /* Only defined once */
+  if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+    return NULL;
+
+  if (getSize (operandType (op)) > 2)
+    return NULL;
+
+  /* And this is the definition */
+  if (bitVectFirstBit (OP_DEFS (op)) != lic->key)
+    return NULL;
+
+  /* first check if any overlapping liverange has already been
+     assigned to DPTR */
+  if (OP_SYMBOL(op)->clashes) 
+    {
+      for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ ) 
+        {
+          if (bitVectBitValue(OP_SYMBOL(op)->clashes,i)) 
+            {
+              sym = hTabItemWithKey(liveRanges,i);
+              if (sym->accuse == ACCUSE_SCRATCH)
+                {
+                  return NULL;
+                }
+            }
+        }
+    }
+
+  /* Nothing else that clashes with this is using the scratch
+     register.  Scan through all of the intermediate instructions and
+     see if any of them could nuke HL.
+  */
+  dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom);
+
+  for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
+       ic = hTabNextItem(iCodeSeqhTab, &key)) 
+    {
+      if (D_PACK_HLUSE3)
+        piCode(ic, NULL);
+      D (D_PACK_HLUSE3, ("(On %p: op: %u next: %p)\n", ic, ic->op, ic->next));
+
+      if (isFirst)
+        {
+          isFirst = FALSE;
+          if (ic->op == ADDRESS_OF)
+            continue;
+          if (POINTER_GET (ic))
+            continue;
+          if (ic->op == '=' && !POINTER_SET(ic))
+            continue;
+        }
+
+      if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic))
+          && isOperandInDirSpace (IC_RESULT (ic)))
+        return NULL;
+
+      if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic))
+          && isOperandInDirSpace (IC_LEFT (ic)))
+        return NULL;
+
+      if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic))
+          && isOperandInDirSpace (IC_RIGHT (ic)))
+        return NULL;
+
+      /* Handle the non left/right/result ones first */
+      if (ic->op == IFX)
+        continue;
+      if (ic->op == JUMPTABLE)
+        return NULL;
+
+      if (SKIP_IC2(ic))
+        continue;
+
+      if (ic->op == CAST)
+        continue;
+
+      if (ic->op == IPUSH && isOperandEqual (op, IC_LEFT (ic)))
+        continue;
+
+      if (ic->op == SEND && isOperandEqual (op, IC_LEFT (ic)))
+        continue;
+
+      if (ic->op == CALL && isOperandEqual (op, IC_RESULT (ic)))
+        continue;
+
+      if (ic->op == LEFT_OP && isOperandLiteral (IC_RIGHT (ic)))
+        continue;
+
+      if ((ic->op == '=' && !POINTER_SET(ic)) ||
+          ic->op == UNARYMINUS ||
+          ic->op == '+' ||
+          ic->op == '-' ||
+          ic->op == '>' ||
+          ic->op == '<' ||
+          ic->op == EQ_OP ||
+          0)
+        continue;
+
+      if (ic->op == '*' && isOperandEqual (op, IC_LEFT (ic)))
+        continue;
+
+      if (POINTER_SET (ic) && isOperandEqual (op, IC_RESULT (ic)))
+        continue;
+
+      if (POINTER_GET (ic) && isOperandEqual (op, IC_LEFT (ic)))
+        continue;
+
+      if (IS_VALOP (IC_RIGHT (ic)) &&
+          (ic->op == EQ_OP ||
+           0))
+        {
+          continue;
+        }
+
+      /* By default give up */
+      return NULL;
+    }
+
+  D (D_PACK_HLUSE3, ("Succeeded!\n"))
+
+  OP_SYMBOL (op)->accuse = ACCUSE_SCRATCH;
+  return dic;
+}
+
+static iCode *
+packRegsForIYUse (iCode * lic, operand * op, eBBlock * ebp)
+{
+  int i, key;
+  symbol *sym;
+  iCode *ic, *dic;
+  bitVect *uses;
+
+  D (D_PACK_IY, ("Checking IY on %p lic key %u first def %u line %u:\n", OP_SYMBOL(op), lic->key, bitVectFirstBit(OP_DEFS(op)), lic->lineno));
+  if (D_PACK_IY)
+    piCode(lic, NULL);
+
+  if ( OP_SYMBOL(op)->accuse)
+    {
+      return NULL;
+    }
+
+  if (OP_SYMBOL(op)->remat)
+    {
+      return NULL; 
+    }
+
+  /* Only defined once */
+  if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+    return NULL;
+
+  /* And this is the definition */
+  if (bitVectFirstBit (OP_DEFS (op)) != lic->key)
+    return NULL;
+
+  /* first check if any overlapping liverange has already been
+     assigned to DPTR */
+  if (OP_SYMBOL(op)->clashes) 
+    {
+      for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ ) 
+        {
+          if (bitVectBitValue(OP_SYMBOL(op)->clashes,i)) 
+            {
+              sym = hTabItemWithKey(liveRanges,i);
+              if (sym->accuse == ACCUSE_IY)
+                {
+                  return NULL;
+                }
+            }
+        }
+    }
+
+  /* Only a few instructions can load into IY */
+  if (lic->op != '=')
+    {
+      return NULL;
+    }
+
+  if (getSize (operandType (op)) != 2)
+    {
+      D (D_ACCUSE2, ("  + Dropping as operation has size is too big\n"));
+      return FALSE;
+    }
+
+  /* Nothing else that clashes with this is using the scratch
+     register.  Scan through all of the intermediate instructions and
+     see if any of them could nuke HL.
+  */
+  dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom);
+  uses = OP_USES(op);
+
+  for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
+       ic = hTabNextItem(iCodeSeqhTab,&key)) 
+    {
+      if (D_PACK_IY)
+        piCode(ic, NULL);
+
+      if (ic->op == PCALL || 
+          ic->op == CALL ||
+          ic->op == JUMPTABLE
+          )
+        return NULL;
+
+      if (SKIP_IC2(ic))
+        continue;
+
+      /* Be pessamistic. */
+      if (ic->op == IFX)
+        return NULL;
+
+      D (D_PACK_IY, ("  op: %u uses %u result: %d left: %d right: %d\n", ic->op, bitVectBitValue(uses, ic->key),
+                     IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) ? isOperandInDirSpace(IC_RESULT(ic)) : -1,
+                     IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) ? isOperandInDirSpace(IC_LEFT(ic)) : -1,
+                     IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) ? isOperandInDirSpace(IC_RIGHT(ic)) : -1
+                     ));
+
+      if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) && 
+          isOperandInDirSpace(IC_RESULT(ic)))
+        return NULL;
+      
+      if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) && 
+          isOperandInDirSpace(IC_RIGHT(ic)))
+        return NULL;
+      
+      if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) && 
+          isOperandInDirSpace(IC_LEFT(ic)))
+        return NULL;
+
+      /* Only certain rules will work against IY.  Check if this iCode uses
+         this symbol. */
+      if (bitVectBitValue(uses, ic->key) != 0)
+        {
+          if (ic->op == '=' &&
+              isOperandEqual(IC_RESULT(ic), op))
+            continue;
+
+          if (ic->op == GET_VALUE_AT_ADDRESS &&
+              isOperandEqual(IC_LEFT(ic), op))
+            continue;
+
+          if (isOperandEqual(IC_RESULT(ic), IC_LEFT(ic)) == FALSE)
+            return NULL;
+
+          if (IC_RIGHT (ic) && IS_VALOP (IC_RIGHT (ic)))
+            {
+              if (ic->op == '+' ||
+                  ic->op == '-')
+                {
+                  /* Only works if the constant is small */
+                  if (operandLitValue (IC_RIGHT (ic)) < 4)
+                    continue;
+                }
+            }
+
+          return NULL;
+        }
+      else
+        {
+          /* This iCode doesn't use the sym.  See if this iCode preserves IY.
+           */
+          continue;
+        }
+
+      /* By default give up */
+      return NULL;
+    }
+
+  D (D_PACK_IY, ("Succeeded IY!\n"));
+
+  OP_SYMBOL (op)->accuse = ACCUSE_IY;
+  return dic;
+}
+
+/** Returns TRUE if this operation can use acc and if it preserves the value.
+ */
 static bool 
-opPreservesA (iCode * ic, iCode * uic)
+opPreservesA (iCode * uic)
 {
   if (uic->op == IFX)
     {
@@ -2093,6 +2704,8 @@ opPreservesA (iCode * ic, iCode * uic)
   return FALSE;
 }
 
+/** Returns true if this operand preserves the value of A.
+ */
 static bool
 opIgnoresA (iCode * ic, iCode * uic)
 {
@@ -2112,6 +2725,15 @@ opIgnoresA (iCode * ic, iCode * uic)
           return TRUE;
         }
     }
+  else if (uic->op == '=' && !POINTER_SET (uic))
+    {
+      /* If they are equal and get optimised out then things are OK. */
+      if (isOperandEqual (IC_RESULT (uic), IC_RIGHT (uic)))
+        {
+          /* Straight assign is OK. */
+          return TRUE;
+        }
+    }
 
   return FALSE;
 }
@@ -2178,16 +2800,22 @@ packRegsForAccUse2 (iCode * ic)
 {
   iCode *uic;
 
-  D (D_ALLOC, ("packRegsForAccUse2: running on ic %p\n", ic));
+  D (D_ACCUSE2, ("packRegsForAccUse2: running on ic %p line %u\n", ic, ic->lineno));
+  if (D_ACCUSE2)
+    piCode (ic, NULL);
 
   /* Filter out all but those 'good' commands */
   if (
        !POINTER_GET (ic) &&
        ic->op != '+' &&
+       ic->op != '-' &&
        !IS_BITWISE_OP (ic) &&
        ic->op != '=' &&
        ic->op != EQ_OP &&
+       ic->op != '<' &&
+       ic->op != '>' &&
        ic->op != CAST &&
+       ic->op != GETHBIT &&
        1)
     {
       D (D_ACCUSE2, ("  + Dropping as not a 'good' source command\n"));
@@ -2243,7 +2871,7 @@ packRegsForAccUse2 (iCode * ic)
 
            bitVectUnSetBit (uses, setBit);
            /* Still contigous. */
-           if (!opPreservesA (ic, next))
+           if (!opPreservesA (next))
              {
                 D (D_ACCUSE2, ("  + Dropping as operation doesn't preserve A\n"));
                return;
@@ -2255,7 +2883,7 @@ packRegsForAccUse2 (iCode * ic)
           {
             if (next->prev == NULL)
               {
-                if (!opPreservesA (ic, next))
+                if (!opPreservesA (next))
                   {
                     D (D_ACCUSE2, ("  + Dropping as operation doesn't preserve A #2\n"));
                     return;
@@ -2295,110 +2923,6 @@ packRegsForAccUse2 (iCode * ic)
     OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
     return;
   }
-
-  /* OLD CODE FOLLOWS */
-  /* if it is a conditional branch then we definitely can
-     MLH: Depends.
-   */
-#if 0
-  if (uic->op == IFX)
-    goto accuse;
-
-  /* MLH: Depends. */
-  if (uic->op == JUMPTABLE)
-    return;
-#endif
-
-  /* if the usage is not is an assignment or an 
-     arithmetic / bitwise / shift operation then not.
-     MLH: Pending:  Invalid.  Our pointer sets are always peechy.
-   */
-#if 0
-  if (POINTER_SET (uic) &&
-      getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
-    {
-      printf ("e5 %u\n", getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)));
-      return;
-    }
-#endif
-
-  printf ("1\n");
-  if (uic->op != '=' &&
-      !IS_ARITHMETIC_OP (uic) &&
-      !IS_BITWISE_OP (uic) &&
-      uic->op != LEFT_OP &&
-      uic->op != RIGHT_OP)
-    {
-      printf ("e6\n");
-      return;
-    }
-
-  /* if used in ^ operation then make sure right is not a 
-     literl */
-  if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic)))
-    return;
-
-  /* if shift operation make sure right side is not a literal */
-  if (uic->op == RIGHT_OP &&
-      (isOperandLiteral (IC_RIGHT (uic)) ||
-       getSize (operandType (IC_RESULT (uic))) > 1))
-    return;
-
-  if (uic->op == LEFT_OP &&
-      (isOperandLiteral (IC_RIGHT (uic)) ||
-       getSize (operandType (IC_RESULT (uic))) > 1))
-    return;
-
-#if 0
-  /* make sure that the result of this icode is not on the
-     stack, since acc is used to compute stack offset */
-  if (IS_TRUE_SYMOP (IC_RESULT (uic)) &&
-      OP_SYMBOL (IC_RESULT (uic))->onStack)
-    return;
-#endif
-
-#if 0
-  /* if either one of them in far space then we cannot */
-  if ((IS_TRUE_SYMOP (IC_LEFT (uic)) &&
-       isOperandInFarSpace (IC_LEFT (uic))) ||
-      (IS_TRUE_SYMOP (IC_RIGHT (uic)) &&
-       isOperandInFarSpace (IC_RIGHT (uic))))
-    return;
-#endif
-
-  /* if the usage has only one operand then we can */
-  if (IC_LEFT (uic) == NULL ||
-      IC_RIGHT (uic) == NULL)
-    goto accuse;
-
-  /* make sure this is on the left side if not
-     a '+' since '+' is commutative */
-  if (ic->op != '+' &&
-      IC_LEFT (uic)->key != IC_RESULT (ic)->key)
-    return;
-
-  /* if one of them is a literal then we can */
-  if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) ||
-      (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
-    {
-      goto accuse;
-      return;
-    }
-
-/** This is confusing :)  Guess for now */
-  if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
-      (IS_ITEMP (IC_RIGHT (uic)) ||
-       (IS_TRUE_SYMOP (IC_RIGHT (uic)))))
-    goto accuse;
-
-  if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
-      (IS_ITEMP (IC_LEFT (uic)) ||
-       (IS_TRUE_SYMOP (IC_LEFT (uic)))))
-    goto accuse;
-  return;
-accuse:
-  printf ("acc ok!\n");
-  OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
 }
 
 /** Does some transformations to reduce register pressure.
@@ -2486,6 +3010,13 @@ packRegisters (eBBlock * ebp)
        packRegsForSupport (ic, ebp);
 #endif
 
+      /* some cases the redundant moves can
+         can be eliminated for return statements */
+      if (ic->op == RETURN || ic->op == SEND)
+        {
+         packRegsForOneuse (ic, IC_LEFT (ic), ebp);
+       }
+
       /* if pointer set & left has a size more than
          one and right is not in far space */
       if (!DISABLE_PACK_ONE_USE &&
@@ -2503,6 +3034,7 @@ packRegisters (eBBlock * ebp)
       /* if pointer get */
       if (!DISABLE_PACK_ONE_USE &&
          POINTER_GET (ic) &&
+         IS_SYMOP (IC_LEFT (ic)) &&
       /* MLH: dont have far space
          !isOperandInFarSpace(IC_RESULT(ic))&& */
          !OP_SYMBOL (IC_LEFT (ic))->remat &&
@@ -2522,7 +3054,21 @@ packRegisters (eBBlock * ebp)
 
       if (!DISABLE_PACK_HL && IS_ITEMP (IC_RESULT (ic)))
        {
-         packRegsForHLUse (ic);
+         /* PENDING */
+          if (IS_GB)
+           {
+             if (0)
+               packRegsForHLUse (ic);
+           }
+          else
+           {
+             packRegsForHLUse3 (ic, IC_RESULT (ic), ebp);
+           }
+       }
+
+      if (!DISABLE_PACK_IY && IS_ITEMP (IC_RESULT (ic)) && IS_Z80)
+       {
+          packRegsForIYUse (ic, IC_RESULT (ic), ebp);
        }
 
       if (!DISABLE_PACK_ACC && IS_ITEMP (IC_RESULT (ic)) &&
@@ -2533,18 +3079,78 @@ packRegisters (eBBlock * ebp)
     }
 }
 
+/** Joins together two byte constant pushes into one word push.
+ */
+static iCode *
+joinPushes (iCode *lic)
+{
+  iCode *ic, *uic;
+
+  for (ic = lic; ic; ic = ic->next)
+    {
+      int first, second;
+      value *val;
+
+      uic = ic->next;
+
+      /* Anything past this? */
+      if (uic == NULL)
+        {
+          continue;
+        }
+      /* This and the next pushes? */
+      if (ic->op != IPUSH || uic->op != IPUSH)
+        {
+          continue;
+        }
+      /* Both literals? */
+      if ( !IS_OP_LITERAL (IC_LEFT (ic)) || !IS_OP_LITERAL (IC_LEFT (uic)))
+        {
+          continue;
+        }
+      /* Both characters? */
+      if ( getSize (operandType (IC_LEFT (ic))) != 1 || getSize (operandType (IC_LEFT (uic))) != 1)
+        {
+          continue;
+        }
+      /* Pull out the values, make a new type, and create the new iCode for it.
+       */
+      first = (int)operandLitValue ( IC_LEFT (ic));
+      second = (int)operandLitValue ( IC_LEFT (uic));
+
+      sprintf (buffer, "%uu", ((first << 8) | (second & 0xFF)) & 0xFFFFU);
+      val = constVal (buffer);
+      SPEC_NOUN (val->type) = V_INT;
+      IC_LEFT (ic) = operandFromOperand (IC_LEFT (ic));
+      IC_LEFT (ic)->operand.valOperand = val;
+      
+      /* Now remove the second one from the list. */
+      ic->next = uic->next;
+      if (uic->next)
+        {
+          /* Patch up the reverse link */
+          uic->next->prev = ic;
+        }
+    }
+
+  return lic;
+}
+
 /*-----------------------------------------------------------------*/
 /* assignRegisters - assigns registers to each live range as need  */
 /*-----------------------------------------------------------------*/
 void 
-z80_assignRegisters (eBBlock ** ebbs, int count)
+z80_assignRegisters (ebbIndex * ebbi)
 {
+  eBBlock ** ebbs = ebbi->bbOrder;
+  int count = ebbi->count;
   iCode *ic;
   int i;
 
   D (D_ALLOC, ("\n-> z80_assignRegisters: entered.\n"));
 
   setToNull ((void *) &_G.funcrUsed);
+  setToNull ((void *) &_G.totRegAssigned);  
   _G.stackExtend = _G.dataExtend = 0;
 
   if (IS_GB)
@@ -2564,8 +3170,12 @@ z80_assignRegisters (eBBlock ** ebbs, int count)
   for (i = 0; i < count; i++)
     packRegisters (ebbs[i]);
 
+  /* liveranges probably changed by register packing
+     so we compute them again */
+  recomputeLiveRanges (ebbs, count);
+
   if (options.dump_pack)
-    dumpEbbsToFileExt (DUMP_PACK, ebbs, count);
+    dumpEbbsToFileExt (DUMP_PACK, ebbi);
 
   /* first determine for each live range the number of 
      registers & the type of registers required for each */
@@ -2574,6 +3184,9 @@ z80_assignRegisters (eBBlock ** ebbs, int count)
   /* and serially allocate registers */
   serialRegAssign (ebbs, count);
 
+  freeAllRegs ();
+  fillGaps();
+
   /* if stack was extended then tell the user */
   if (_G.stackExtend)
     {
@@ -2590,7 +3203,7 @@ z80_assignRegisters (eBBlock ** ebbs, int count)
     }
 
   if (options.dump_rassgn) {
-    dumpEbbsToFileExt (DUMP_RASSGN, ebbs, count);
+    dumpEbbsToFileExt (DUMP_RASSGN, ebbi);
     dumpLiveRanges (DUMP_LRANGE, liveRanges);
   }
 
@@ -2601,6 +3214,8 @@ z80_assignRegisters (eBBlock ** ebbs, int count)
   /* now get back the chain */
   ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
 
+  ic = joinPushes (ic);
+
   /* redo that offsets for stacked automatic variables */
   redoStackOffsets ();
 
@@ -2609,8 +3224,8 @@ z80_assignRegisters (eBBlock ** ebbs, int count)
   /* free up any stackSpil locations allocated */
   applyToSet (_G.stackSpil, deallocStackSpil);
   _G.slocNum = 0;
-  setToNull ((void **) &_G.stackSpil);
-  setToNull ((void **) &_G.spiltSet);
+  setToNull ((void *) &_G.stackSpil);
+  setToNull ((void *) &_G.spiltSet);
   /* mark all registers as free */
   freeAllRegs ();