fixed bug #510826
[fw/sdcc] / src / ds390 / ralloc.c
index 2a17ebf22bf0470ca119e85d9f61997925b5eb82..de8d4696aa41cbf6434be59169bdbead1f5a92b0 100644 (file)
@@ -36,6 +36,8 @@
 /* since the pack the registers depending strictly on the MCU      */
 /*-----------------------------------------------------------------*/
 
+#define D(x)
+
 /* Global data */
 static struct
   {
@@ -66,20 +68,22 @@ regs regs390[] =
   {REG_GPR, R7_IDX, REG_GPR, "r7", "ar7", "0", 7, 1, 1},
   {REG_PTR, R0_IDX, REG_PTR, "r0", "ar0", "0", 0, 1, 1},
   {REG_PTR, R1_IDX, REG_PTR, "r1", "ar1", "0", 1, 1, 1},
+  {REG_GPR, DPL_IDX, REG_GPR, "dpl", "dpl", "dpl", 0, 0, 0},
+  {REG_GPR, DPH_IDX, REG_GPR, "dph", "dph", "dph", 0, 0, 0},
+  {REG_GPR, DPX_IDX, REG_GPR, "dpx", "dpx", "dpx", 0, 0, 0},
+  {REG_GPR, B_IDX, REG_GPR, "b", "b", "b", 0, 0, 0},
   {REG_GPR, X8_IDX, REG_GPR, "x8", "x8", "xreg", 0, 0, 0},
   {REG_GPR, X9_IDX, REG_GPR, "x9", "x9", "xreg", 1, 0, 0},
   {REG_GPR, X10_IDX, REG_GPR, "x10", "x10", "xreg", 2, 0, 0},
   {REG_GPR, X11_IDX, REG_GPR, "x11", "x11", "xreg", 3, 0, 0},
   {REG_GPR, X12_IDX, REG_GPR, "x12", "x12", "xreg", 4, 0, 0},
   {REG_CND, CND_IDX, REG_GPR, "C", "C", "xreg", 0, 0, 0},
-  {REG_GPR, DPL_IDX, REG_GPR, "dpl", "dpl", "dpl", 0, 0, 0},
-  {REG_GPR, DPH_IDX, REG_GPR, "dph", "dph", "dph", 0, 0, 0},
-  {REG_GPR, DPX_IDX, REG_GPR, "dpx", "dpx", "dpx", 0, 0, 0},
-  {REG_GPR, B_IDX, REG_GPR, "b", "b", "b", 0, 0, 0},
 };
 int ds390_nRegs = 13;
 static void spillThis (symbol *);
 static void freeAllRegs ();
+static iCode * packRegsDPTRuse (operand *);
+static int packRegsDPTRnuse (operand *,int);
 
 /*-----------------------------------------------------------------*/
 /* allocReg - allocates register of given type                     */
@@ -212,6 +216,18 @@ allDefsOutOfRange (bitVect * defs, int fseq, int toseq)
   return TRUE;
 }
 
+/*-----------------------------------------------------------------*/
+/* isOperandInReg - returns true if operand is currently in regs   */
+/*-----------------------------------------------------------------*/
+static int isOperandInReg(operand *op)
+{
+    if (!IS_SYMOP(op)) return 0;
+    if (OP_SYMBOL(op)->ruonly) return 1;
+    if (OP_SYMBOL(op)->accuse) return 1;
+    if (OP_SYMBOL(op)->dptr) return 1;
+    return bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(op)->key);
+}
+
 /*-----------------------------------------------------------------*/
 /* computeSpillable - given a point find the spillable live ranges */
 /*-----------------------------------------------------------------*/
@@ -295,7 +311,8 @@ static int
 notUsedInBlock (symbol * sym, eBBlock * ebp, iCode * ic)
 {
   return (!bitVectBitsInCommon (sym->defs, ebp->usesDefs) &&
-         allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq));
+         allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq) &&
+         allDefsOutOfRange (sym->uses, ebp->fSeq, ebp->lSeq));
 /*     return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs)); */
 }
 
@@ -523,6 +540,8 @@ createStackSpil (symbol * sym)
   }
   SPEC_EXTR (sloc->etype) = 0;
   SPEC_STAT (sloc->etype) = 0;
