Improved caching of pointers and division
[fw/sdcc] / src / z80 / gen.c
index e218d9b0a280808669268326217e1266863bf0a4..b45d7a8516c2fe621b1cb7e75ce53458700e8f8e 100644 (file)
 #include <string.h>
 #include <ctype.h>
 
-#if defined(__BORLANDC__) || defined(_MSC_VER)
-#define STRCASECMP stricmp
-#else
-#define STRCASECMP strcasecmp
-#endif
-
 #include "z80.h"
 #include "SDCCglobl.h"
 #include "SDCCpeeph.h"
@@ -128,16 +122,16 @@ enum
 };
 
 static char *_z80_return[] =
-{"l", "h", "e", "d"};
+  {"l", "h", "e", "d"};
 static char *_gbz80_return[] =
-{"e", "d", "l", "h"};
+  {"e", "d", "l", "h"};
 static char *_fReceive[] =
   { "c", "b", "e", "d" };
 
 static char **_fReturn;
 static char **_fTmp;
 
-extern FILE *codeOutFile;
+extern struct dbuf_s *codeOutBuf;
 
 enum
   {
@@ -388,7 +382,7 @@ _tidyUp (char *buf)
 }
 
 static lineNode *
-_newLineNode (char *line)
+_newLineNode (const char *line)
 {
   lineNode *pl;
 
@@ -401,9 +395,14 @@ _newLineNode (char *line)
 static void
 _vemit2 (const char *szFormat, va_list ap)
 {
-  char buffer[INITIAL_INLINEASM];
+  struct dbuf_s dbuf;
+  char *buffer;
+
+  dbuf_init(&dbuf, INITIAL_INLINEASM);
+
+  dbuf_tvprintf (&dbuf, szFormat, ap);
 
-  tvsprintf (buffer, sizeof(buffer), szFormat, ap);
+  buffer = (char *)dbuf_c_str(&dbuf);
 
   _tidyUp (buffer);
   _G.lines.current = (_G.lines.current ?
@@ -413,6 +412,9 @@ _vemit2 (const char *szFormat, va_list ap)
   _G.lines.current->isInline = _G.lines.isInline;
   _G.lines.current->isDebug = _G.lines.isDebug;
   _G.lines.current->ic = _G.current_iCode;
+  _G.lines.current->isComment = (*buffer == ';');
+
+  dbuf_destroy(&dbuf);
 }
 
 static void
@@ -430,6 +432,8 @@ emit2 (const char *szFormat,...)
 static void
 emitDebug (const char *szFormat,...)
 {
+  if (!options.verboseAsm)
+    return;
   if (!DISABLE_DEBUG)
     {
       va_list ap;
@@ -699,9 +703,12 @@ _push (PAIR_ID pairId)
 static void
 _pop (PAIR_ID pairId)
 {
-  emit2 ("pop %s", _pairs[pairId].name);
-  _G.stack.pushed -= 2;
-  spillPair (pairId);
+  if (pairId != PAIR_INVALID)
+    {
+      emit2 ("pop %s", _pairs[pairId].name);
+      _G.stack.pushed -= 2;
+      spillPair (pairId);
+    }
 }
 
 void
@@ -1255,7 +1262,7 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
         /* otherwise it is fairly simple */
         if (!IS_FLOAT (val->type))
           {
-            unsigned long v = (unsigned long) floatFromVal (val);
+            unsigned long v = ulFromVal (val);
 
             if (offset == 2)
               {
@@ -1378,28 +1385,62 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
     {
       if (pairId == PAIR_HL || pairId == PAIR_IY)
         {
-          if (_G.pairs[pairId].last_type == left->type)
+          if ((_G.pairs[pairId].last_type == AOP_IMMD && left->type == AOP_IMMD) ||
+            (_G.pairs[pairId].last_type == AOP_IY && left->type == AOP_IY))
             {
               if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
                 {
                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
                     {
                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
-                      return;
+                      goto adjusted;
                     }
                   if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
                     {
-                      return;
+                       goto adjusted;
                     }
                 }
             }
         }
+
+      if (pairId == PAIR_HL && left->type == AOP_LIT && _G.pairs[pairId].last_type == AOP_LIT &&
+        !IS_FLOAT (left->aopu.aop_lit->type) && offset == 0 && _G.pairs[pairId].offset == 0)
+        {
+          unsigned new_low, new_high, old_low, old_high;
+          unsigned long v_new = ulFromVal (left->aopu.aop_lit);
+          unsigned long v_old = strtoul (_G.pairs[pairId].base, NULL, 0);
+          new_low = (v_new >> 0) & 0xff;
+          new_high = (v_new >> 8) & 0xff;
+          old_low = (v_old >> 0) & 0xff;
+          old_high = (v_old >> 8) & 0xff;
+
+          /* Change lower byte only. */
+          if(new_high == old_high)
+            {
+              emit2("ld l, %s", aopGet (left, 0, FALSE));
+              goto adjusted;
+            }
+          /* Change upper byte only. */
+          else if(new_low == old_low)
+            {
+              emit2("ld h, %s", aopGet (left, 1, FALSE));
+              goto adjusted;
+            }
+        }
+
+
       _G.pairs[pairId].last_type = left->type;
       _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
       _G.pairs[pairId].offset = offset;
     }
   /* Both a lit on the right and a true symbol on the left */
   emit2 ("ld %s,!hashedstr", pair, l);
+  return;
+
+adjusted:
+  _G.pairs[pairId].last_type = left->type;
+  _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
+  _G.pairs[pairId].offset = offset;
 }
 
 static PAIR_ID
@@ -1503,8 +1544,18 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
           }
         else
           {
-            emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
-            emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
+            /* Operand resides (partially) in the pair */
+            if(!strcmp(aopGet (aop, offset + 1, FALSE), _pairs[pairId].l))
+              {
+                emit2 ("ld a,%s", aopGet (aop, offset + 1, FALSE));
+                emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
+                emit2 ("ld %s,a", _pairs[pairId].h);
+              }
+            else
+              {
+                emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
+                emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
+              }
           }
         /* PENDING: check? */
         if (pairId == PAIR_HL)
@@ -1632,10 +1683,19 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset)
   _G.pairs[pairId].last_type = aop->type;
 }
 
+/* Can be used for local labels where Code generation takes care of spilling */
+static void
+emitLabelNoSpill (int key)
+{
+  emit2 ("!tlabeldef", key);
+  _G.lines.current->isLabel = 1;
+}
+
 static void
 emitLabel (int key)
 {
   emit2 ("!tlabeldef", key);
+  _G.lines.current->isLabel = 1;
   spillCached ();
 }
 
@@ -1801,11 +1861,9 @@ aopGet (asmop * aop, int offset, bool bit16)
     case AOP_PAIRPTR:
       setupPair (aop->aopu.aop_pairId, aop, offset);
       if (aop->aopu.aop_pairId==PAIR_IX)
-        SNPRINTF (buffer, sizeof(buffer),
-                  "!*ixx", 0);
+        tsprintf (buffer, sizeof(buffer), "!*ixx", offset);
       else if (aop->aopu.aop_pairId==PAIR_IY)
-        SNPRINTF (buffer, sizeof(buffer),
-                  "!*iyx", 0);
+        tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
       else
         SNPRINTF (buffer, sizeof(buffer),
                   "(%s)", _pairs[aop->aopu.aop_pairId].name);
@@ -2083,6 +2141,7 @@ aopPut (asmop * aop, const char *s, int offset)
 #define AOP_TYPE(op) AOP(op)->type
 #define AOP_SIZE(op) AOP(op)->size
 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
+#define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
 
 static void
 commitPair (asmop * aop, PAIR_ID id)
@@ -2223,29 +2282,22 @@ outAcc (operand * result)
 /** Take the value in carry and put it into a register
  */
 void
-outBitCLong (operand * result, bool swap_sense)
+outBitC (operand * result)
 {
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassertl (0, "Tried to write carry to a bit");
+      if (!IS_OP_RUONLY (result))
+        aopPut (AOP (result), "c", 0);
     }
   else
     {
       emit2 ("ld a,!zero");
       emit2 ("rla");
-      if (swap_sense)
-        emit2 ("xor a,!immedbyte", 1);
       outAcc (result);
     }
 }
 
-void
-outBitC (operand * result)
-{
-  outBitCLong (result, FALSE);
-}
-
 /*-----------------------------------------------------------------*/
 /* toBoolean - emit code for orl a,operator(sizeop)                */
 /*-----------------------------------------------------------------*/
@@ -2513,7 +2565,17 @@ assignResultValue (operand * oper)
     }
   else
     {
-      while (size--)
+      if ((AOP_TYPE (oper) == AOP_REG) && (AOP_SIZE (oper) == 4) &&
+          !strcmp (AOP (oper)->aopu.aop_reg[size-1]->name, _fReturn[size-2]))
+        {
+          size--;
+          _emitMove ("a", _fReturn[size-1]);
+          _emitMove (_fReturn[size-1], _fReturn[size]);
+          _emitMove (_fReturn[size], "a");
+          aopPut (AOP (oper), _fReturn[size], size-1);
+          size--;
+        }
+      while(size--)
         {
           aopPut (AOP (oper), _fReturn[size], size);
         }
@@ -2656,7 +2718,6 @@ genIpush (iCode * ic)
         {
           fetchHL (AOP (IC_LEFT (ic)));
           emit2 ("push hl");
-          spillPair (PAIR_HL);
           _G.stack.pushed += 2;
           goto release;
         }
@@ -2664,11 +2725,9 @@ genIpush (iCode * ic)
         {
           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
           emit2 ("push hl");
-          spillPair (PAIR_HL);
           _G.stack.pushed += 2;
           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
           emit2 ("push hl");
-          spillPair (PAIR_HL);
           _G.stack.pushed += 2;
           goto release;
         }
@@ -2680,13 +2739,23 @@ genIpush (iCode * ic)
               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
               wassert (l);
               emit2 ("ld a,(%s)", l);
+              emit2 ("push af");
             }
           else
             {
               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
-              emit2 ("ld a,%s", l);
+              if (!strcmp(l, "b"))
+                emit2 ("push bc");
+              else if (!strcmp(l, "d"))
+                emit2 ("push de");
+              else if (!strcmp(l, "h"))
+                emit2 ("push hl");
+              else
+                {
+                  emit2 ("ld a,%s", l);
+                  emit2 ("push af");
+                }
             }
