* src/mcs51/gen.c (pushSide, genSignedRightShift, genDjnz, geniPush):
[fw/sdcc] / src / mcs51 / gen.c
index fc821211b07c879bef1d98b844f5c674d375ce2f..7e61b9de17774c15d138a7921eaf9be969798250 100644 (file)
@@ -74,6 +74,7 @@ static struct
     short nRegsSaved;
     set *sendSet;
     iCode *current_iCode;
+    symbol *currentFunc;
   }
 _G;
 
@@ -134,6 +135,8 @@ emitcode (char *inst, const char *fmt,...)
   while (isspace (*lbp))
     lbp++;
 
+  //printf ("%s\n", lb);
+  
   if (lbp && *lbp)
     lineCurr = (lineCurr ?
                connectLine (lineCurr, newLineNode (lb)) :
@@ -258,6 +261,60 @@ endOfWorld:
   exit (1);
 }
 
+
+/*-----------------------------------------------------------------*/
+/* getTempRegs - initialize an array of pointers to GPR registers */
+/*               that are not in use. Returns 1 if the requested   */
+/*               number of registers were available, 0 otherwise.  */
+/*-----------------------------------------------------------------*/
+int
+getTempRegs(regs **tempRegs, int size, iCode *ic)
+{
+  bitVect * freeRegs;
+  int i;
+  int offset;
+
+  if (!ic)
+    ic = _G.current_iCode;
+  if (!ic)
+    return 0;
+  if (!_G.currentFunc)
+    return 0;
+
+  freeRegs = newBitVect(8);
+  bitVectSetBit (freeRegs, R2_IDX);
+  bitVectSetBit (freeRegs, R3_IDX);
+  bitVectSetBit (freeRegs, R4_IDX);
+  bitVectSetBit (freeRegs, R5_IDX);
+  bitVectSetBit (freeRegs, R6_IDX);
+  bitVectSetBit (freeRegs, R7_IDX);
+
+  if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
+    {
+      bitVect * newfreeRegs;
+      newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
+      freeBitVect(freeRegs);
+      freeRegs = newfreeRegs;
+    }
+  freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
+
+  offset = 0;
+  for (i=0; i<freeRegs->size; i++)
+    {
+      if (bitVectBitValue(freeRegs,i))
+        tempRegs[offset++] = mcs51_regWithIdx(i);
+      if (offset>=size)
+        {
+         freeBitVect(freeRegs);
+         return 1;
+       }
+    }
+
+  freeBitVect(freeRegs);
+  return 1;
+}
+
+
 /*-----------------------------------------------------------------*/
 /* newAsmop - creates a new asmOp                                  */
 /*-----------------------------------------------------------------*/
@@ -293,7 +350,7 @@ leftRightUseAcc(iCode *ic)
   int size;
   int accuseSize = 0;
   int accuse = 0;
-  
+
   if (!ic)
     {
       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
@@ -342,7 +399,7 @@ leftRightUseAcc(iCode *ic)
             accuseSize = size;
         }
     }
-  
+
   if (accuseSize)
     return accuseSize;
   else
@@ -720,7 +777,7 @@ aopOp (operand * op, iCode * ic, bool result)
          aop->size = getSize (sym->type);
          return;
         }
-      
+
       /* else must be a dummy iTemp */
       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
       aop->size = getSize (sym->type);
@@ -908,7 +965,7 @@ aopGet (asmop * aop, int offset, bool bit16, bool dname)
     {
     case AOP_DUMMY:
       return zero;
-      
+
     case AOP_R0:
     case AOP_R1:
       /* if we need to increment it */
@@ -1050,7 +1107,7 @@ aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
     case AOP_DUMMY:
       MOVA (s);                /* read s in case it was volatile */
       break;
-      
+
     case AOP_DIR:
       if (offset)
        sprintf (d, "(%s + %d)",
@@ -1439,20 +1496,35 @@ genCpl (iCode * ic)
   aopOp (IC_RESULT (ic), ic, TRUE);
 
   /* special case if in bit space */
-  if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) {
-    if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) {
-      emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
-      emitcode ("cpl", "c");
-      emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
+  if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+    {
+      if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+       {
+         emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+         emitcode ("cpl", "c");
+         emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
+         goto release;
+       }
+
+      tlbl=newiTempLabel(NULL);
+      if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
+         AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
+         IS_AOP_PREG (IC_LEFT (ic)))
+       {
+         emitcode ("cjne", "%s,#0x01,%05d$",
+                   aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
+                   tlbl->key + 100);
+       }
+      else
+       {
+         char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
+         MOVA (l);
+         emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
+       }
+      emitcode ("", "%05d$:", tlbl->key + 100);
+      outBitC (IC_RESULT(ic));
       goto release;
     }
-    tlbl=newiTempLabel(NULL);
-    emitcode ("cjne", "%s,#0x01,%05d$", 
-             aopGet(AOP(IC_LEFT(ic)), 0, FALSE,FALSE), tlbl->key+100);
-    emitcode ("", "%05d$:", tlbl->key+100);
-    outBitC (IC_RESULT(ic));
-    goto release;
-  }
 
   size = AOP_SIZE (IC_RESULT (ic));
   while (size--)
@@ -1609,10 +1681,10 @@ saveRegisters (iCode * lic)
       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
     return;
-  
+
   /* safe the registers in use at this time but skip the
      ones for the result */
-  rsave = bitVectCplAnd (bitVectCopy (ic->rMask), 
+  rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
                         mcs51_rUmaskForOp (IC_RESULT(ic)));
 
   ic->regsSaved = 1;
@@ -1656,7 +1728,7 @@ unsaveRegisters (iCode * ic)
 
   /* restore the registers in use at this time but skip the
      ones for the result */
-  rsave = bitVectCplAnd (bitVectCopy (ic->rMask), 
+  rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
                         mcs51_rUmaskForOp (IC_RESULT(ic)));
 
   if (options.useXstack)
@@ -1703,7 +1775,7 @@ pushSide (operand * oper, int size)
          AOP_TYPE (oper) != AOP_DIR &&
          strcmp (l, "a"))
        {
-         emitcode ("mov", "a,%s", l);
+         MOVA (l);
          emitcode ("push", "acc");
        }
       else
@@ -1827,7 +1899,7 @@ genIpush (iCode * ic)
          AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
          strcmp (l, "a"))
        {
-         emitcode ("mov", "a,%s", l);
+         MOVA (l);
          emitcode ("push", "acc");
        }
       else
@@ -1876,16 +1948,16 @@ unsaveRBank (int bank, iCode * ic, bool popPsw)
       if (!ic)
       {
          /* Assume r0 is available for use. */
-         r = mcs51_regWithIdx (R0_IDX);;          
-      }        
+         r = mcs51_regWithIdx (R0_IDX);;
+      }
       else
       {
          aop = newAsmop (0);
          r = getFreePtr (ic, &aop, FALSE);
       }
-      emitcode ("mov", "%s,_spx", r->name);      
+      emitcode ("mov", "%s,_spx", r->name);
   }
-  
+
   if (popPsw)
     {
       if (options.useXstack)
@@ -1919,11 +1991,11 @@ unsaveRBank (int bank, iCode * ic, bool popPsw)
     {
       emitcode ("mov", "_spx,%s", r->name);
     }
-    
+
   if (aop)
   {
-      freeAsmop (NULL, aop, ic, TRUE);  
-  }    
+      freeAsmop (NULL, aop, ic, TRUE);
+  }
 }
 
 /*-----------------------------------------------------------------*/
@@ -1989,7 +2061,7 @@ saveRBank (int bank, iCode * ic, bool pushPsw)
     }
 
   if (ic)
-  {  
+  {
       ic->bankSaved = 1;
   }
 }