+  SPEC_VOLATILE(sloc->etype) = 0;
+  SPEC_ABSA(sloc->etype) = 0;
 
   /* we don't allow it to be allocated`
      onto the external stack since : so we
@@ -1135,7 +1154,9 @@ serialRegAssign (eBBlock ** ebbs, int count)
          (ebbs[i]->entryLabel != entryLabel &&
           ebbs[i]->entryLabel != returnLabel))
        continue;
-
+      
+/*       if (returnsAtEnd(ebbs[i])) */
+      
       /* of all instructions do */
       for (ic = ebbs[i]->sch; ic; ic = ic->next)
        {
@@ -1283,95 +1304,167 @@ 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 loop = 0, change;
 
-       int i;
-       int pdone = 0;
+    if (getenv("DISABLE_FILL_GAPS")) return;
+    
+    /* First try to do DPTRuse once more since now we know what got into
+       registers */ 
+    
+    while (loop++ < 10) {
+       change = 0;
+
+       for (sym = hTabFirstItem(liveRanges,&key) ; sym ; 
+            sym = hTabNextItem(liveRanges,&key)) {
+           int size = getSize(sym->type);
+
+           if (sym->liveFrom == sym->liveTo) continue;
+
+           if (sym->uptr && sym->dptr==0 && !sym->ruonly && 
+               size < 4 && size > 1) {
+
+               if (packRegsDPTRuse(operandFromSymbol(sym))) {
+                   
+                   /* if this was ssigned to registers then */
+                   if (bitVectBitValue(_G.totRegAssigned,sym->key)) {
+                       /* take it out of the register assigned set */
+                       bitVectUnSetBit(_G.totRegAssigned,sym->key);
+                   } else if (sym->usl.spillLoc) {
+                       sym->usl.spillLoc->allocreq--;
+                       sym->usl.spillLoc = NULL;
+                   }
+                   
+                   sym->nRegs = 0;                 
+                   sym->isspilt = sym->spillA = 0;
+                   continue ;
+               }
 
-       if (!sym->spillA || !sym->clashes || sym->remat) continue ;
+               /* try assigning other dptrs */
+               if (sym->dptr == 0 && packRegsDPTRnuse(operandFromSymbol(sym),1) && !getenv("DPTRnDISABLE")) {
+                   /* if this was ssigned to registers then */
+                   if (bitVectBitValue(_G.totRegAssigned,sym->key)) {
+                       /* take it out of the register assigned set */
+                       bitVectUnSetBit(_G.totRegAssigned,sym->key);
+                   } else if (sym->usl.spillLoc) {
+                       sym->usl.spillLoc->allocreq--;
+                       sym->usl.spillLoc = NULL;
+                   }
+/*                 printf("Allocated %s in function %s to DPTR1\n",sym->name,currFunc->name); */
+                   sym->nRegs = 0;                 
+                   sym->isspilt = sym->spillA = 0;                 
+               }
+           }
+       }
        
-       /* 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 */
+       /* 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 ;
+           if (!sym->uses || !sym->defs) 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 ;
+               
+               assert (clr = hTabItemWithKey(liveRanges,i));
+               
+               /* 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 ;
-
-           assert (clr = hTabItemWithKey(liveRanges,i));
-        
-           /* 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++ ) {
-           if (sym->regType == REG_PTR)
-               sym->regs[i] = getRegPtrNoSpil ();
-           else
-               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)));
+           }
+           
+           /* THERE IS HOPE !!!! */
+           for (i=0; i < sym->nRegs ; i++ ) {
+               if (sym->regType == REG_PTR)
+                   sym->regs[i] = getRegPtrNoSpil ();
+               else
+                   sym->regs[i] = getRegGprNoSpil ();            
+           }
+           
+           /* for all its definitions & uses 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;
                }
-               if (IS_SYMOP(IC_RIGHT(ic)) && 
-                   bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RIGHT(ic))->key)) {
-                   pdone += positionRegs(sym,OP_SYMBOL(IC_RIGHT(ic)));
+           }
+           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;
                }
-               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 = 0;
-           for (i=0; i < sym->nRegs ; i++ ) {
-               sym->regs[i] = NULL;
+           /* 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 (fprintf (stderr, "Fill Gap gave up due to positioning for "
+                           "%s in function %s\n",
+                           sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+               continue ;          
            }
+           D (fprintf (stderr, "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--;
+           sym->usl.spillLoc = NULL;
            freeAllRegs();
-           printf("Fill Gap gave up due to positioning for %s in function %s\n",sym->name, currFunc ? currFunc->name : "UNKNOWN");
-           continue ;      
+           change ++;
        }
-       printf("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();
+       if (!change) break;
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* rUmaskForOp :- returns register mask for an operand             */
 /*-----------------------------------------------------------------*/
-static bitVect *
-rUmaskForOp (operand * op)
+bitVect *
+ds390_rUmaskForOp (operand * op)
 {
   bitVect *rumask;
   symbol *sym;
@@ -1411,7 +1504,7 @@ regsUsedIniCode (iCode * ic)
   if (ic->op == IFX)
     {
       rmask = bitVectUnion (rmask,
-                           rUmaskForOp (IC_COND (ic)));
+                           ds390_rUmaskForOp (IC_COND (ic)));
       goto ret;
     }
 
@@ -1419,7 +1512,7 @@ regsUsedIniCode (iCode * ic)
   if (ic->op == JUMPTABLE)
     {
       rmask = bitVectUnion (rmask,
-                           rUmaskForOp (IC_JTCOND (ic)));
+                           ds390_rUmaskForOp (IC_JTCOND (ic)));
 
       goto ret;
     }
@@ -1427,16 +1520,16 @@ regsUsedIniCode (iCode * ic)
   /* of all other cases */
   if (IC_LEFT (ic))
     rmask = bitVectUnion (rmask,
-                         rUmaskForOp (IC_LEFT (ic)));
+                         ds390_rUmaskForOp (IC_LEFT (ic)));
 
 
   if (IC_RIGHT (ic))
     rmask = bitVectUnion (rmask,
-                         rUmaskForOp (IC_RIGHT (ic)));
+                         ds390_rUmaskForOp (IC_RIGHT (ic)));
 
   if (IC_RESULT (ic))
     rmask = bitVectUnion (rmask,
-                         rUmaskForOp (IC_RESULT (ic)));
+                         ds390_rUmaskForOp (IC_RESULT (ic)));
 
 ret:
   return rmask;