-          emit2 ("push af");
           emit2 ("inc sp");
           _G.stack.pushed++;
         }
@@ -2899,6 +2968,7 @@ emitCall (iCode * ic, bool ispcall)
           fetchHL (AOP (IC_LEFT (ic)));
           emit2 ("jp !*hl");
           emit2 ("!tlabeldef", (rlbl->key + 100));
+          _G.lines.current->isLabel = 1;
           _G.stack.pushed -= 2;
         }
       freeAsmop (IC_LEFT (ic), NULL, ic);
@@ -2925,20 +2995,6 @@ emitCall (iCode * ic, bool ispcall)
   /* Mark the registers as restored. */
   _G.saves.saved = FALSE;
 
-  /* if we need assign a result value */
-  if ((IS_ITEMP (IC_RESULT (ic)) &&
-       (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
-        OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
-      IS_TRUE_SYMOP (IC_RESULT (ic)))
-    {
-
-      aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
-
-      assignResultValue (IC_RESULT (ic));
-
-      freeAsmop (IC_RESULT (ic), NULL, ic);
-    }
-
   /* adjust the stack for parameters if required */
   if (ic->parmBytes)
     {
@@ -2973,6 +3029,19 @@ emitCall (iCode * ic, bool ispcall)
         }
     }
 
+  /* if we need assign a result value */
+  if ((IS_ITEMP (IC_RESULT (ic)) &&
+       (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
+        OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
+      IS_TRUE_SYMOP (IC_RESULT (ic)))
+    {
+      aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+
+      assignResultValue (IC_RESULT (ic));
+
+      freeAsmop (IC_RESULT (ic), NULL, ic);
+    }
+
   spillCached ();
   if (IC_RESULT (ic))
     {
@@ -3112,8 +3181,10 @@ genFunction (iCode * ic)
     {
       sprintf (buffer, "%s_start", sym->rname);
       emit2 ("!labeldef", buffer);
+      _G.lines.current->isLabel = 1;
     }
   emit2 ("!functionlabeldef", sym->rname);
+  _G.lines.current->isLabel = 1;
 
   ftype = operandType (IC_LEFT (ic));
 
@@ -3242,7 +3313,22 @@ genFunction (iCode * ic)
   else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
     emit2 ("!enterxl", sym->stack);
   else if (sym->stack)
-    emit2 ("!enterx", sym->stack);
+    {
+      if ((optimize.codeSize && sym->stack <= 8) || sym->stack <= 4)
+        {
+          int stack = sym->stack;
+          emit2 ("!enter");
+          while (stack > 1)
+            {
+              emit2 ("push af");
+              stack -= 2;
+            }
+          if(stack > 0)
+            emit2 ("dec sp");
+        }
+      else
+        emit2 ("!enterx", sym->stack);
+    }
   else
     emit2 ("!enter");
 
@@ -3329,9 +3415,10 @@ genEndFunction (iCode * ic)
               emit2 ("pop af");
               //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
               //don't enable interrupts as they were off before
-              emit2 ("jp po,!tlabel", tlbl->key + 100);
+              emit2 ("jp PO,!tlabel", tlbl->key + 100);
               emit2 ("!ei");
               emit2 ("!tlabeldef", (tlbl->key + 100));
+              _G.lines.current->isLabel = 1;
             }
         }
     }
@@ -3359,6 +3446,7 @@ genEndFunction (iCode * ic)
     {
       sprintf (buffer, "%s_end", sym->rname);
       emit2 ("!labeldef", buffer);
+      _G.lines.current->isLabel = 1;
     }
 
   _G.flushStatics = 1;
@@ -3476,7 +3564,7 @@ genPlusIncr (iCode * ic)
 
   emitDebug ("; genPlusIncr");
 
-  icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+  icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
 
   /* If result is a pair */
   if (resultId != PAIR_INVALID)
@@ -3547,10 +3635,10 @@ genPlusIncr (iCode * ic)
           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
           if (size)
             {
-              emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+              emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
             }
         }
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
       return TRUE;
     }
 