@@ -2022,7 +2094,7 @@ static void genSend(set *sendSet)
                  emitcode ("mov","b1_%d,%s",rb1_count++,
                            aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
              }
-         }       
+         }
          freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
     }
 }
@@ -2179,7 +2251,7 @@ genPcall (iCode * ic)
 
   if (swapBanks)
   {
-        emitcode ("mov", "psw,#0x%02x", 
+        emitcode ("mov", "psw,#0x%02x",
            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
   }
 
@@ -2190,7 +2262,7 @@ genPcall (iCode * ic)
 
   if (swapBanks)
   {
-       emitcode ("mov", "psw,#0x%02x", 
+       emitcode ("mov", "psw,#0x%02x",
           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
   }
 
@@ -2289,26 +2361,30 @@ inExcludeList (char *s)
 static void
 genFunction (iCode * ic)
 {
-  symbol *sym;
+  symbol *sym = OP_SYMBOL (IC_LEFT (ic));
   sym_link *ftype;
   bool   switchedPSW = FALSE;
   int calleesaves_saved_register = -1;
+  int stackAdjust = sym->stack;
+  int accIsFree = sym->recvSize < 4;
+  iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
 
   _G.nRegsSaved = 0;
   /* create the function header */
   emitcode (";", "-----------------------------------------");
-  emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
+  emitcode (";", " function %s", sym->name);
   emitcode (";", "-----------------------------------------");
 
   emitcode ("", "%s:", sym->rname);
   ftype = operandType (IC_LEFT (ic));
+  _G.currentFunc = sym;
 
   if (IFFUNC_ISNAKED(ftype))
   {
       emitcode(";", "naked function: no prologue.");
       return;
   }
-
+  
   /* here we need to generate the equates for the
      register bank if required */
   if (FUNC_REGBANK (ftype) != rbank)
@@ -2362,17 +2438,15 @@ genFunction (iCode * ic)
                  /* save the registers used */
                  for (i = 0; i < sym->regsUsed->size; i++)
                    {
-                     if (bitVectBitValue (sym->regsUsed, i) ||
-                         (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                     if (bitVectBitValue (sym->regsUsed, i))
                        emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
                    }
                }
-
            }
          else
            {
-               
-             /* this function has  a function call cannot
+
+             /* this function has a function call. We cannot
                 determines register usage so we will have to push the
                 entire bank */
                saveRBank (0, ic, FALSE);
@@ -2395,7 +2469,7 @@ genFunction (iCode * ic)
             * other bank, we must save that bank entirely.
             */
            unsigned long banksToSave = 0;
-           
+
            if (IFFUNC_HASFCALL(sym->type))
            {
 
@@ -2411,11 +2485,11 @@ genFunction (iCode * ic)
                        /* we got to the end OK. */
                        break;
                    }
-                   
+
                    if (i->op == CALL)
                    {
                        sym_link *dtype;
-                       
+
                        dtype = operandType (IC_LEFT(i));
                        if (dtype
                         && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
@@ -2429,8 +2503,8 @@ genFunction (iCode * ic)
                             {
                                 banksToSave |= (1 << FUNC_REGBANK(dtype));
                             }
-                            
-                            /* And note that we don't need to do it in 
+
+                            /* And note that we don't need to do it in
                              * genCall.
                              */
                             i->bankSaved = 1;
@@ -2445,24 +2519,24 @@ genFunction (iCode * ic)
                         * The only thing I can think of to do is
                         * throw a warning and hope.
                         */
-                       werror(W_FUNCPTR_IN_USING_ISR);   
+                       werror(W_FUNCPTR_IN_USING_ISR);
                    }
                }
 
                if (banksToSave && options.useXstack)
                {
-                   /* Since we aren't passing it an ic, 
+                   /* Since we aren't passing it an ic,
                     * saveRBank will assume r0 is available to abuse.
                     *
                     * So switch to our (trashable) bank now, so
                     * the caller's R0 isn't trashed.
                     */
                    emitcode ("push", "psw");
-                   emitcode ("mov", "psw,#0x%02x", 
+                   emitcode ("mov", "psw,#0x%02x",
                              (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
                    switchedPSW = TRUE;
                }
-               
+
                for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
                {
                     if (banksToSave & (1 << ix))
@@ -2474,9 +2548,20 @@ genFunction (iCode * ic)
            // TODO: this needs a closer look
            SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
        }
+      
+      /* Set the register bank to the desired value if nothing else */
+      /* has done so yet. */
+      if (!switchedPSW)
+        {
+          emitcode ("push", "psw");
+          emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
+        }
     }
   else
     {
+      /* This is a non-ISR function. The caller has already switched register */
+      /* banks, if necessary, so just handle the callee-saves option. */
+      
       /* if callee-save to be used for this function
          then save the registers being used in this function */
       if (IFFUNC_CALLEESAVES(sym->type))
@@ -2489,8 +2574,7 @@ genFunction (iCode * ic)
              /* save the registers used */
              for (i = 0; i < sym->regsUsed->size; i++)
                {
-                 if (bitVectBitValue (sym->regsUsed, i) ||
-                     (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                 if (bitVectBitValue (sym->regsUsed, i))
                    {
                      /* remember one saved register for later usage */
                      if (calleesaves_saved_register < 0)
@@ -2503,23 +2587,20 @@ genFunction (iCode * ic)
        }
     }
 
-  /* set the register bank to the desired value */
-  if (( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
-   && !switchedPSW)
-    {
-      emitcode ("push", "psw");
-      emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
-    }
 
   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
     {
 
       if (options.useXstack)
        {
+         if (!accIsFree)
+           emitcode ("push", "acc");
          emitcode ("mov", "r0,%s", spname);
          emitcode ("mov", "a,_bp");
          emitcode ("movx", "@r0,a");
          emitcode ("inc", "%s", spname);
+         if (!accIsFree)
+           emitcode ("pop", "acc");
        }
       else
        {
@@ -2528,16 +2609,76 @@ genFunction (iCode * ic)
        }
       emitcode ("mov", "_bp,%s", spname);
     }
-
+  
+  /* For some cases it is worthwhile to perform a RECEIVE iCode */
+  /* before setting up the stack frame completely. */
+  if (ric && ric->argreg == 1 && IC_RESULT (ric))
+    {
+      symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
+      
+      if (rsym->isitmp)
+        {
+         if (rsym && rsym->regType == REG_CND)
+           rsym = NULL;
+         if (rsym && (rsym->accuse || rsym->ruonly))
+           rsym = NULL;
+          if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
+            rsym = rsym->usl.spillLoc;
+       }
+      
+      /* If the RECEIVE operand immediately spills to the first entry on the */
+      /* stack, we can push it directly (since sp = _bp + 1 at this point) */
+      /* rather than the usual @r0/r1 machinations. */
+      if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
+        {
+         int ofs;
+         
+         _G.current_iCode = ric;
+         D(emitcode (";     genReceive",""));
+         for (ofs=0; ofs < sym->recvSize; ofs++)
+           {
+             if (!strcmp (fReturn[ofs], "a"))
+               emitcode ("push", "acc");
+             else
+               emitcode ("push", fReturn[ofs]);
+           }
+         stackAdjust -= sym->recvSize;
+         if (stackAdjust<0)
+           {
+             assert (stackAdjust>=0);
+             stackAdjust = 0;
+           }
+         _G.current_iCode = ic;
+         ric->generated = 1;
+         accIsFree = 1;
+       }
+      /* If the RECEIVE operand is 4 registers, we can do the moves now */
+      /* to free up the accumulator. */
+      else if (rsym && rsym->nRegs && sym->recvSize == 4)
+        {
+         int ofs;
+         
+         _G.current_iCode = ric;
+         D(emitcode (";     genReceive",""));
+         for (ofs=0; ofs < sym->recvSize; ofs++)
+           {
+             emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
+           }
+         _G.current_iCode = ic;
+         ric->generated = 1;
+         accIsFree = 1;
+       }
+    }
+  
   /* adjust the stack for the function */
-  if (sym->stack)
+  if (stackAdjust)
     {
 
-      int i = sym->stack;
+      int i = stackAdjust;
       if (i > 256)
        werror (W_STACK_OVERFLOW, sym->name);
 
-      if (i > 3 && sym->recvSize < 4)
+      if (i > 3 && accIsFree)
        {
 
          emitcode ("mov", "a,sp");
@@ -2547,6 +2688,11 @@ genFunction (iCode * ic)
        }
       else if (i > 5)
         {
+         /* The accumulator is not free, so we will need another register */
+         /* to clobber. No need to worry about a possible conflict with */
+         /* the above early RECEIVE optimizations since they would have */
+         /* freed the accumulator if they were generated. */
+         
          if (IFFUNC_CALLEESAVES(sym->type))
            {
              /* if it's a callee-saves function we need a saved register */
@@ -2581,17 +2727,24 @@ genFunction (iCode * ic)
   if (sym->xstack)
     {
 
+      if (!accIsFree)
+        emitcode ("push", "acc");
       emitcode ("mov", "a,_spx");
       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
       emitcode ("mov", "_spx,a");
+      if (!accIsFree)
+        emitcode ("pop", "acc");
     }
-  
+
   /* if critical function then turn interrupts off */
   if (IFFUNC_ISCRITICAL (ftype))
     {
-      emitcode ("mov", "c,ea");
+      symbol *tlbl = newiTempLabel (NULL);
+      emitcode ("setb", "c");
+      emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+      emitcode ("clr", "c");
+      emitcode ("", "%05d$:", (tlbl->key + 100));
       emitcode ("push", "psw"); /* save old ea via c in psw */
-      emitcode ("clr", "ea");
     }
 }
 
@@ -2602,13 +2755,19 @@ static void
 genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
-
+  lineNode *lnp = lineCurr;
+  bitVect *regsUsed;
+  bitVect *regsUsedPrologue;
+  bitVect *regsUnneeded;
+  int idx;
+  
+  _G.currentFunc = NULL;
   if (IFFUNC_ISNAKED(sym->type))
   {
       emitcode(";", "naked function: no epilogue.");
       return;
   }
-      
+
   if (IFFUNC_ISCRITICAL (sym->type))
     {
       emitcode ("pop", "psw"); /* restore ea via c in psw */
@@ -2681,18 +2840,16 @@ genEndFunction (iCode * ic)
                  /* save the registers used */
                  for (i = sym->regsUsed->size; i >= 0; i--)
                    {
-                     if (bitVectBitValue (sym->regsUsed, i) ||
-                         (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                     if (bitVectBitValue (sym->regsUsed, i))
                        emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
                    }
                }
-
            }
          else
            {
              if (options.parms_in_bank1) {
                  int i;
-                 for (i = 7 ; i >= 0 ; i-- ) {               
+                 for (i = 7 ; i >= 0 ; i-- ) {
                      emitcode ("pop","%s",rb1regs[i]);
                  }
              }
@@ -2711,7 +2868,7 @@ genEndFunction (iCode * ic)
             */
            unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
            int ix;
-         
+
            for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
            {
                if (savedBanks & (1 << ix))
@@ -2719,7 +2876,7 @@ genEndFunction (iCode * ic)
                    unsaveRBank(ix, NULL, FALSE);
                }
            }
-           
+
            if (options.useXstack)
            {
                /* Restore bank AFTER calling unsaveRBank,
@@ -2771,6 +2928,11 @@ genEndFunction (iCode * ic)
                    emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
                }
            }
+          else if (mcs51_ptrRegReq)
+           {
+             emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
+             emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
+           }
 
        }
 
@@ -2791,6 +2953,99 @@ genEndFunction (iCode * ic)
       emitcode ("ret", "");
     }
 
+  if (!port->peep.getRegsRead || !port->peep.getRegsWritten)
+    return;
+  
+  /* If this was an interrupt handler using bank 0 that called another */
+  /* function, then all registers must be saved; nothing to optimized. */
+  if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
+      && !FUNC_REGBANK(sym->type))
+    return;
+
+  /* There are no push/pops to optimize if not callee-saves or ISR */
+  if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
+    return;
+  
+  /* If there were stack parameters, we cannot optimize without also    */
+  /* fixing all of the stack offsets; this is too dificult to consider. */
+  if (FUNC_HASSTACKPARM(sym->type))
+    return;
+    
+  /* Compute the registers actually used */
+  regsUsed = newBitVect (mcs51_nRegs);
+  regsUsedPrologue = newBitVect (mcs51_nRegs);
+  while (lnp)
+    {
+      if (lnp->ic && lnp->ic->op == FUNCTION)
+        regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
+      else
+        regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
+      
+      if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
+          && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
+       break;
+      if (!lnp->prev)
+        break;
+      lnp = lnp->prev;
+    }
+
+  if (bitVectBitValue (regsUsedPrologue, CND_IDX)
+      && !bitVectBitValue (regsUsed, CND_IDX))
+    {
+      regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
+      if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK(sym->type)
+          && !sym->stack)
+        bitVectUnSetBit (regsUsed, CND_IDX);
+    }
+  else
+    regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
+    
+  /* If this was an interrupt handler that called another function */
+  /* function, then assume A, B, DPH, & DPL may be modified by it. */
+  if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
+    {
+      regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
+      regsUsed = bitVectSetBit (regsUsed, B_IDX);
+      regsUsed = bitVectSetBit (regsUsed, A_IDX);
+      regsUsed = bitVectSetBit (regsUsed, CND_IDX);
+    }
+
+  /* Remove the unneeded push/pops */
+  regsUnneeded = newBitVect (mcs51_nRegs);
+  while (lnp)
+    {
+      if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
+        {
+         if (!strncmp(lnp->line, "push", 4))
+           {
+             idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
+             if (idx>=0 && !bitVectBitValue (regsUsed, idx))
+               {
+                 connectLine (lnp->prev, lnp->next);
+                 regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+               }
+           }
+         if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
+           {
+             idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
+             if (idx>=0 && !bitVectBitValue (regsUsed, idx))
+               {
+                 connectLine (lnp->prev, lnp->next);
+                 regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+               }
+           }
+       }
+      lnp = lnp->next;
+    }  
+  
+  for (idx = 0; idx < regsUnneeded->size; idx++)
+    if (bitVectBitValue (regsUnneeded, idx))
+      emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
+  
+  freeBitVect (regsUnneeded);
+  freeBitVect (regsUsed);
+  freeBitVect (regsUsedPrologue);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2895,7 +3150,7 @@ findLabelBackwards (iCode * ic, int key)
       count++;
 
       /* If we have any pushes or pops, we cannot predict the distance.
-        I don't like this at all, this should be dealt with in the 
+        I don't like this at all, this should be dealt with in the
         back-end */
       if (ic->op == IPUSH || ic->op == IPOP) {
        return 0;
@@ -2934,7 +3189,7 @@ genPlusIncr (iCode * ic)
 
   /* if increment >=16 bits in register or direct space */
   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
-      sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && 
+      sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
       (size > 1) &&
       (icount == 1))
     {
@@ -3174,8 +3429,10 @@ static void
 genPlus (iCode * ic)
 {
   int size, offset = 0;
-  char *add;
+  int skip_bytes = 0;
+  char *add = "add";
   asmop *leftOp, *rightOp;
+  operand * op;
 
   /* special cases :- */
 
@@ -3237,33 +3494,92 @@ genPlus (iCode * ic)
     goto release;
 
   size = getDataSize (IC_RESULT (ic));
-
   leftOp = AOP(IC_LEFT(ic));
   rightOp = AOP(IC_RIGHT(ic));
-  add = "add";
+  op=IC_LEFT(ic);
+
+  /* if this is an add for an array access
+     at a 256 byte boundary */
+  if ( 2 == size
+       && AOP_TYPE (op) == AOP_IMMD
+       && IS_SYMOP (op)
+       && IS_SPEC (OP_SYM_ETYPE (op))
+       && SPEC_ABSA (OP_SYM_ETYPE (op))
+       && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
+     )
+    {
+      D(emitcode (";     genPlus aligned array",""));
+      aopPut (AOP (IC_RESULT (ic)),
+             aopGet (rightOp, 0, FALSE, FALSE),
+             0,
+             isOperandVolatile (IC_RESULT (ic), FALSE));
 
-  while (size--)
-    {
-      if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
+      if( 1 == getDataSize (IC_RIGHT (ic)) )
        {
-         emitcode("mov", "b,a");
-         MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
-         emitcode("xch", "a,b");
-         MOVA (aopGet (rightOp, offset, FALSE, TRUE));
-         emitcode (add, "a,b");
+         aopPut (AOP (IC_RESULT (ic)),
+                 aopGet (leftOp, 1, FALSE, FALSE),
+                 1,
+                 isOperandVolatile (IC_RESULT (ic), FALSE));
        }
-      else if (aopGetUsesAcc (leftOp, offset))
-       {
-         MOVA (aopGet (leftOp, offset, FALSE, TRUE));
-         emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
+      else
+        {
+         MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
+         emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
+         aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
        }
+      goto release;
+    }
+
+  /* if the lower bytes of a literal are zero skip the addition */
+  if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
+    {
+       while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
+              (skip_bytes+1 < size))
+         {
+           skip_bytes++;
+        }
+       if (skip_bytes)
+         D(emitcode (";     genPlus shortcut",""));
+    }
+
+  while (size--)
+    {
+      if( offset >= skip_bytes )
+        {
+         if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
+           {
+             emitcode("mov", "b,a");
+             MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
+             emitcode("xch", "a,b");
+             MOVA (aopGet (rightOp, offset, FALSE, TRUE));
+             emitcode (add, "a,b");
+           }
+         else if (aopGetUsesAcc (leftOp, offset))
+           {
+             MOVA (aopGet (leftOp, offset, FALSE, TRUE));
+             emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
+           }
+         else
+           {
+             MOVA (aopGet (rightOp, offset, FALSE, TRUE));
+             emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
+           }
+         aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
+         add = "addc";  /* further adds must propagate carry */
+        }
       else
-       {
-         MOVA (aopGet (rightOp, offset, FALSE, TRUE));
-         emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
+        {
+          if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
+             isOperandVolatile (IC_RESULT (ic), FALSE))
+           {
+             /* just move */
+              aopPut (AOP (IC_RESULT (ic)),
+                     aopGet (leftOp, offset, FALSE, FALSE),
+                     offset,
+                     isOperandVolatile (IC_RESULT (ic), FALSE));
+           }
        }
-      aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
-      add = "addc";  /* further adds must propagate carry */
+      offset++;
     }
 
   adjustArithmeticResult (ic);
@@ -3531,8 +3847,8 @@ genMinus (iCode * ic)
          aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
        }
     }
-  
-  
+
+
   adjustArithmeticResult (ic);
 
 release:
@@ -3557,7 +3873,6 @@ genMultbits (operand * left,
   outBitC (result);
 }
 
-
 /*-----------------------------------------------------------------*/
 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
 /*-----------------------------------------------------------------*/
@@ -3566,18 +3881,20 @@ genMultOneByte (operand * left,
                operand * right,
                operand * result)
 {
-  sym_link *opetype = operandType (result);
   symbol *lbl;
-  int size=AOP_SIZE(result);
+  int size = AOP_SIZE (result);
+  bool runtimeSign, compiletimeSign;
+  bool lUnsigned, rUnsigned;
 
   D(emitcode (";     genMultOneByte",""));
 
-  if (size<1 || size>2) {
-    // this should never happen
+  if (size < 1 || size > 2)
+    {
+      /* this should never happen */
       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
               AOP_SIZE(result), __FILE__, lineno);
       exit (1);
-  }
+    }
 
   /* (if two literals: the value is computed before) */
   /* if one literal, literal on the right */
@@ -3586,83 +3903,171 @@ genMultOneByte (operand * left,
       operand *t = right;
       right = left;
       left = t;
-      //emitcode (";", "swapped left and right");
-    }
-
-  if (SPEC_USIGN(opetype)
-      // ignore the sign of left and right, what else can we do?
-      || (SPEC_USIGN(operandType(left)) &&
-         SPEC_USIGN(operandType(right)))) {
-    // just an unsigned 8*8=8/16 multiply
-    //emitcode (";","unsigned");
-    // TODO: check for accumulator clash between left & right aops?
-    emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-    MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
-    emitcode ("mul", "ab");
-    aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
-    if (size==2) {
-      aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
+      /* emitcode (";", "swapped left and right"); */
     }
-    return;
-  }
+  /* if no literal, unsigned on the right: shorter code */
+  if (   AOP_TYPE (right) != AOP_LIT
+      && SPEC_USIGN (getSpec (operandType (left))))
+    {
+      operand *t = right;
+      right = left;
+      left = t;
+    }
+
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+  if (size == 1 /* no, this is not a bug; with a 1 byte result there's
+                  no need to take care about the signedness! */
+      || (lUnsigned && rUnsigned))
+    {
+      /* just an unsigned 8 * 8 = 8 multiply
+         or 8u * 8u = 16u */
+      /* emitcode (";","unsigned"); */
+      /* TODO: check for accumulator clash between left & right aops? */
+
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          /* moving to accumulator first helps peepholes */
+          MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+          emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+        }
+      else
+        {
+          emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+          MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+        }
 
-  // we have to do a signed multiply
+      emitcode ("mul", "ab");
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      if (size == 2)
+        aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
+      return;
+    }
 
-  //emitcode (";", "signed");
-  emitcode ("clr", "F0"); // reset sign flag
-  MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+  /* we have to do a signed multiply */
+  /* emitcode (";", "signed"); */
 
-  lbl=newiTempLabel(NULL);
-  emitcode ("jnb", "acc.7,%05d$",  lbl->key+100);
-  // left side is negative, 8-bit two's complement, this fails for -128
-  emitcode ("setb", "F0"); // set sign flag
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
+  /* now sign adjust for both left & right */
 
-  emitcode ("", "%05d$:", lbl->key+100);
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
 
-  /* if literal */
-  if (AOP_TYPE(right)==AOP_LIT) {
-    signed char val=(signed char)floatFromVal (AOP (right)->aopu.aop_lit);
-    /* AND literal negative */
-    if (val < 0) {
-      emitcode ("cpl", "F0"); // complement sign flag
-      emitcode ("mov", "b,#0x%02x", -val);
-    } else {
-      emitcode ("mov", "b,#0x%02x", val);
+  if (!lUnsigned)
+    {
+      if (AOP_TYPE(left) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign = TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
     }
-  } else {
-    lbl=newiTempLabel(NULL);
-    emitcode ("mov", "b,a");
-    emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-    emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
-    // right side is negative, 8-bit two's complement
-    emitcode ("cpl", "F0"); // complement sign flag
-    emitcode ("cpl", "a");
-    emitcode ("inc", "a");
-    emitcode ("", "%05d$:", lbl->key+100);
-  }
-  emitcode ("mul", "ab");
 
-  lbl=newiTempLabel(NULL);
-  emitcode ("jnb", "F0,%05d$", lbl->key+100);
-  // only ONE op was negative, we have to do a 8/16-bit two's complement
-  emitcode ("cpl", "a"); // lsb
-  if (size==1) {
-    emitcode ("inc", "a");
-  } else {
-    emitcode ("add", "a,#1");
-    emitcode ("xch", "a,b");
-    emitcode ("cpl", "a"); // msb
-    emitcode ("addc", "a,#0");
-    emitcode ("xch", "a,b");
-  }
+  if (!rUnsigned)
+    {
+      if (AOP_TYPE(right) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign ^= TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  /* initialize F0, which stores the runtime sign */
+  if (runtimeSign)
+    {
+      if (compiletimeSign)
+       emitcode ("setb", "F0"); /* set sign flag */
+      else
+       emitcode ("clr", "F0"); /* reset sign flag */
+    }
+
+  /* save the signs of the operands */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#0x%02x", -val);
+      else
+        emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (rUnsigned)  /* emitcode (";", "signed"); */
+
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+      else
+        {
+         MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "%05d$:", (lbl->key + 100));
+          emitcode ("mov", "b,a");
+       }
+    }
+
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+
+      if (!lUnsigned && val < 0)
+        emitcode ("mov", "a,#0x%02x", -val);
+      else
+        emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+
+      if (!lUnsigned)
+        {
+          lbl = newiTempLabel (NULL);
+          emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+          emitcode ("cpl", "F0"); /* complement sign flag */
+          emitcode ("cpl", "a"); /* 2's complement */
+          emitcode ("inc", "a");
+          emitcode ("", "%05d$:", (lbl->key + 100));
+        }
+    }
 
-  emitcode ("", "%05d$:", lbl->key+100);
+  /* now the multiplication */
+  emitcode ("mul", "ab");
+  if (runtimeSign || compiletimeSign)
+    {
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+      emitcode ("cpl", "a"); /* lsb 2's complement */
+      if (size != 2)
+        emitcode ("inc", "a"); /* inc doesn't set carry flag */
+      else
+        {
+          emitcode ("add", "a,#1"); /* this sets carry flag */
+          emitcode ("xch", "a,b");
+          emitcode ("cpl", "a"); /* msb 2's complement */
+          emitcode ("addc", "a,#0");
+          emitcode ("xch", "a,b");
+        }
+      emitcode ("", "%05d$:", (lbl->key + 100));
+    }
   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
-  if (size==2) {
+  if (size == 2)
     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
-  }
 }
 
 /*-----------------------------------------------------------------*/
@@ -3746,84 +4151,189 @@ genDivOneByte (operand * left,
               operand * right,
               operand * result)
 {
-  sym_link *opetype = operandType (result);
-  char *l;
+  bool lUnsigned, rUnsigned;
+  bool runtimeSign, compiletimeSign;
   symbol *lbl;
   int size, offset;
 
   D(emitcode (";     genDivOneByte",""));
 
+  /* Why is it necessary that genDivOneByte() can return an int result?
+     Have a look at:
+     
+       volatile unsigned char uc;
+       volatile signed char sc1, sc2;
+       volatile int i;
+     
+       uc  = 255;
+       sc1 = -1;
+       i = uc / sc1;
+
+     Or:
+  
+       sc1 = -128;
+       sc2 = -1;
+       i = sc1 / sc2;
+
+     In all cases a one byte result would overflow, the following cast to int
+     would return the wrong result.
+  
+     Two possible solution:
+       a) cast operands to int, if ((unsigned) / (signed)) or
+          ((signed) / (signed))
+       b) return an 16 bit signed int; this is what we're doing here!
+  */
+  
   size = AOP_SIZE (result) - 1;
   offset = 1;
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
   /* signed or unsigned */
-  if (SPEC_USIGN (opetype))
+  if (lUnsigned && rUnsigned)
     {
       /* unsigned is easy */
       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-      l = aopGet (AOP (left), 0, FALSE, FALSE);
-      MOVA (l);
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
       emitcode ("div", "ab");
       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
       while (size--)
        aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
       return;
     }
-
+  
   /* signed is a little bit more difficult */
 
+  /* now sign adjust for both left & right */
+
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
+
+  if (!lUnsigned)
+    {
+      if (AOP_TYPE(left) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign = TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  if (!rUnsigned)
+    {
+      if (AOP_TYPE(right) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign ^= TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  /* initialize F0, which stores the runtime sign */
+  if (runtimeSign)
+    {
+      if (compiletimeSign)
+       emitcode ("setb", "F0"); /* set sign flag */
+      else
+       emitcode ("clr", "F0"); /* reset sign flag */
+    }
+
   /* save the signs of the operands */
-  l = aopGet (AOP (left), 0, FALSE, FALSE);
-  MOVA (l);
-  emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE));
-  emitcode ("push", "acc");    /* save it on the stack */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#0x%02x", -val);
+      else
+        emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (rUnsigned)
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+      else
+        {
+         MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "%05d$:", (lbl->key + 100));
+          emitcode ("mov", "b,a");
+       }
+    }
 
-  /* now sign adjust for both left & right */
-  l = aopGet (AOP (right), 0, FALSE, FALSE);
-  MOVA (l);
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
-  emitcode ("mov", "b,a");
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
 
-  /* sign adjust left side */
-  l = aopGet (AOP (left), 0, FALSE, FALSE);
-  MOVA (l);
+      if (!lUnsigned && val < 0)
+        emitcode ("mov", "a,#0x%02x", -val);
+      else
+        emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
+      if (!lUnsigned)
+        {
+          lbl = newiTempLabel (NULL);
+          emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+          emitcode ("cpl", "F0"); /* complement sign flag */
+          emitcode ("cpl", "a");  /* 2's complement */
+          emitcode ("inc", "a");
+          emitcode ("", "%05d$:", (lbl->key + 100));
+        }
+    }
 
   /* now the division */
   emitcode ("div", "ab");
-  /* we are interested in the lower order
-     only */
-  emitcode ("mov", "b,a");
-  lbl = newiTempLabel (NULL);
-  emitcode ("pop", "acc");
-  /* if there was an over flow we don't
-     adjust the sign of the result */
-  emitcode ("jb", "ov,%05d$", (lbl->key + 100));
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  CLRC;
-  emitcode ("clr", "a");
-  emitcode ("subb", "a,b");
-  emitcode ("mov", "b,a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
 
-  /* now we are done */
-  aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
-  if (size > 0)
+  if (runtimeSign || compiletimeSign)
     {
-      emitcode ("mov", "c,b.7");
-      emitcode ("subb", "a,acc");
-    }
-  while (size--)
-    aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+      emitcode ("cpl", "a"); /* lsb 2's complement */
+      emitcode ("inc", "a");
+      emitcode ("", "%05d$:", (lbl->key + 100));
 
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      if (size > 0)
+       {
+         /* msb is 0x00 or 0xff depending on the sign */
+         if (runtimeSign)
+           {
+             emitcode ("mov", "c,F0");
+             emitcode ("subb", "a,acc");
+             while (size--)
+               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+           }
+         else /* compiletimeSign */
+           while (size--)
+             aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
+       }
+    }
+  else
+    {
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      while (size--)
+       aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
+    }
 }
 
 /*-----------------------------------------------------------------*/
@@ -3901,73 +4411,133 @@ genModOneByte (operand * left,
               operand * right,
               operand * result)
 {
-  sym_link *opetype = operandType (result);
-  char *l;
+  bool lUnsigned, rUnsigned;
+  bool runtimeSign, compiletimeSign;
   symbol *lbl;
+  int size, offset;
 
   D(emitcode (";     genModOneByte",""));
 
+  size = AOP_SIZE (result) - 1;
+  offset = 1;
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+  
   /* signed or unsigned */
-  if (SPEC_USIGN (opetype))
+  if (lUnsigned && rUnsigned)
     {
       /* unsigned is easy */
       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-      l = aopGet (AOP (left), 0, FALSE, FALSE);
-      MOVA (l);
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
       emitcode ("div", "ab");
       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+      while (size--)
+       aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
       return;
     }
 
   /* signed is a little bit more difficult */
 
-  /* save the signs of the operands */
-  l = aopGet (AOP (left), 0, FALSE, FALSE);
-  MOVA (l);
-
-  emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-  emitcode ("push", "acc");    /* save it on the stack */
-
   /* now sign adjust for both left & right */
-  l = aopGet (AOP (right), 0, FALSE, FALSE);
-  MOVA (l);
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
-  emitcode ("mov", "b,a");
+  /* modulus: sign of the right operand has no influence on the result! */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
 
-  /* sign adjust left side */
-  l = aopGet (AOP (left), 0, FALSE, FALSE);
-  MOVA (l);
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#0x%02x", -val);
+      else
+        emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+    }
+  else /* not literal */
+    {
+      if (rUnsigned)
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+      else
+        {
+         MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+         emitcode ("cpl", "a"); /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "%05d$:", (lbl->key + 100));
+          emitcode ("mov", "b,a");
+       }
+    }
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
+  
+  /* sign adjust left side */
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
 
-  /* now the multiplication */
-  emitcode ("div", "ab");
-  /* we are interested in the lower order
-     only */
-  lbl = newiTempLabel (NULL);
-  emitcode ("pop", "acc");
-  /* if there was an over flow we don't
-     adjust the sign of the result */
-  emitcode ("jb", "ov,%05d$", (lbl->key + 100));
-  emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
-  CLRC;
-  emitcode ("clr", "a");
-  emitcode ("subb", "a,b");
-  emitcode ("mov", "b,a");
-  emitcode ("", "%05d$:", (lbl->key + 100));
+      if (!lUnsigned && val < 0)
+       {
+          compiletimeSign = TRUE; /* set sign flag */
+          emitcode ("mov", "a,#0x%02x", -val);
+        }
+      else
+        emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
 
-  /* now we are done */
-  aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+      if (!lUnsigned)
+        {
+          runtimeSign = TRUE;
+          emitcode ("clr", "F0"); /* clear sign flag */
+
+          lbl = newiTempLabel (NULL);
+          emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
+          emitcode ("setb", "F0"); /* set sign flag */
+          emitcode ("cpl", "a");   /* 2's complement */
+          emitcode ("inc", "a");
+          emitcode ("", "%05d$:", (lbl->key + 100));
+        }
+    }
 
+  /* now the modulus */
+  emitcode ("div", "ab");
+  
+  if (runtimeSign || compiletimeSign)
+    {
+      emitcode ("mov", "a,b");
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
+      emitcode ("cpl", "a"); /* 2's complement */
+      emitcode ("inc", "a");
+      emitcode ("", "%05d$:", (lbl->key + 100));
+     
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      if (size > 0)
+       {
+         /* msb is 0x00 or 0xff depending on the sign */
+         if (runtimeSign)
+           {
+             emitcode ("mov", "c,F0");
+             emitcode ("subb", "a,acc");
+             while (size--)
+               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+           }
+         else /* compiletimeSign */
+           while (size--)
+             aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
+       }
+    }
+  else
+    {
+      aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
+      while (size--)
+       aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
+    }
 }
 
 /*-----------------------------------------------------------------*/
@@ -4190,7 +4760,8 @@ genCmpGt (iCode * ic, iCode * ifx)
 
   letype = getSpec (operandType (left));
   retype = getSpec (operandType (right));
-  sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+  sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
+           (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
   /* assign the amsops */
   aopOp (left, ic, FALSE);
   aopOp (right, ic, FALSE);
@@ -4219,8 +4790,8 @@ genCmpLt (iCode * ic, iCode * ifx)
 
   letype = getSpec (operandType (left));
   retype = getSpec (operandType (right));
-  sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
-
+  sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
+           (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
   /* assign the amsops */
   aopOp (left, ic, FALSE);
   aopOp (right, ic, FALSE);
@@ -4245,12 +4816,14 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
      if the right is in a pointer register and left
      is not */
   if ((AOP_TYPE (left) == AOP_LIT) ||
+      (AOP_TYPE (left) == AOP_IMMD) ||
       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
     {
       operand *t = right;
       right = left;
       left = t;
     }
+
   if (AOP_TYPE (right) == AOP_LIT)
     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
 
@@ -4274,6 +4847,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
   else if (AOP_TYPE (right) == AOP_REG ||
           AOP_TYPE (right) == AOP_DIR ||
           AOP_TYPE (right) == AOP_LIT ||
+           AOP_TYPE (right) == AOP_IMMD ||
           (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
           (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
     {
@@ -4521,7 +5095,7 @@ hasInc (operand *op, iCode *ic,int osize)
   sym_link *retype = getSpec (type);
   iCode *lic = ic->next;
   int isize ;
-  
+
   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
   if (!IS_SYMOP(op)) return NULL;
 
@@ -4532,7 +5106,7 @@ hasInc (operand *op, iCode *ic,int osize)
   while (lic) {
     /* if operand of the form op = op + <sizeof *op> */
     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
-       isOperandEqual(IC_RESULT(lic),op) && 
+       isOperandEqual(IC_RESULT(lic),op) &&
        isOperandLiteral(IC_RIGHT(lic)) &&
        operandLitValue(IC_RIGHT(lic)) == isize) {
       return lic;
@@ -4873,6 +5447,8 @@ genAnd (iCode * ic, iCode * ifx)
            {
              if (ifx)
                jmpTrueOrFalse (ifx, tlbl);
+              else
+               emitcode ("", "%05d$:", tlbl->key + 100);
              goto release;
            }
        }
@@ -4963,6 +5539,8 @@ genAnd (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+          else
+           emitcode ("", "%05d$:", tlbl->key + 100);
        }
       else
        {
@@ -5249,6 +5827,8 @@ genOr (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+         else
+           emitcode ("", "%05d$:", tlbl->key + 100);
        }
       else
        for (; (size--); offset++)
@@ -5730,6 +6310,66 @@ genGetHbit (iCode * ic)
   freeAsmop (result, NULL, ic, TRUE);
 }
 
+/*-----------------------------------------------------------------*/
+/* genSwap - generates code to swap nibbles or bytes               */
+/*-----------------------------------------------------------------*/
+static void
+genSwap (iCode * ic)
+{
+  operand *left, *result;
+
+  D(emitcode (";     genSwap",""));
+
+  left = IC_LEFT (ic);
+  result = IC_RESULT (ic);
+  aopOp (left, ic, FALSE);
+  aopOp (result, ic, FALSE);
+
+  switch (AOP_SIZE (left))
+    {
+    case 1: /* swap nibbles in byte */
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+      emitcode ("swap", "a");
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      break;
+    case 2: /* swap bytes in word */
+      if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
+       {
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
+       }
+      else if (operandsEqu (left, result))
+       {
+          char * reg = "a";
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+         if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
+           {
+             emitcode ("mov", "b,a");
+              reg = "b";
+            }
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
+       }
+      else
+       {
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
+                 1, isOperandVolatile (result, FALSE));
+       }
+      break;
+    default:
+      wassertl(FALSE, "unsupported SWAP operand size");
+    }
+
+  freeAsmop (left, NULL, ic, TRUE);
+  freeAsmop (result, NULL, ic, TRUE);
+}
+
+
 /*-----------------------------------------------------------------*/
 /* AccRol - rotate left accumulator by known count                 */
 /*-----------------------------------------------------------------*/
@@ -6009,16 +6649,16 @@ AccAXLsh (char *x, int shCount)
       AccAXRrl1 (x);           // BCCCCCCD:D000000B
       AccAXRrl1 (x);           // BBCCCCCC:DD000000
 #else
-      emitcode("rrc","a"); 
-      emitcode("xch","a,%s", x); 
-      emitcode("rrc","a"); 
-      emitcode("mov","c,acc.0"); //<< get correct bit 
-      emitcode("xch","a,%s", x); 
-
-      emitcode("rrc","a"); 
-      emitcode("xch","a,%s", x); 
-      emitcode("rrc","a"); 
-      emitcode("xch","a,%s", x); 
+      emitcode("rrc","a");
+      emitcode("xch","a,%s", x);
+      emitcode("rrc","a");
+      emitcode("mov","c,acc.0"); //<< get correct bit
+      emitcode("xch","a,%s", x);
+
+      emitcode("rrc","a");
+      emitcode("xch","a,%s", x);
+      emitcode("rrc","a");
+      emitcode("xch","a,%s", x);
 #endif
       break;
     case 7:                    // a:x <<= 7
@@ -6742,7 +7382,7 @@ shiftRLong (operand * left, int offl,
   }
 
   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
-  
+
   if (offl==MSB16) {
     // shift is > 8
     if (sign) {
@@ -6997,7 +7637,7 @@ genSignedRightShift (iCode * ic)
 
   size = AOP_SIZE (result);
   offset = size - 1;
-  emitcode ("mov", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE));
+  MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
   emitcode ("rlc", "a");
   emitcode ("mov", "ov,c");
   /* if it is only one byte then */
@@ -7042,7 +7682,7 @@ static void
 genRightShift (iCode * ic)
 {
   operand *right, *left, *result;
-  sym_link *retype;
+  sym_link *letype;
   int size, offset;
   char *l;
   symbol *tlbl, *tlbl1;
@@ -7051,9 +7691,9 @@ genRightShift (iCode * ic)
 
   /* if signed then we do it the hard way preserve the
      sign bit moving it inwards */
-  retype = getSpec (operandType (IC_RESULT (ic)));
+  letype = getSpec (operandType (IC_LEFT (ic)));
 
-  if (!SPEC_USIGN (retype))
+  if (!SPEC_USIGN (letype))
     {
       genSignedRightShift (ic);
       return;
@@ -7178,7 +7818,7 @@ emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
         emitcode ("mov", "b,a");
       emitcode ("movx", "a,@%s", rname);
       break;
-      
+
     case FPOINTER:
       if (preserveAinB)
         emitcode ("mov", "b,a");
@@ -7229,7 +7869,7 @@ emitPtrByteSet (char *rname, int p_type, char *src)
       MOVA (src);
       emitcode ("movx", "@%s,a", rname);
       break;
-      
+
     case FPOINTER:
       MOVA (src);
       emitcode ("movx", "@dptr,a");
@@ -7356,11 +7996,11 @@ genNearPointerGet (operand * left,
   aopOp (left, ic, FALSE);
 
   /* if left is rematerialisable and
-     result is not bit variable type and
+     result is not bitfield variable type and
      the left is pointer to data space i.e
      lower 128 bytes of space */
   if (AOP_TYPE (left) == AOP_IMMD &&
-      !IS_BITVAR (retype) &&
+      !IS_BITFIELD (retype) &&
       DCL_TYPE (ltype) == POINTER)
     {
       genDataPointerGet (left, result, ic);
@@ -7405,7 +8045,7 @@ genNearPointerGet (operand * left,
   aopOp (result, ic, result?TRUE:FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype))
+  if (IS_BITFIELD (retype))
     genUnpackBits (result, rname, POINTER);
   else
     {
@@ -7504,7 +8144,7 @@ genPagedPointerGet (operand * left,
   aopOp (result, ic, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype))
+  if (IS_BITFIELD (retype))
     genUnpackBits (result, rname, PPOINTER);
   else
     {
@@ -7571,7 +8211,7 @@ loadDptrFromOperand (operand *op, bool loadBToo)
          emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
           if (loadBToo)
             {
-             if (AOP(op)->aopu.aop_immd.from_cast_remat) 
+             if (AOP(op)->aopu.aop_immd.from_cast_remat)
                emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
              else
                 {
@@ -7631,12 +8271,12 @@ genFarPointerGet (operand * left,
 
   aopOp (left, ic, FALSE);
   loadDptrFromOperand (left, FALSE);
-  
+
   /* so dptr now contains the address */
   aopOp (result, ic, FALSE);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype))
+  if (IS_BITFIELD (retype))
     genUnpackBits (result, "dptr", FPOINTER);
   else
     {
@@ -7651,7 +8291,7 @@ genFarPointerGet (operand * left,
            emitcode ("inc", "dptr");
        }
     }
-  
+
   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
@@ -7675,12 +8315,12 @@ genCodePointerGet (operand * left,
 
   aopOp (left, ic, FALSE);
   loadDptrFromOperand (left, FALSE);
-  
+
   /* so dptr now contains the address */
   aopOp (result, ic, FALSE);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype))
+  if (IS_BITFIELD (retype))
     genUnpackBits (result, "dptr", CPOINTER);
   else
     {
@@ -7697,7 +8337,7 @@ genCodePointerGet (operand * left,
              emitcode ("inc", "dptr");
            }
          else
-           { 
+           {
              emitcode ("mov", "a,#0x%02x", offset);
              emitcode ("movc", "a,@a+dptr");
              aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
@@ -7728,12 +8368,12 @@ genGenPointerGet (operand * left,
 
   aopOp (left, ic, FALSE);
   loadDptrFromOperand (left, TRUE);
-  
+
   /* so dptr know contains the address */
   aopOp (result, ic, FALSE);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype))
+  if (IS_BITFIELD (retype))
     genUnpackBits (result, "dptr", GPOINTER);
   else
     {
@@ -7906,7 +8546,7 @@ genPackBits (sym_link * etype,
   /* all except the partial byte at the end                 */
   for (rlen=blen;rlen>=8;rlen-=8)
     {
-      emitPtrByteSet (rname, p_type, 
+      emitPtrByteSet (rname, p_type,
                       aopGet (AOP (right), offset++, FALSE, TRUE) );
       if (rlen>8)
         emitcode ("inc", "%s", rname);
@@ -7916,7 +8556,7 @@ genPackBits (sym_link * etype,
   if (rlen)
     {
       mask = (((unsigned char) -1 << rlen) & 0xff);
-      
+
       if (AOP_TYPE (right) == AOP_LIT)
         {
           /* Case with partial byte and literal source
@@ -8056,8 +8696,8 @@ genNearPointerSet (operand * right,
   aopOp (right, ic, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, POINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
   else
     {
       /* we have can just get the values */
@@ -8151,8 +8791,8 @@ genPagedPointerSet (operand * right,
   aopOp (right, ic, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, PPOINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
   else
     {
       /* we have can just get the values */
@@ -8221,13 +8861,13 @@ genFarPointerSet (operand * right,
 
   aopOp (result, ic, FALSE);
   loadDptrFromOperand (result, FALSE);
-  
+
   /* so dptr know contains the address */
   aopOp (right, ic, FALSE);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", FPOINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
   else
     {
       size = AOP_SIZE (right);
@@ -8266,13 +8906,13 @@ genGenPointerSet (operand * right,
 
   aopOp (result, ic, FALSE);
   loadDptrFromOperand (result, TRUE);
-  
+
   /* so dptr know contains the address */
   aopOp (right, ic, FALSE);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", GPOINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
   else
     {
       size = AOP_SIZE (right);
@@ -8357,7 +8997,7 @@ genPointerSet (iCode * ic, iCode *pi)
       break;
 
     default:
-      werror (E_INTERNAL_ERROR, __FILE__, __LINE__, 
+      werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
              "genPointerSet: illegal pointer type");
     }
 
@@ -8756,16 +9396,16 @@ genCast (iCode * ic)
            {
                int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
                char gpValStr[10];
-           
+
                if (gpVal == -1)
                {
                    // pointerTypeToGPByte will have bitched.
                    exit(1);
                }
-           
+
                sprintf(gpValStr, "#0x%d", gpVal);
                aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
-           }       
+           }
          goto release;
        }
 
@@ -8869,7 +9509,7 @@ genDjnz (iCode * ic, iCode * ifx)
        * it back after the decrement.
        */
       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
-      
+
       if (strcmp(rByte, "a"))
       {
            /* Something is hopelessly wrong */
@@ -8889,7 +9529,7 @@ genDjnz (iCode * ic, iCode * ifx)
     {
       emitcode ("dec", "%s",
                aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
-      emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
+      MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
       emitcode ("jnz", "%05d$", lbl->key + 100);
     }
   else
@@ -8922,6 +9562,46 @@ genReceive (iCode * ic)
          (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
           IS_TRUE_SYMOP (IC_RESULT (ic)))) {
 
+         regs *tempRegs[4];
+         int receivingA = 0;
+         int roffset = 0;
+
+         for (offset = 0; offset<size; offset++)
+           if (!strcmp (fReturn[offset], "a"))
+             receivingA = 1;
+
+         if (!receivingA)
+           {
+             if (size==1 || getTempRegs(tempRegs, size-1, ic))
+               {
+                 for (offset = size-1; offset>0; offset--)
+                   emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
+                 emitcode("mov","a,%s", fReturn[0]);
+                 _G.accInUse++;
+                 aopOp (IC_RESULT (ic), ic, FALSE);
+                 _G.accInUse--;
+                 aopPut (AOP (IC_RESULT (ic)), "a", offset,
+                         isOperandVolatile (IC_RESULT (ic), FALSE));
+                 for (offset = 1; offset<size; offset++)
+                   aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
+                           isOperandVolatile (IC_RESULT (ic), FALSE));
+                 goto release;
+               }
+           }
+         else
+           {
+             if (getTempRegs(tempRegs, size, ic))
+               {
+                 for (offset = 0; offset<size; offset++)
+                   emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
+                 aopOp (IC_RESULT (ic), ic, FALSE);
+                 for (offset = 0; offset<size; offset++)
+                   aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
+                           isOperandVolatile (IC_RESULT (ic), FALSE));
+                 goto release;
+               }
+           }
+
          offset = fReturnSizeMCS51 - size;
          while (size--) {
              emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
@@ -8950,6 +9630,8 @@ genReceive (iCode * ic)
          aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
       }
   }
+
+release:
   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
 }
 
@@ -8959,34 +9641,116 @@ genReceive (iCode * ic)
 static void
 genDummyRead (iCode * ic)
 {
-  operand *right;
+  operand *op;
   int size, offset;
 
   D(emitcode(";     genDummyRead",""));
 
-  right = IC_RIGHT (ic);
+  op = IC_RIGHT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE);
 
-  aopOp (right, ic, FALSE);
+      /* if the result is a bit */
+      if (AOP_TYPE (op) == AOP_CRY)
+        emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+      else
+       {
+         /* bit variables done */
+         /* general case */
+         size = AOP_SIZE (op);
+         offset = 0;
+         while (size--)
+         {
+           MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
+           offset++;
+         }
+       }
 
-  /* if the result is a bit */
-  if (AOP_TYPE (right) == AOP_CRY)
-    {
-      emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
-      goto release;
+      freeAsmop (op, NULL, ic, TRUE);
     }
 
-  /* bit variables done */
-  /* general case */
-  size = AOP_SIZE (right);
-  offset = 0;
-  while (size--)
+  op = IC_LEFT (ic);
+  if (op && IS_SYMOP (op))
     {
-      MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
-      offset++;
+      aopOp (op, ic, FALSE);
+
+      /* if the result is a bit */
+      if (AOP_TYPE (op) == AOP_CRY)
+        emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+      else
+       {
+         /* bit variables done */
+         /* general case */
+         size = AOP_SIZE (op);
+         offset = 0;
+         while (size--)
+         {
+           MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
+           offset++;
+         }
+       }
+
+      freeAsmop (op, NULL, ic, TRUE);
     }
+}
 
-release:
-  freeAsmop (right, NULL, ic, TRUE);
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence    */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+  symbol *tlbl = newiTempLabel (NULL);
+
+  D(emitcode(";     genCritical",""));
+
+  if (IC_RESULT (ic))
+    aopOp (IC_RESULT (ic), ic, TRUE);
+
+  emitcode ("setb", "c");
+  emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+  emitcode ("clr", "c");
+  emitcode ("", "%05d$:", (tlbl->key + 100));
+
+  if (IC_RESULT (ic))
+    outBitC (IC_RESULT (ic)); /* save old ea in an operand */
+  else
+    emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
+
+  if (IC_RESULT (ic))
+    freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence   */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+  D(emitcode(";     genEndCritical",""));
+
+  if (IC_RIGHT (ic))
+    {
+      aopOp (IC_RIGHT (ic), ic, FALSE);
+      if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+        {
+         emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
+          emitcode ("mov", "ea,c");
+        }
+      else
+        {
+          MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
+          emitcode ("rrc", "a");
+          emitcode ("mov", "ea,c");
+        }
+      freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+    }
+  else
+    {
+      emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
+      emitcode ("mov", "ea,c");
+    }
 }
 
 /*-----------------------------------------------------------------*/
@@ -8997,7 +9761,9 @@ gen51Code (iCode * lic)
 {
   iCode *ic;
   int cln = 0;
+  /* int cseq = 0; */
 
+  _G.currentFunc = NULL;
   lineHead = lineCurr = NULL;
 
   /* print the allocation information */
@@ -9024,7 +9790,7 @@ gen51Code (iCode * lic)
   for (ic = lic; ic; ic = ic->next)
     {
       _G.current_iCode = ic;
-      
+
       if (ic->lineno && cln != ic->lineno)
        {
          if (options.debug)
@@ -9036,18 +9802,25 @@ gen51Code (iCode * lic)
              _G.debugLine = 0;
            }
          if (!options.noCcodeInAsm) {
-           emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno, 
+           emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
                      printCLine(ic->filename, ic->lineno));
          }
          cln = ic->lineno;
        }
+      #if 0
+      if (ic->seqPoint && ic->seqPoint != cseq)
+        {
+         emitcode ("", "; sequence point %d", ic->seqPoint);
+         cseq = ic->seqPoint;
+       }
+      #endif
       if (options.iCodeInAsm) {
        char regsInUse[80];
        int i;
 
        for (i=0; i<8; i++) {
          sprintf (&regsInUse[i],
-                  "%c", ic->riu & (1<<i) ? i+'0' : '-'); 
+                  "%c", ic->riu & (1<<i) ? i+'0' : '-');
        }
        regsInUse[i]=0;
        emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
@@ -9247,6 +10020,18 @@ gen51Code (iCode * lic)
          genDummyRead (ic);
          break;
 
+       case CRITICAL:
+         genCritical (ic);
+         break;
+
+       case ENDCRITICAL:
+         genEndCritical (ic);
+         break;
+
+       case SWAP:
+         genSwap (ic);
+         break;
+
        default:
          ic = ic;
        }