@@ -1591,10 +1684,7 @@ regTypeNum ()
            }
 
          /* if the symbol has only one definition &
-            that definition is a get_pointer and the
-            pointer we are getting is rematerializable and
-            in "data" space */
-
+            that definition is a get_pointer */
          if (bitVectnBitsOn (sym->defs) == 1 &&
              (ic = hTabItemWithKey (iCodehTab,
                                     bitVectFirstBit (sym->defs))) &&
@@ -1602,12 +1692,10 @@ regTypeNum ()
              !sym->noSpilLoc &&
              !IS_BITVAR (sym->etype))
            {
-
-
-             /* if remat in data space */
+             /* and that pointer is remat in data space */
              if (OP_SYMBOL (IC_LEFT (ic))->remat &&
                  !IS_CAST_ICODE(OP_SYMBOL (IC_LEFT (ic))->rematiCode) &&
-                 DCL_TYPE (aggrToPtr (sym->type, FALSE)) == POINTER)
+                 DCL_TYPE (aggrToPtr (operandType(IC_LEFT(ic)), FALSE)) == POINTER)
                {
 
                  /* create a psuedo symbol & force a spil */
@@ -1857,6 +1945,8 @@ 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)
@@ -1874,6 +1964,7 @@ pack:
     }
 
   remiCodeFromeBBlock (ebp, ic);
+  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;
@@ -1962,8 +2053,9 @@ findAssignToSym (operand * op, iCode * ic)
 /*-----------------------------------------------------------------*/
 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 */
@@ -1978,12 +2070,16 @@ packRegsForSupport (iCode * ic, eBBlock * ebp)
 
       /* found it we need to remove it from the
          block */
-      for (sic = dic; sic != ic; sic = sic->next)
+      for (sic = dic; sic != ic; sic = sic->next) {
        bitVectUnSetBit (sic->rlive, IC_LEFT (ic)->key);
+       sic->rlive = bitVectSetBit (sic->rlive, IC_RIGHT (dic)->key);
+      }
 
       IC_LEFT (ic)->operand.symOperand =
        IC_RIGHT (dic)->operand.symOperand;
+      OP_SYMBOL(IC_LEFT(ic))->liveTo = ic->seq;
       IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
+      bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
       remiCodeFromeBBlock (ebp, dic);
       hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
       change++;
@@ -2011,14 +2107,17 @@ right:
        }
       /* found it we need to remove it from the
          block */