@@ -3600,9 +3688,9 @@ outBitAcc (operand * result)
     }
   else
     {
-      emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
+      emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
       emit2 ("ld a,!one");
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
       outAcc (result);
     }
 }
@@ -3749,8 +3837,6 @@ genPlus (iCode * ic)
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
-  emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
-
   size = getDataSize (IC_RESULT (ic));
 
   /* Special case when left and right are constant */
@@ -3812,7 +3898,16 @@ genPlus (iCode * ic)
     {
       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
-      spillCached();
+      spillPair (PAIR_HL);
+      commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+      goto release;
+    }
+
+  if (isPair (AOP (IC_LEFT (ic))) && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
+    {
+      fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+      emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+      spillPair (PAIR_HL);
       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
       goto release;
     }
@@ -3890,28 +3985,62 @@ genPlus (iCode * ic)
 
   setupToPreserveCarry (ic);
 
-  while (size--)
+  /* This is ugly, but it fixes the worst code generation bug on Z80. */
+  /* Probably something similar has to be done for addition of larger numbers, too. */
+  if(size == 2)
     {
-      if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
+      _moveA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
+      emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), 0, FALSE));
+      if(strcmp (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), aopGet (AOP (IC_LEFT (ic)), 1, FALSE)))
         {
-          _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
-          if (offset == 0)
-            emit2 ("add a,%s",
-                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-          else
-            emit2 ("adc a,%s",
-                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+          aopPut (AOP (IC_RESULT (ic)), "a", 0);
+          _moveA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
         }
       else
         {
-          _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
-          if (offset == 0)
-            emit2 ("add a,%s",
-                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+          emitDebug ("; Addition result is in same register as operand of next addition.");
+          if(strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'c') ||
+             strchr (aopGet (AOP (IC_RESULT (ic)), 0, FALSE), 'b') )
+            {
+              emit2 ("push de");
+              emit2 ("ld e, a");
+              emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
+              emit2 ("ld d, a");
+              emit2 ("ld a, e");
+              emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
+              emit2 ("ld a, d");
+              emit2 ("pop de");
+            }
           else
-            emit2 ("adc a,%s",
-                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+            {
+              emit2 ("push bc");
+              emit2 ("ld c, a");
+              emit2 ("ld a, %s", aopGet (AOP (IC_LEFT (ic)), 1, FALSE));
+              emit2 ("ld b, a");
+              emit2 ("ld a, c");
+              emit2 ("ld %s, a", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
+              emit2 ("ld a, b");
+              emit2 ("pop bc");
+            }
+
         }
+      emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), 1, FALSE));
+      aopPut (AOP (IC_RESULT (ic)), "a", 1);
+      goto release;
+    }
+
+  while (size--)
+    {
+      _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+      if (offset == 0)
+      {
+        if(size == 0 && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) == 1)
+          emit2 ("inc a");
+        else
+          emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+      }
+      else
+        emit2 ("adc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
     }
 
@@ -3938,7 +4067,7 @@ genMinusDec (iCode * ic)
 
   /* if the literal value of the right hand side
      is greater than 4 then it is not worth it */
-  if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
+  if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
     return FALSE;
 
   size = getDataSize (IC_RESULT (ic));
@@ -4028,7 +4157,7 @@ genMinus (iCode * ic)
     }
   else
     {
-      lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+      lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
       lit = -(long) lit;
     }
 
@@ -4104,7 +4233,12 @@ genMinus (iCode * ic)
         {
           /* first add without previous c */
           if (!offset)
-            emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
+            {
+              if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
+                emit2 ("dec a");
+              else
+                emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
+            }
           else
             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
         }
@@ -4125,6 +4259,72 @@ release:
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
+/*-----------------------------------------------------------------*/
+/* genMultChar - generates code for unsigned 8x8 multiplication    */
+/*-----------------------------------------------------------------*/
+static void
+genMultOneChar (iCode * ic)
+{
+  symbol *tlbl1, *tlbl2;
+  bool savedB = FALSE;
+
+  if(IS_GB)
+    {
+      wassertl (0, "Multiplication is handled through support function calls on gbz80");
+      return;
+    }
+
+  /* Save b into a if b is in use. */
+  if (bitVectBitValue (ic->rMask, B_IDX) &&
+    !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC))
+    {
+      emit2 ("ld a, b");
+      savedB = TRUE;
+    }
+  if (isPairInUse (PAIR_DE, ic) &&
+    !(getPairId (AOP (IC_RESULT (ic))) == PAIR_DE))
+  {
+    _push (PAIR_DE);
+    _G.stack.pushedDE = TRUE;
+  }
+
+  tlbl1 = newiTempLabel (NULL);
+  tlbl2 = newiTempLabel (NULL);
+
+  emit2 ("ld e,%s", aopGet (AOP (IC_RIGHT (ic)), LSB, FALSE));
+  emit2 ("ld h,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
+  emit2 ("ld l,#0x00");
+  emit2 ("ld d,l");
+  emit2 ("ld b,#0x08");
+  emitLabelNoSpill (tlbl1->key + 100);
+  emit2 ("add hl,hl");
+  emit2 ("jp NC,!tlabel", tlbl2->key + 100);
+  emit2 ("add hl,de");
+  emitLabelNoSpill (tlbl2->key + 100);
+  emit2 ("djnz !tlabel", tlbl1->key + 100);
+
+  spillPair(PAIR_HL);
+
+  if (IS_Z80 && _G.stack.pushedDE)
+    {
+      _pop (PAIR_DE);
+      _G.stack.pushedDE = FALSE;
+    }
+  if (savedB)
+    {
+      emit2 ("ld b, a");
+    }
+
+  if (AOP_SIZE (IC_RESULT (ic)) == 1)
+    aopPut (AOP (IC_RESULT (ic)), "l", 0);
+  else
+    commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+
+  freeAsmop (IC_LEFT (ic), NULL, ic);
+  freeAsmop (IC_RIGHT (ic), NULL, ic);
+  freeAsmop (IC_RESULT (ic), NULL, ic);
+}
+
 /*-----------------------------------------------------------------*/
 /* genMult - generates code for multiplication                     */
 /*-----------------------------------------------------------------*/
@@ -4159,9 +4359,15 @@ genMult (iCode * ic)
       IC_LEFT (ic) = t;
     }
 
+  if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
+    {
+      genMultOneChar (ic);
+      return;
+    }
+
   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
 
-  val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
+  val = (int) ulFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
   //  wassertl (val > 0, "Multiply must be positive");
   wassertl (val != 1, "Can't multiply by 1");
 
@@ -4170,7 +4376,9 @@ genMult (iCode * ic)
     _G.stack.pushedDE = TRUE;
   }
 