-      for (sic = dic; sic != ic; sic = sic->next)
+      for (sic = dic; sic != ic; sic = sic->next) {
        bitVectUnSetBit (sic->rlive, IC_RIGHT (ic)->key);
+       sic->rlive = bitVectSetBit (sic->rlive, IC_RIGHT (dic)->key);
+      }
 
       IC_RIGHT (ic)->operand.symOperand =
        IC_RIGHT (dic)->operand.symOperand;
       IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
-
+      OP_SYMBOL(IC_RIGHT(ic))->liveTo = ic->seq;
       remiCodeFromeBBlock (ebp, dic);
+      bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
       hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
       change++;
     }
@@ -2029,11 +2128,108 @@ right:
 #define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
 
 
+/*-----------------------------------------------------------------*/
+/* packRegsDPTRnuse - color live ranges that can go into extra DPTRS */
+/*-----------------------------------------------------------------*/
+static int packRegsDPTRnuse( operand *op , int dptr)
+{
+    int i,key;
+    iCode *ic;
+
+    if (!IS_SYMOP(op) || !IS_ITEMP(op)) return 0;
+    if (OP_SYMBOL(op)->remat || OP_SYMBOL(op)->ruonly || OP_SYMBOL(op)->dptr) 
+       return 0; 
+    
+    /* first check if any overlapping liverange has already been
+       assigned to this DPTR */
+    if (OP_SYMBOL(op)->clashes) {
+       for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ ) {
+           symbol *sym;
+           if (bitVectBitValue(OP_SYMBOL(op)->clashes,i)) {
+               sym = hTabItemWithKey(liveRanges,i);
+               if (sym->dptr == dptr) return 0;
+           }
+       }
+    }
+   
+    /* future for more dptrs */
+    if (dptr > 1) {
+       OP_SYMBOL(op)->dptr = dptr;
+       return 1;
+    }
+
+    /* DPTR1 is special since it is also used as a scratch by the backend .
+       so we walk thru the entire live range of this operand and make sure
+       DPTR1 will not be used by the backed . The logic here is to find out if 
+       more than one operand in an icode is in far space then we give up : we 
+       don't keep it live across functions for now
+    */
+    
+    ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom);
+    for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
+        ic = hTabNextItem(iCodeSeqhTab,&key)) {
+       int nfs =0;
+       
+       if (ic->op == CALL || ic->op == PCALL) return 0;
+
+       /* single operand icode are ok */
+       if (ic->op == IFX || ic->op == IPUSH)
+           continue ;
+
+       if (ic->op == SEND ) {
+           if (ic->argreg != 1) return 0;
+           else continue ;
+       }
+       /* two special cases first */
+       if (POINTER_GET(ic) && !isOperandEqual(IC_LEFT(ic),op)  && /* pointer get */
+           !OP_SYMBOL(IC_LEFT(ic))->ruonly                     && /* with result in far space */
+           (isOperandInFarSpace(IC_RESULT(ic)) &&              
+            !isOperandInReg(IC_RESULT(ic)))) {
+           return 0;
+       }
+
+       if (POINTER_SET(ic) && !isOperandEqual(IC_RESULT(ic),op)        && /* pointer set */
+           !OP_SYMBOL(IC_RESULT(ic))->ruonly                           && /* with right in far space */
+           (isOperandInFarSpace(IC_RIGHT(ic)) &&               
+            !isOperandInReg(IC_RIGHT(ic)))) {
+           return 0;
+       }
+
+       if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic))    && /* if symbol operand */
+           !isOperandEqual(IC_RESULT(ic),op)           && /* not the same as this */
+           ((isOperandInFarSpace(IC_RESULT(ic)) ||        /* in farspace or */
+             OP_SYMBOL(IC_RESULT(ic))->onStack)        && /* on the stack   */
+            !isOperandInReg(IC_RESULT(ic)))) {            /* and not in register */
+           nfs++;
+       }
+       /* same for left */
+       if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic))        && /* if symbol operand */
+           !isOperandEqual(IC_LEFT(ic),op)             && /* not the same as this */
+           ((isOperandInFarSpace(IC_LEFT(ic)) ||          /* in farspace or */
+             OP_SYMBOL(IC_LEFT(ic))->onStack)          && /* on the stack   */
+            !isOperandInReg(IC_LEFT(ic)))) {              /* and not in register */
+           nfs++;
+       }
+       /* same for right */
+       if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic))      && /* if symbol operand */
+           !isOperandEqual(IC_RIGHT(ic),op)            && /* not the same as this */
+           ((isOperandInFarSpace(IC_RIGHT(ic)) ||         /* in farspace or */
+             OP_SYMBOL(IC_RIGHT(ic))->onStack)         && /* on the stack   */
+            !isOperandInReg(IC_RIGHT(ic)))) {             /* and not in register */
+           nfs++;
+       }
+       
+       if (nfs > 1) return 0;
+    }
+    OP_SYMBOL(op)->dptr = dptr;
+    return 1;
+}
+
 /*-----------------------------------------------------------------*/
 /* packRegsDPTRuse : - will reduce some registers for single Use */
 /*-----------------------------------------------------------------*/
 static iCode *
-packRegsDPTRuse (iCode * lic, operand * op, eBBlock * ebp)
+packRegsDPTRuse (operand * op)
 {
     /* go thru entire liveRange of this variable & check for
        other possible usage of DPTR , if we don't find it the
@@ -2063,57 +2259,82 @@ packRegsDPTRuse (iCode * lic, operand * op, eBBlock * ebp)
     for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo;
         ic = hTabNextItem(iCodeSeqhTab,&key)) {
 
+       if (SKIP_IC3(ic)) continue;
+
        /* if PCALL cannot be sure give up */
        if (ic->op == PCALL) return NULL;
 
-       /* if CALL then make sure it is VOID || return value not used */
+       /* if SEND & not the first parameter then giveup */
+       if (ic->op == SEND && ic->argreg != 1) return NULL;
+
+       /* if CALL then make sure it is VOID || return value not used 
+          or the return value is assigned to this one */
        if (ic->op == CALL) {
            if (OP_SYMBOL(IC_RESULT(ic))->liveTo == 
                OP_SYMBOL(IC_RESULT(ic))->liveFrom) continue ;
            etype = getSpec(type = operandType(IC_RESULT(ic)));
-           if (getSize(type) == 0) continue ;
+           if (getSize(type) == 0 || isOperandEqual(op,IC_RESULT(ic))) 
+               continue ;
            return NULL ;
        }
 
        /* special case of add with a [remat] */
        if (ic->op == '+' && 
            OP_SYMBOL(IC_LEFT(ic))->remat &&
-           !isOperandInFarSpace(IC_RIGHT(ic))) continue ;
+           (isOperandInFarSpace(IC_RIGHT(ic)) &&
+            !isOperandInReg(IC_RIGHT(ic)))) return NULL ;
 
-       /* special case */
+       /* special case */
        /* pointerGet */
-       if (POINTER_GET(ic) && isOperandEqual(IC_RESULT(ic),op) &&
-           getSize(operandType(IC_LEFT(ic))) > 1) return NULL ;
-
-       if (POINTER_SET(ic) && isOperandEqual(IC_RIGHT(ic),op) &&
-           getSize(operandType(IC_RESULT(ic))) > 1) return NULL;
+       if (POINTER_GET(ic) && !isOperandEqual(IC_LEFT(ic),op) &&
+           getSize(operandType(IC_LEFT(ic))) > 1 ) return NULL ;
+
+       /* pointerSet */
+       if (POINTER_SET(ic) && !isOperandEqual(IC_RESULT(ic),op) &&
+           getSize(operandType(IC_RESULT(ic))) > 1 ) return NULL;
+
+       /* conditionals can destroy 'b' - make sure B wont 
+          be used in this one*/
+       if ((IS_CONDITIONAL(ic) || ic->op == '*' || ic->op == '/'  || 
+            ic->op == LEFT_OP || ic->op == RIGHT_OP ) && 
+           getSize(operandType(op)) > 3) return NULL;
+
+       /* if this is a cast to a bigger type */
+       if (ic->op==CAST) {
+         if (!IS_PTR(OP_SYM_TYPE(IC_RESULT(ic))) && 
+             getSize(OP_SYM_TYPE(IC_RESULT(ic))) >
+             getSize(OP_SYM_TYPE(IC_RIGHT(ic)))) {
+           return 0;
+         }
+       }
 
        /* general case */
        if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) && 
            !isOperandEqual(IC_RESULT(ic),op) &&