-  if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
+  if (byteResult)
+    emit2 ("ld a,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
+  else if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
     {
       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
       if (!byteResult)
@@ -4188,32 +4396,40 @@ genMult (iCode * ic)
 
   i = val;
 
-  /* Fully unroled version of mul.s.  Not the most efficient.
-   */
   for (count = 0; count < 16; count++)
     {
       if (count != 0 && active)
         {
-          emit2 ("add hl,hl");
+          if (byteResult)
+            emit2 ("add a,a");
+          else
+            emit2 ("add hl,hl");
         }
       if (i & 0x8000U)
         {
           if (active == FALSE)
             {
-              emit2 ("ld l,e");
-              if (!byteResult)
-                emit2 ("ld h,d");
+              if (byteResult)
+                emit2("ld e,a");
+              else
+                {
+                  emit2 ("ld l,e");
+                  emit2 ("ld h,d");
+                }
             }
           else
             {
-              emit2 ("add hl,de");
+              if (byteResult)
+                emit2 ("add a,e");
+              else
+                emit2 ("add hl,de");
             }
           active = TRUE;
         }
       i <<= 1;
     }
 
-  spillCached();
+  spillPair(PAIR_HL);
 
   if (IS_Z80 && _G.stack.pushedDE)
     {
@@ -4222,7 +4438,7 @@ genMult (iCode * ic)
     }
 
   if (byteResult)
-    aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
+    aopPut (AOP (IC_RESULT (ic)), "a", 0);
   else
     commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
 
@@ -4267,28 +4483,28 @@ genIfxJump (iCode * ic, char *jval)
       jlbl = IC_TRUE (ic);
       if (!strcmp (jval, "a"))
         {
-          inst = "nz";
+          inst = "NZ";
         }
       else if (!strcmp (jval, "c"))
         {
-          inst = "c";
+          inst = "C";
         }
       else if (!strcmp (jval, "nc"))
         {
-          inst = "nc";
+          inst = "NC";
         }
       else if (!strcmp (jval, "m"))
         {
-          inst = "m";
+          inst = "M";
         }
       else if (!strcmp (jval, "p"))
         {
-          inst = "p";
+          inst = "P";
         }
       else
         {
           /* The buffer contains the bit on A that we should test */
-          inst = "nz";
+          inst = "NZ";
         }
     }
   else
@@ -4297,28 +4513,28 @@ genIfxJump (iCode * ic, char *jval)
       jlbl = IC_FALSE (ic);
       if (!strcmp (jval, "a"))
         {
-          inst = "z";
+          inst = "Z";
         }
       else if (!strcmp (jval, "c"))
         {
-          inst = "nc";
+          inst = "NC";
         }
       else if (!strcmp (jval, "nc"))
         {
-          inst = "c";
+          inst = "C";
         }
       else if (!strcmp (jval, "m"))
         {
-          inst = "p";
+          inst = "P";
         }
       else if (!strcmp (jval, "p"))
         {
-          inst = "m";
+          inst = "M";
         }
       else
         {
           /* The buffer contains the bit on A that we should test */
-          inst = "z";
+          inst = "Z";
         }
     }
   /* Z80 can do a conditional long jump */