-           (isOperandInFarSpace(IC_RESULT(ic)) || 
-            OP_SYMBOL(IC_RESULT(ic))->ruonly   ||
-            OP_SYMBOL(IC_RESULT(ic))->onStack)) return NULL;
+           ( ( ( isOperandInFarSpace(IC_RESULT(ic)) || OP_SYMBOL(IC_RESULT(ic))->onStack) && 
+               !isOperandInReg(IC_RESULT(ic))) || 
+            OP_SYMBOL(IC_RESULT(ic))->ruonly)) return NULL;
 
        if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) && 
            !isOperandEqual(IC_RIGHT(ic),op) &&
-           (OP_SYMBOL(IC_RIGHT(ic))->liveTo > ic->seq || 
+           (OP_SYMBOL(IC_RIGHT(ic))->liveTo >= ic->seq || 
             IS_TRUE_SYMOP(IC_RIGHT(ic))               ||
             OP_SYMBOL(IC_RIGHT(ic))->ruonly) &&
-           (isOperandInFarSpace(IC_RIGHT(ic)) || 
-            OP_SYMBOL(IC_RIGHT(ic))->onStack)) return NULL;
+           ( ( isOperandInFarSpace(IC_RIGHT(ic)) || OP_SYMBOL(IC_RIGHT(ic))->onStack) && 
+               !isOperandInReg(IC_RIGHT(ic))) ) return NULL;
 
        if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) && 
            !isOperandEqual(IC_LEFT(ic),op) &&
            (OP_SYMBOL(IC_LEFT(ic))->liveTo > ic->seq || 
             IS_TRUE_SYMOP(IC_LEFT(ic))               ||
             OP_SYMBOL(IC_LEFT(ic))->ruonly) &&
-           (isOperandInFarSpace(IC_LEFT(ic)) || 
-            OP_SYMBOL(IC_LEFT(ic))->onStack)) return NULL;
+           ( ( isOperandInFarSpace(IC_LEFT(ic)) || OP_SYMBOL(IC_LEFT(ic))->onStack) && 
+               !isOperandInReg(IC_LEFT(ic))) ) return NULL;
        
        if (IC_LEFT(ic) && IC_RIGHT(ic) && 
            IS_ITEMP(IC_LEFT(ic)) && IS_ITEMP(IC_RIGHT(ic)) &&
-           isOperandInFarSpace(IC_LEFT(ic)) && isOperandInFarSpace(IC_RIGHT(ic)))
+           (isOperandInFarSpace(IC_LEFT(ic)) && !isOperandInReg(IC_LEFT(ic))) && 
+           (isOperandInFarSpace(IC_RIGHT(ic)) && !isOperandInReg(IC_RIGHT(ic))))
            return NULL;
     }
     OP_SYMBOL(op)->ruonly = 1;
@@ -2162,6 +2383,17 @@ packRegsForAccUse (iCode * ic)
     return;
   }
 
+  /* if we are calling a reentrant function that has stack parameters */
+  if (ic->op == CALL &&
+       IFFUNC_ISREENT(operandType(IC_LEFT(ic))) &&
+       FUNC_HASSTACKPARM(operandType(IC_LEFT(ic))))
+      return;
+
+  if (ic->op == PCALL &&
+       IFFUNC_ISREENT(operandType(IC_LEFT(ic))->next) &&
+       FUNC_HASSTACKPARM(operandType(IC_LEFT(ic))->next))
+      return;
+
   /* if + or - then it has to be one byte result */
   if ((ic->op == '+' || ic->op == '-')
       && getSize (operandType (IC_RESULT (ic))) > 1)
@@ -2237,8 +2469,7 @@ packRegsForAccUse (iCode * ic)
 
   /* 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)
+  if (isOperandOnStack(IC_RESULT(uic)))
     return;
 
   /* if either one of them in far space then we cannot */
@@ -2259,19 +2490,6 @@ packRegsForAccUse (iCode * ic)
       IC_LEFT (uic)->key != IC_RESULT (ic)->key)
     return;
 