@@ -4452,7 +4668,7 @@ _getPairIdName (PAIR_ID id)
         {
           if (AOP_TYPE (right) == AOP_LIT)
             {
-              lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+              lit = ulFromVal (AOP (right)->aopu.aop_lit);
               /* optimize if(x < 0) or if(x >= 0) */
               if (lit == 0L)
                 {
@@ -4483,8 +4699,7 @@ _getPairIdName (PAIR_ID id)
               bool fDidXor = FALSE;
               if (AOP_TYPE (left) == AOP_LIT)
                 {
-                  unsigned long lit = (unsigned long)
-                  floatFromVal (AOP (left)->aopu.aop_lit);
+                  unsigned long lit = ulFromVal (AOP (left)->aopu.aop_lit);
                   emit2 ("ld %s,!immedbyte", _fTmp[0],
                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
                 }
@@ -4497,8 +4712,7 @@ _getPairIdName (PAIR_ID id)
                 }
               if (AOP_TYPE (right) == AOP_LIT)
                 {
-                  unsigned long lit = (unsigned long)
-                  floatFromVal (AOP (right)->aopu.aop_lit);
+                  unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
                   emit2 ("ld %s,!immedbyte", _fTmp[1],
                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
                 }
@@ -4541,7 +4755,6 @@ genCmp (operand * left, operand * right,
 {
   int size, offset = 0;
   unsigned long lit = 0L;
-  bool swap_sense = FALSE;
 
   /* if left & right are bit variables */
   if (AOP_TYPE (left) == AOP_CRY &&
@@ -4582,7 +4795,7 @@ genCmp (operand * left, operand * right,
 
       if (AOP_TYPE (right) == AOP_LIT)
         {
-          lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+          lit = ulFromVal (AOP (right)->aopu.aop_lit);
           /* optimize if(x < 0) or if(x >= 0) */
           if (lit == 0)
             {
@@ -4608,7 +4821,7 @@ genCmp (operand * left, operand * right,
                         }
                       if (ifx)
                         {
-                          genIfxJump (ifx, swap_sense ? "c" : "nc");
+                          genIfxJump (ifx, "nc");
                           return;
                         }
                     }
@@ -4634,7 +4847,7 @@ release:
           /* Shift the sign bit up into carry */
           emit2 ("rlca");
         }
-      outBitCLong (result, swap_sense);
+      outBitC (result);
     }
   else
     {
@@ -4648,16 +4861,16 @@ release:
               if (IS_GB)
                 {
                   emit2 ("rlca");
-                  genIfxJump (ifx, swap_sense ? "nc" : "c");
+                  genIfxJump (ifx, "c");
                 }
               else
                 {
-                  genIfxJump (ifx, swap_sense ? "p" : "m");
+                  genIfxJump (ifx, "m");
                 }
             }
           else
             {
-              genIfxJump (ifx, swap_sense ? "nc" : "c");
+              genIfxJump (ifx, "c");
             }
         }
       else
@@ -4667,7 +4880,7 @@ release:
               /* Shift the sign bit up into carry */
               emit2 ("rlca");
             }
-          outBitCLong (result, swap_sense);
+          outBitC (result);
         }
       /* leave the result in acc */
     }
@@ -4690,13 +4903,16 @@ genCmpGt (iCode * ic, iCode * ifx)
   letype = getSpec (operandType (left));
   retype = getSpec (operandType (right));
   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
-  /* assign the amsops */
+  /* assign the asmops */
   aopOp (left, ic, FALSE, FALSE);
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
 
+  setupToPreserveCarry (ic);
+
   genCmp (right, left, result, ifx, sign);
 
+  _G.preserveCarry = FALSE;
   freeAsmop (left, NULL, ic);
   freeAsmop (right, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -4720,13 +4936,16 @@ genCmpLt (iCode * ic, iCode * ifx)
   retype = getSpec (operandType (right));
   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
 
-  /* assign the amsops */
+  /* assign the asmops */
   aopOp (left, ic, FALSE, FALSE);
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
 
+  setupToPreserveCarry (ic);
+
   genCmp (left, right, result, ifx, sign);
 
+  _G.preserveCarry = FALSE;
   freeAsmop (left, NULL, ic);
   freeAsmop (right, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -4734,8 +4953,9 @@ genCmpLt (iCode * ic, iCode * ifx)
 
 /*-----------------------------------------------------------------*/
 /* gencjneshort - compare and jump if not equal                    */
+/* returns pair that still needs to be popped                      */
 /*-----------------------------------------------------------------*/
-static void
+static PAIR_ID
 gencjneshort (operand * left, operand * right, symbol * lbl)
 {
   int size = max (AOP_SIZE (left), AOP_SIZE (right));
@@ -4750,18 +4970,13 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
       left = t;
     }
 
-  if (AOP_TYPE (right) == AOP_LIT)
-    {
-      lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
-    }
-
   /* if the right side is a literal then anything goes */
-  if (AOP_TYPE (right) == AOP_LIT &&
-      AOP_TYPE (left) != AOP_DIR)
+  if (AOP_TYPE (right) == AOP_LIT)
     {
+      lit = ulFromVal (AOP (right)->aopu.aop_lit);
       if (lit == 0)
         {
-          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+          _moveA (aopGet (AOP (left), offset, FALSE));
           if (size > 1)
             {
               while (--size)
@@ -4773,55 +4988,74 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
             {
               emit2 ("or a,a");
             }
-          emit2 ("jp nz,!tlabel", lbl->key + 100);
+          emit2 ("jp NZ,!tlabel", lbl->key + 100);
         }
       else
         {
           while (size--)
             {
-              emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
-              if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
+              _moveA (aopGet (AOP (left), offset, FALSE));
+              if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
                 emit2 ("or a,a");
               else
-                emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
-              emit2 ("jp nz,!tlabel", lbl->key + 100);
+                emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
+              emit2 ("jp NZ,!tlabel", lbl->key + 100);
               offset++;
             }
         }
     }
-  /* if the right side is in a register or in direct space or
-     if the left is a pointer register & right is not */
+  /* if the right side is in a register or
+     pointed to by HL, IX or IY */
   else if (AOP_TYPE (right) == AOP_REG ||
-           AOP_TYPE (right) == AOP_DIR ||
-           (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
+           AOP_TYPE (right) == AOP_HL  ||
+           AOP_TYPE (right) == AOP_IY  ||
+           AOP_TYPE (right) == AOP_STK ||
+           AOP_IS_PAIRPTR (right, PAIR_HL) ||
+           AOP_IS_PAIRPTR (right, PAIR_IX) ||
+           AOP_IS_PAIRPTR (right, PAIR_IY))
     {
       while (size--)
         {
           _moveA (aopGet (AOP (left), offset, FALSE));
-          if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
+          if (AOP_TYPE (right) == AOP_LIT &&
               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
-            /* PENDING */
-            emit2 ("jp nz,!tlabel", lbl->key + 100);
+            {
+              emit2 ("or a,a");
+              emit2 ("jp NZ,!tlabel", lbl->key + 100);
+            }
           else
             {
-              emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
-              emit2 ("jp nz,!tlabel", lbl->key + 100);
+              emit2 ("sub a,%s", aopGet (AOP (right), offset, FALSE));
+              emit2 ("jp NZ,!tlabel", lbl->key + 100);
             }
           offset++;
         }
     }
+  /* right is in direct space or a pointer reg, need both a & b */
   else
     {
-      /* right is a pointer reg need both a & b */
-      /* PENDING: is this required? */
+      PAIR_ID pair;
+      for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
+        {
+          if (((AOP_TYPE (left)  != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId  != pair)) &&
+              ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
+            {
+              break;
+            }
+        }
+      _push (pair);
       while (size--)
         {
+          emit2 ("; direct compare");
+          _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
           _moveA (aopGet (AOP (right), offset, FALSE));
-          emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
-          emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
+          emit2 ("sub a,%s", _pairs[pair].l);
+          emit2 ("!shortjp NZ,!tlabel", lbl->key + 100);
           offset++;
         }
+      return pair;
     }
+  return PAIR_INVALID;
 }
 
 /*-----------------------------------------------------------------*/
@@ -4832,14 +5066,15 @@ gencjne (operand * left, operand * right, symbol * lbl)
 {
   symbol *tlbl = newiTempLabel (NULL);
 
-  gencjneshort (left, right, lbl);
+  PAIR_ID pop = gencjneshort (left, right, lbl);
 
   /* PENDING: ?? */
   emit2 ("ld a,!one");
   emit2 ("!shortjp !tlabel", tlbl->key + 100);
   emitLabel (lbl->key + 100);
   emit2 ("xor a,a");
-  emitLabel (tlbl->key + 100);
+  emitLabelNoSpill (tlbl->key + 100);
+  _pop (pop);
 }
 
 /*-----------------------------------------------------------------*/
@@ -4877,21 +5112,26 @@ genCmpEq (iCode * ic, iCode * ifx)
         }
       else
         {
+          PAIR_ID pop;
           tlbl = newiTempLabel (NULL);
-          gencjneshort (left, right, tlbl);
+          pop = gencjneshort (left, right, tlbl);
           if (IC_TRUE (ifx))
             {
+              _pop (pop);
               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
-              emitLabel (tlbl->key + 100);
+              emitLabelNoSpill (tlbl->key + 100);
+              _pop (pop);
             }
           else
             {
               /* PENDING: do this better */
               symbol *lbl = newiTempLabel (NULL);
+              _pop (pop);
               emit2 ("!shortjp !tlabel", lbl->key + 100);
-              emitLabel (tlbl->key + 100);
+              emitLabelNoSpill (tlbl->key + 100);
+              _pop (pop);
               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
-              emitLabel (lbl->key + 100);
+              emitLabelNoSpill (lbl->key + 100);
             }
         }
       /* mark the icode as generated */
@@ -4984,9 +5224,9 @@ genAndOp (iCode * ic)
     {
       tlbl = newiTempLabel (NULL);
       _toBoolean (left);
-      emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
+      emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
       _toBoolean (right);
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
       outBitAcc (result);
     }
 
@@ -5021,9 +5261,9 @@ genOrOp (iCode * ic)
     {
       tlbl = newiTempLabel (NULL);
       _toBoolean (left);
-      emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+      emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
       _toBoolean (right);
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
       outBitAcc (result);
     }
 
@@ -5065,14 +5305,14 @@ jmpTrueOrFalse (iCode * ic, symbol * tlbl)
     {
       symbol *nlbl = newiTempLabel (NULL);
       emit2 ("jp !tlabel", nlbl->key + 100);
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
-      emitLabel (nlbl->key + 100);
+      emitLabelNoSpill (nlbl->key + 100);
     }
   else
     {
       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
-      emitLabel (tlbl->key + 100);
+      emitLabelNoSpill (tlbl->key + 100);
     }
   ic->generated = 1;
 }
@@ -5118,7 +5358,7 @@ genAnd (iCode * ic, iCode * ifx)
       left = tmp;
     }
   if (AOP_TYPE (right) == AOP_LIT)
-    lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    lit = ulFromVal (AOP (right)->aopu.aop_lit);
 
   size = AOP_SIZE (result);
 
@@ -5155,7 +5395,8 @@ genAnd (iCode * ic, iCode * ifx)
                   /* For the flags */
                   emit2 ("or a,a");
                 }
-              emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+          if (size || ifx)  /* emit jmp only, if it is actually used */
+              emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
             }
               offset++;
         }
@@ -5164,6 +5405,7 @@ genAnd (iCode * ic, iCode * ifx)
         {
           emit2 ("clr c");
           emit2 ("!tlabeldef", tlbl->key + 100);
+          _G.lines.current->isLabel = 1;
         }
       // if(left & literal)
       else
@@ -5308,7 +5550,7 @@ genOr (iCode * ic, iCode * ifx)
       left = tmp;
     }
   if (AOP_TYPE (right) == AOP_LIT)
-    lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    lit = ulFromVal (AOP (right)->aopu.aop_lit);
 
   size = AOP_SIZE (result);
 
@@ -5337,9 +5579,19 @@ genOr (iCode * ic, iCode * ifx)
           bytelit = (lit >> (offset * 8)) & 0x0FFL;
 
           _moveA (aopGet (AOP (left), offset, FALSE));
-          /* OR with any literal is the same as OR with itself. */
-          emit2 ("or a,a");
-          emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+          if (bytelit != 0)
+            { /* FIXME, allways true, shortcut possible */
+              emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+            }
+          else
+            {
+              /* For the flags */
+              emit2 ("or a,a");
+            }
+
+          if (ifx)  /* emit jmp only, if it is actually used */
+            emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
 
           offset++;
         }