-#if 0
-  // this is too dangerous and need further restrictions
-  // see bug #447547
-
-  /* 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;
-    }
-#endif
-
   /* if the other one is not on stack then we can */
   if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
       (IS_ITEMP (IC_RIGHT (uic)) ||
@@ -2302,7 +2520,7 @@ packForPush (iCode * ic, eBBlock * ebp)
   iCode *dic, *lic;
   bitVect *dbv;
 
-  if (ic->op != IPUSH || !IS_ITEMP (IC_LEFT (ic)))
+  if ((ic->op != IPUSH && ic->op != SEND) || !IS_ITEMP (IC_LEFT (ic)))
     return;
 
   /* must have only definition & one usage */
@@ -2337,11 +2555,18 @@ packForPush (iCode * ic, eBBlock * ebp)
   if (OP_SYMBOL(IC_RIGHT(dic))->liveTo < ic->seq) {
          OP_SYMBOL(IC_RIGHT(dic))->liveTo = ic->seq;
   }
+  for (lic = ic; lic && lic != dic; lic = lic->prev)
+    {
+      bitVectUnSetBit (lic->rlive, IC_LEFT (ic)->key);
+      if (IS_ITEMP (IC_RIGHT (dic)))
+       bitVectSetBit (lic->rlive, IC_RIGHT (dic)->key);
+    }
   /* we now we know that it has one & only one def & use
      and the that the definition is an assignment */
   IC_LEFT (ic) = IC_RIGHT (dic);
 
   remiCodeFromeBBlock (ebp, dic);
+  bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
   hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
 }
 
@@ -2395,6 +2620,18 @@ packRegisters (eBBlock * ebp)
 
        }
 
+       /* if this is an itemp & used as a pointer
+          & assigned to a literal then remat */
+       if (IS_ASSIGN_ICODE(ic) && 
+           IS_ITEMP(IC_RESULT(ic)) &&
+           bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 &&
+           isOperandLiteral(IC_RIGHT(ic))) 
+       {
+         OP_SYMBOL (IC_RESULT (ic))->remat = 1;
+         OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
+         OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;          
+       }
+
       /* if straight assignment then carry remat flag if
          this is the only definition */
       if (ic->op == '=' &&
@@ -2415,6 +2652,7 @@ packRegisters (eBBlock * ebp)
         cast is remat, then we can remat this cast as well */
       if (ic->op == CAST && 
          IS_SYMOP(IC_RIGHT(ic)) &&
+         !OP_SYMBOL(IC_RESULT(ic))->isreqv &&
          OP_SYMBOL(IC_RIGHT(ic))->remat ) {
              sym_link *to_type = operandType(IC_LEFT(ic));
              sym_link *from_type = operandType(IC_RIGHT(ic));
@@ -2449,6 +2687,13 @@ packRegisters (eBBlock * ebp)
       if (POINTER_GET (ic))
        OP_SYMBOL (IC_LEFT (ic))->uptr = 1;
 
+      if (ic->op == RETURN && IS_SYMOP (IC_LEFT(ic)))
+         OP_SYMBOL (IC_LEFT (ic))->uptr = 1;
+
+      if (ic->op == RECEIVE && ic->argreg == 1 &&
+         getSize (operandType(IC_RESULT(ic))) <= 3)
+         OP_SYMBOL (IC_RESULT(ic))->uptr = 1;
+
       if (!SKIP_IC2 (ic))
        {
          /* if we are using a symbol on the stack
@@ -2473,21 +2718,6 @@ packRegisters (eBBlock * ebp)
            }
        }
 
-#if 0
-      /* if the condition of an if instruction
-         is defined in the previous instruction then
-         mark the itemp as a conditional */
-      if ((IS_CONDITIONAL (ic) ||
-          (IS_BITWISE_OP(ic) && isBitwiseOptimizable(ic))) &&
-         ic->next && ic->next->op == IFX &&
-         isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) &&
-         OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq)
-       {
-
-         OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND;
-         continue;
-       }
-#else
       /* if the condition of an if instruction
          is defined in the previous instruction and
         this is the only usage then
@@ -2502,23 +2732,27 @@ packRegisters (eBBlock * ebp)
          OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND;
          continue;
        }
-#endif
-
+#if 1
       /* reduce for support function calls */
       if (ic->supportRtn || ic->op == '+' || ic->op == '-')
        packRegsForSupport (ic, ebp);
-
+#endif
       /* some cases the redundant moves can
-         can be eliminated for return statements */
-      if ((ic->op == RETURN || ic->op == SEND) &&        
+         can be eliminated for return statements . Can be elminated for the first SEND */      
+      if ((ic->op == RETURN || 
+          ((ic->op == SEND || ic->op == RECEIVE)&& ic->argreg == 1)) &&          
          !isOperandInFarSpace (IC_LEFT (ic)) &&
          !options.model) {
         
-         packRegsDPTRuse (ic, IC_LEFT (ic), ebp);
+         packRegsDPTRuse (IC_LEFT (ic));
       }
 
-      if ((ic->op == CALL && getSize(operandType(IC_RESULT(ic))) <= 4)) {
-         packRegsDPTRuse (ic, IC_RESULT (ic), ebp);      
+      if (ic->op == CALL) {
+         sym_link *ftype = operandType(IC_LEFT(ic));
+         if (getSize(operandType(IC_RESULT(ic))) <= 4 &&
+             !IFFUNC_ISBUILTIN(ftype)) {
+             packRegsDPTRuse (IC_RESULT (ic));   
+         }
       }
 
       /* if pointer set & left has a size more than
@@ -2529,7 +2763,7 @@ packRegisters (eBBlock * ebp)
          !IS_OP_RUONLY (IC_RIGHT (ic)) &&
          getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1) {
          
-         packRegsDPTRuse (ic, IC_RESULT (ic), ebp);
+         packRegsDPTRuse (IC_RESULT (ic));
       }
 
       /* if pointer get */
@@ -2539,7 +2773,7 @@ packRegisters (eBBlock * ebp)
          !IS_OP_RUONLY (IC_RESULT (ic)) &&
          getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1) {
 
-         packRegsDPTRuse (ic, IC_LEFT (ic), ebp);
+         packRegsDPTRuse (IC_LEFT (ic));
       }
 
       /* if this is cast for intergral promotion then
@@ -2557,13 +2791,15 @@ packRegisters (eBBlock * ebp)
              SPEC_USIGN (fromType) == SPEC_USIGN (toType))
            {
 
-             iCode *dic = packRegsDPTRuse (ic, IC_RIGHT (ic), ebp);
+             iCode *dic = packRegsDPTRuse (IC_RIGHT (ic));
              if (dic)
                {
                  if (IS_ARITHMETIC_OP (dic))
                    {
+                     bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
                      IC_RESULT (dic) = IC_RESULT (ic);
                      remiCodeFromeBBlock (ebp, ic);
+                     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);
                      ic = ic->prev;
@@ -2580,11 +2816,13 @@ packRegisters (eBBlock * ebp)
              if (compareType (operandType (IC_RIGHT (ic)),
                             operandType (IC_LEFT (ic))) == 1)
                {
-                 iCode *dic = packRegsDPTRuse (ic, IC_RIGHT (ic), ebp);
+                 iCode *dic = packRegsDPTRuse (IC_RIGHT (ic));
                  if (dic)
                    {
+                     bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key);
                      IC_RESULT (dic) = IC_RESULT (ic);
                      remiCodeFromeBBlock (ebp, ic);
+                     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);
                      ic = ic->prev;
@@ -2599,7 +2837,7 @@ packRegisters (eBBlock * ebp)
          -------------
          push V1
        */
-      if (ic->op == IPUSH)
+      if (ic->op == IPUSH || ic->op == SEND)
        {
          packForPush (ic, ebp);
        }
@@ -2616,7 +2854,7 @@ packRegisters (eBBlock * ebp)
       if ((IS_ARITHMETIC_OP (ic)
           || IS_CONDITIONAL(ic)
           || IS_BITWISE_OP (ic)
-          || ic->op == LEFT_OP || ic->op == RIGHT_OP || ic->op == CALL
+          || ic->op == LEFT_OP || ic->op == RIGHT_OP 
           || (ic->op == ADDRESS_OF && isOperandOnStack (IC_LEFT (ic)))
          ) &&
          IS_ITEMP (IC_RESULT (ic)) &&
@@ -2641,7 +2879,7 @@ ds390_assignRegisters (eBBlock ** ebbs, int count)
   setToNull ((void *) &_G.totRegAssigned);  
   setToNull ((void *) &_G.funcrUsed);  
   ds390_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
-  ds390_nRegs = 18;
+  ds390_nRegs = 12;
   if (options.model != MODEL_FLAT24) options.stack10bit = 0;
   /* change assignments this will remove some
      live ranges reducing some register pressure */
@@ -2661,7 +2899,7 @@ ds390_assignRegisters (eBBlock ** ebbs, int count)
   ds390_nRegs = 8;
   freeAllRegs ();
   fillGaps();
-  ds390_nRegs = 18;
+  ds390_nRegs = 12;
 
   /* if stack was extended then tell the user */
   if (_G.stackExtend)