@@ -5466,7 +5718,7 @@ genXor (iCode * ic, iCode * ifx)
       left = tmp;
     }
   if (AOP_TYPE (right) == AOP_LIT)
-    lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    lit = ulFromVal (AOP (right)->aopu.aop_lit);
 
   size = AOP_SIZE (result);
 
@@ -5494,7 +5746,7 @@ genXor (iCode * ic, iCode * ifx)
         {
           _moveA (aopGet (AOP (left), offset, FALSE));
           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
-          emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+          emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
           offset++;
         }
       if (ifx)
@@ -5592,37 +5844,49 @@ static void
 genInline (iCode * ic)
 {
   char *buffer, *bp, *bp1;
+  bool inComment = FALSE;
 
   _G.lines.isInline += (!options.asmpeep);
 
-  buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
-  strcpy (buffer, IC_INLINE (ic));
+  buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
 
   /* emit each line as a code */
   while (*bp)
     {
-      if (*bp == '\n')
+      switch (*bp)
         {
+        case ';':
+          inComment = TRUE;
+          ++bp;
+          break;
+
+        case '\n':
+          inComment = FALSE;
           *bp++ = '\0';
           emit2 (bp1);
           bp1 = bp;
-        }
-      else
-        {
-          if (*bp == ':')
+          break;
+
+        default:
+          /* Add \n for labels, not dirs such as c:\mydir */
+          if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
             {
-              bp++;
+              ++bp;
               *bp = '\0';
-              bp++;
+              ++bp;
               emit2 (bp1);
               bp1 = bp;
             }
           else
-            bp++;
+            ++bp;
+          break;
         }
     }
   if (bp1 != bp)
     emit2 (bp1);
+
+  Safe_free (buffer);
+
   _G.lines.isInline -= (!options.asmpeep);
 
 }
@@ -5707,7 +5971,7 @@ shiftR2Left2Result (operand * left, int offl,
                     int shCount, int is_signed)
 {
   int size = 2;
-  symbol *tlbl, *tlbl1;
+  symbol *tlbl;
 
   movLeft2Result (left, offl, result, offr, 0);
   movLeft2Result (left, offl + 1, result, offr + 1, 0);
@@ -5718,10 +5982,10 @@ shiftR2Left2Result (operand * left, int offl,
   /*  if (AOP(result)->type == AOP_REG) { */
 
   tlbl = newiTempLabel (NULL);
-  tlbl1 = newiTempLabel (NULL);
 
   /* Left is already in result - so now do the shift */
-  if (shCount <= 4)
+  /* Optimizing for speed by default. */
+  if (!optimize.codeSize || shCount <= 2)
     {
       while (shCount--)
         {
@@ -5730,15 +5994,14 @@ shiftR2Left2Result (operand * left, int offl,
     }
   else
     {
-      emit2 ("ld a,!immedbyte+1", shCount);
-      emit2 ("!shortjp !tlabel", tlbl1->key + 100);
-      emitLabel (tlbl->key + 100);
+      emit2 ("ld a,!immedbyte", shCount);
+
+      emitLabelNoSpill (tlbl->key + 100);
 
       emitRsh2 (AOP (result), size, is_signed);
 
-      emitLabel (tlbl1->key + 100);
       emit2 ("dec a");
-      emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+      emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
     }
 }
 
@@ -5807,7 +6070,7 @@ shiftL2Left2Result (operand * left, int offl,
           {
             emit2 ("ld a,!immedbyte+1", shCount);
             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
-            emitLabel (tlbl->key + 100);
+            emitLabelNoSpill (tlbl->key + 100);
           }
 
         while (size--)
@@ -5827,9 +6090,9 @@ shiftL2Left2Result (operand * left, int offl,
           }
         if (shCount > 1)
           {
-            emitLabel (tlbl1->key + 100);
+            emitLabelNoSpill (tlbl1->key + 100);
             emit2 ("dec a");
-            emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+            emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
           }
       }
   }
@@ -5958,13 +6221,25 @@ shiftL1Left2Result (operand * left, int offl,
                     operand * result, int offr, int shCount)
 {
   const char *l;
-  l = aopGet (AOP (left), offl, FALSE);
-  _moveA (l);
-  /* shift left accumulator */
-  AccLsh (shCount);
-  aopPut (AOP (result), "a", offr);
-}
 
+  /* If operand and result are the same we can shift in place.
+     However shifting in acc using add is cheaper than shifting
+     in place using sla; when shifting by more than 2 shifting in
+     acc is worth the additional effort for loading from/to acc. */
+  if (sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
+    {
+      while (shCount--)
+        emit2 ("sla %s", aopGet (AOP (result), 0, FALSE));
+    }
+  else
+    {
+      l = aopGet (AOP (left), offl, FALSE);
+      _moveA (l);
+      /* shift left accumulator */
+      AccLsh (shCount);
+      aopPut (AOP (result), "a", offr);
+    }
+}
 
 /*-----------------------------------------------------------------*/
 /* genlshTwo - left shift two bytes by known amount                */
@@ -6031,7 +6306,7 @@ genLeftShiftLiteral (operand * left,
                      operand * result,
                      iCode * ic)
 {
-  int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+  int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
   int size;
 
   freeAsmop (right, NULL, ic);
@@ -6134,7 +6409,7 @@ genLeftShift (iCode * ic)
      _pop (PAIR_AF);
 
   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
-  emitLabel (tlbl->key + 100);
+  emitLabelNoSpill (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
 
   while (size--)
@@ -6151,9 +6426,9 @@ genLeftShift (iCode * ic)
         }
       offset++;
     }
-  emitLabel (tlbl1->key + 100);
+  emitLabelNoSpill (tlbl1->key + 100);
   emit2 ("dec a");
-  emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+  emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
 
   freeAsmop (left, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -6288,7 +6563,7 @@ genRightShiftLiteral (operand * left,
                       iCode * ic,
                       int sign)
 {
-  int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+  int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
   int size;
 
   freeAsmop (right, NULL, ic);
@@ -6409,7 +6684,7 @@ genRightShift (iCode * ic)
      _pop (PAIR_AF);
 
   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
-  emitLabel (tlbl->key + 100);
+  emitLabelNoSpill (tlbl->key + 100);
   while (size--)
     {
       l = aopGet (AOP (result), offset--, FALSE);
@@ -6423,9 +6698,9 @@ genRightShift (iCode * ic)
           emit2 ("rr %s", l);
         }
     }
-  emitLabel (tlbl1->key + 100);
+  emitLabelNoSpill (tlbl1->key + 100);
   emit2 ("dec a");
-  emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+  emit2 ("!shortjp NZ,!tlabel", tlbl->key + 100);
 
   freeAsmop (left, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -6464,9 +6739,9 @@ genUnpackBits (operand * result, int pair)
           symbol *tlbl = newiTempLabel (NULL);
 
           emit2 ("bit %d,a", blen - 1);
-          emit2 ("jp z,!tlabel", tlbl->key + 100);
+          emit2 ("jp Z,!tlabel", tlbl->key + 100);
           emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
-          emitLabel (tlbl->key + 100);
+          emitLabelNoSpill (tlbl->key + 100);
         }
       aopPut (AOP (result), "a", offset++);
       goto finish;
@@ -6486,11 +6761,10 @@ genUnpackBits (operand * result, int pair)
         {
           /* signed bitfield */
           symbol *tlbl = newiTempLabel (NULL);
-
-          emit2 ("bit %d,a", blen - 1);
-          emit2 ("jp z,!tlabel", tlbl->key + 100);
-          emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
-          emitLabel (tlbl->key + 100);
+          emit2 ("bit %d,a", blen - 1 - 8);
+          emit2 ("jp Z,!tlabel", tlbl->key + 100);
+          emit2 ("or a,!immedbyte", (unsigned char) (0xff << (blen - 8)));
+          emitLabelNoSpill (tlbl->key + 100);
         }
       emit2 ("ld h,a");
       spillPair (PAIR_HL);
@@ -6521,9 +6795,9 @@ genUnpackBits (operand * result, int pair)
           symbol *tlbl = newiTempLabel (NULL);
 
           emit2 ("bit %d,a", rlen - 1);
-          emit2 ("jp z,!tlabel", tlbl->key + 100);
+          emit2 ("jp Z,!tlabel", tlbl->key + 100);
           emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
-          emitLabel (tlbl->key + 100);
+          emitLabelNoSpill (tlbl->key + 100);
         }
       aopPut (AOP (result), "a", offset++);
     }
@@ -6746,7 +7020,7 @@ genPackBits (sym_link * etype,
         {
           /* Case with a bitfield length <8 and literal source
           */
-          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
           litval <<= bstr;
           litval &= (~mask) & 0xff;
           emit2 ("ld a,!*pair", _pairs[pair].name);
@@ -6811,7 +7085,7 @@ genPackBits (sym_link * etype,
         {
           /* Case with partial byte and literal source
           */
-          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
           litval >>= (blen-rlen);
           litval &= (~mask) & 0xff;
           emit2 ("ld a,!*pair", _pairs[pair].name);
@@ -7067,7 +7341,7 @@ genAddrOf (iCode * ic)
     {
       if (sym->onStack)
         {
-          spillCached ();
+          spillPair (PAIR_HL);
           if (sym->stack <= 0)
             {
               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
@@ -7086,7 +7360,7 @@ genAddrOf (iCode * ic)
     }
   else
     {
-      spillCached ();
+      spillPair (PAIR_HL);
       if (sym->onStack)
         {
           /* if it has an offset  then we need to compute it */
@@ -7147,7 +7421,7 @@ genAssign (iCode * ic)
 
   if (AOP_TYPE (right) == AOP_LIT)
     {
-      lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+      lit = ulFromVal (AOP (right)->aopu.aop_lit);
     }
 
   if (isPair (AOP (result)))
@@ -7266,7 +7540,7 @@ genJumpTab (iCode * ic)
   emit2 ("ld e,%s", l);
   emit2 ("ld d,!zero");
   jtab = newiTempLabel (NULL);
-  spillCached ();
+  spillPair (PAIR_HL);
   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
   emit2 ("add hl,de");
   emit2 ("add hl,de");
@@ -7351,8 +7625,7 @@ genCast (iCode * ic)
   else
     {
       /* we need to extend the sign :{ */
-        const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
-                        FALSE);
+      const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE);
       _moveA (l);
       emit2 ("rla ");
       emit2 ("sbc a,a");
@@ -7461,9 +7734,10 @@ genCritical (iCode *ic)
       //disable interrupt
       emit2 ("!di");
       //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
-      emit2 ("jp po,!tlabel", tlbl->key + 100);
+      emit2 ("jp PO,!tlabel", tlbl->key + 100);
       aopPut (AOP (IC_RESULT (ic)), "!one", 0);
       emit2 ("!tlabeldef", (tlbl->key + 100));
+      _G.lines.current->isLabel = 1;
       freeAsmop (IC_RESULT (ic), NULL, ic);
     }
   else
@@ -7473,7 +7747,7 @@ genCritical (iCode *ic)
       //disable interrupt
       emit2 ("!di");
       //save P/O flag
-      emit2 ("push af");
+      _push (PAIR_AF);
     }
 }
 
@@ -7494,7 +7768,7 @@ genEndCritical (iCode *ic)
       aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
       _toBoolean (IC_RIGHT (ic));
       //don't enable interrupts if they were off before
-      emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
+      emit2 ("!shortjp Z,!tlabel", tlbl->key + 100);
       emit2 ("!ei");
       emitLabel (tlbl->key + 100);
       freeAsmop (IC_RIGHT (ic), NULL, ic);
@@ -7502,12 +7776,13 @@ genEndCritical (iCode *ic)
   else
     {
       //restore P/O flag
-      emit2 ("pop af");
+      _pop (PAIR_AF);
       //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
       //don't enable interrupts as they were off before
-      emit2 ("jp po,!tlabel", tlbl->key + 100);
+      emit2 ("jp PO,!tlabel", tlbl->key + 100);
       emit2 ("!ei");
       emit2 ("!tlabeldef", (tlbl->key + 100));
+      _G.lines.current->isLabel = 1;
     }
 }
 
@@ -7778,67 +8053,12 @@ _swap (PAIR_ID one, PAIR_ID two)
     }
 }
 
-/* The problem is that we may have all three pairs used and they may
-   be needed in a different order.
-
-   Note: Have ex de,hl
-
-   Combinations:
-     hl = hl            => unity, fine
-     bc = bc
-     de = de
-
-     hl = hl            hl = hl, swap de <=> bc
-     bc = de
-     de = bc
-
-     hl = bc            Worst case
-     bc = de
-     de = hl
-
-     hl = bc            de = de, swap bc <=> hl
-     bc = hl
-     de = de
-
-     hl = de            Worst case
-     bc = hl
-     de = bc
-
-     hl = de            bc = bc, swap hl <=> de
-     bc = bc
-     de = hl
-
-   Break it down into:
-    * Any pair = pair are done last
-    * Any pair = iTemp are done last
-    * Any swaps can be done any time
-
-   A worst case:
-    push p1
-    p1 = p2
-    p2 = p3
-    pop  p3
-
-   So how do we detect the cases?
-   How about a 3x3 matrix?
-        source
-   dest x x x x
-        x x x x
-        x x x x (Fourth for iTemp/other)
-
-   First determin which mode to use by counting the number of unity and
-   iTemp assigns.
-     Three - any order
-     Two - Assign the pair first, then the rest
-     One - Swap the two, then the rest
-     Zero - Worst case.
-*/
 static void
-setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
+setupForMemcpy (iCode *ic, int nparams, operand **pparams)
 {
   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
   PAIR_ID dest[3] = {
-    PAIR_BC, PAIR_HL, PAIR_DE
+    PAIR_DE, PAIR_HL, PAIR_BC
   };
   int i, j, nunity = 0;
   memset (ids, PAIR_INVALID, sizeof (ids));
@@ -7846,10 +8066,6 @@ setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
   /* Sanity checks */
   wassert (nparams == 3);
 
-  /* First save everything that needs to be saved. */
-  _saveRegsForCall (ic, 0);
-
-  /* Loading HL first means that DE is always fine. */
   for (i = 0; i < nparams; i++)
     {
       aopOp (pparams[i], ic, FALSE, FALSE);
@@ -7871,7 +8087,7 @@ setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
     }
   else if (nunity == 2)
     {
-      /* One is assigned.  Pull it out and assign. */
+      /* Two are OK.  Assign the other one. */
       for (i = 0; i < 3; i++)
         {
           for (j = 0; j < NUM_PAIRS; j++)
@@ -7894,7 +8110,7 @@ setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
     }
   else if (nunity == 1)
     {
-      /* Find the pairs to swap. */
+      /* One is OK. Find the other two. */
       for (i = 0; i < 3; i++)
         {
           for (j = 0; j < NUM_PAIRS; j++)
@@ -7903,12 +8119,22 @@ setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
                 {
                   if (j == PAIR_INVALID || j == dest[i])
                     {
-                      /* Keep looking. */
+                      /* This one is OK. */
                     }
                   else
                     {
-                      _swap (j, dest[i]);
-                      goto done;
+                      /* Found one. */
+                      if(ids[j][dest[i]] == TRUE)
+                        {
+                          /* Just swap. */
+                           _swap (j, dest[i]);
+                           goto done;
+                        }
+                      else
+                        {
+                          fetchPair (dest[i], AOP (pparams[i]));
+                          continue;
+                        }
                     }
                 }
             }
@@ -7942,53 +8168,27 @@ setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
     }
 }
 
-static void
-genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
-{
-  operand *from, *to;
-  symbol *label;
-  bool deInUse;
-
-  wassertl (nParams == 2, "Built-in strcpy must have two parameters");
-  to = pparams[0];
-  from = pparams[1];
-
-  deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
-
-  setupForBuiltin3 (ic, nParams, pparams);
-
-  label = newiTempLabel(NULL);
-
-  emitLabel (label->key);
-  emit2 ("ld a,(hl)");
-  emit2 ("ldi");
-  emit2 ("or a");
-  emit2 ("!shortjp nz,!tlabel ; 1", label->key);
-
-  freeAsmop (from, NULL, ic->next);
-  freeAsmop (to, NULL, ic);
-}
-
 static void
 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
 {
   operand *from, *to, *count;
-  bool deInUse;
 
-  wassertl (nParams == 3, "Built-in memcpy must have two parameters");
+  wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
   to = pparams[2];
   from = pparams[1];
   count = pparams[0];
 
-  deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+  _saveRegsForCall (ic, 0);
 
-  setupForBuiltin3 (ic, nParams, pparams);
+  setupForMemcpy (ic, nParams, pparams);
 
   emit2 ("ldir");
 
   freeAsmop (count, NULL, ic->next->next);
   freeAsmop (from, NULL, ic);
 
+  spillPair (PAIR_HL);
+
   _restoreRegsAfterCall();
 
   /* if we need assign a result value */
@@ -8022,11 +8222,7 @@ static void genBuiltIn (iCode *ic)
     /* which function is it */
     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
 
-    if (strcmp(bif->name,"__builtin_strcpy")==0)
-      {
-        genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
-      }
-    else if (strcmp(bif->name,"__builtin_memcpy")==0)
+    if (strcmp(bif->name,"__builtin_memcpy")==0)
       {
         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
       }
@@ -8084,7 +8280,9 @@ genZ80Code (iCode * lic)
         }
       if (options.iCodeInAsm)
         {
-          emit2 (";ic:%d: %s", ic->key, printILine(ic));
+          const char *iLine = printILine(ic);
+          emit2 (";ic:%d: %s", ic->key, iLine);
+          dbuf_free(iLine);
         }
       /* if the result is marked as
          spilt and rematerializable or code for
@@ -8121,7 +8319,7 @@ genZ80Code (iCode * lic)
              spilt live range, if there is an ifx statement
              following this pop then the if statement might
              be using some of the registers being popped which
-             would destory the contents of the register so
+             would destroy the contents of the register so
              we need to check for this condition and handle it */
           if (ic->next &&
               ic->next->op == IFX &&
@@ -8368,16 +8566,16 @@ genZ80Code (iCode * lic)
   /* This is unfortunate */
   /* now do the actual printing */
   {
-    FILE *fp = codeOutFile;
-    if (isInHome () && codeOutFile == code->oFile)
-      codeOutFile = home->oFile;
-    printLine (_G.lines.head, codeOutFile);
+    struct dbuf_s *buf = codeOutBuf;
+    if (isInHome () && codeOutBuf == &code->oBuf)
+      codeOutBuf = &home->oBuf;
+    printLine (_G.lines.head, codeOutBuf);
     if (_G.flushStatics)
       {
         flushStatics ();
         _G.flushStatics = 0;
       }
-    codeOutFile = fp;
+    codeOutBuf = buf;
   }
 
   freeTrace(&_G.lines.trace);
@@ -8413,7 +8611,7 @@ fetchLitSpecial (asmop * aop, bool negate, bool xor)
   wassert (aop->type == AOP_LIT);
   wassert (!IS_FLOAT (val->type));
 
-  v = (unsigned long) floatFromVal (val);
+  v = ulFromVal (val);
 
   if (xor)
     v ^= 0x8000;