2001-10-21 Michael Hope <michaelh@juju.net.nz>
[fw/sdcc] / src / z80 / gen.c
index 298ffcb47132dbf61ad4cf61fccf6231228d2a79..6719b734fd9af3a0cd3e4c2bff264f137d5f7e14 100644 (file)
 enum 
 {
   /* Set to enable debugging trace statements in the output assembly code. */
-  DISABLE_DEBUG = 0,
+  DISABLE_DEBUG = 0
 };
 
 static char *_z80_return[] =
@@ -135,6 +135,12 @@ static char **_fTmp;
 
 extern FILE *codeOutFile;
 
+enum
+  {
+    INT8MIN = -128,
+    INT8MAX = 127
+  };
+
 /** Enum covering all the possible register pairs.
  */
 typedef enum
@@ -479,6 +485,14 @@ isPtrPair (asmop * aop)
       return FALSE;
     }
 }
+
+static void
+spillPair (PAIR_ID pairId)
+{
+  _G.pairs[pairId].last_type = AOP_INVALID;
+  _G.pairs[pairId].base = NULL;
+}
+
 /** Push a register pair onto the stack */
 void
 genPairPush (asmop * aop)
@@ -498,6 +512,7 @@ _pop (PAIR_ID pairId)
 {
   emit2 ("pop %s", _pairs[pairId].name);
   _G.stack.pushed -= 2;
+  spillPair (pairId);
 }
 
 /*-----------------------------------------------------------------*/
@@ -536,10 +551,10 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
   if (sym->onStack || sym->iaccess)
     {
       /* The pointer that is used depends on how big the offset is.
-         Normally everything is AOP_STK, but for offsets of < -127 or
-         > 128 on the Z80 an extended stack pointer is used.
+         Normally everything is AOP_STK, but for offsets of < -128 or
+         > 127 on the Z80 an extended stack pointer is used.
       */
-      if (IS_Z80 && (options.ommitFramePtr || sym->stack < -127 || sym->stack > (int)(128-getSize (sym->type))))
+      if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
         {
           emitDebug ("; AOP_EXSTK for %s", sym->rname);
           sym->aop = aop = newAsmop (AOP_EXSTK);
@@ -1031,13 +1046,6 @@ adjustPair (const char *pair, int *pold, int new)
     }
 }
 
-static void
-spillPair (PAIR_ID pairId)
-{
-  _G.pairs[pairId].last_type = AOP_INVALID;
-  _G.pairs[pairId].base = NULL;
-}
-
 static void
 spillCached (void)
 {
@@ -1082,7 +1090,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
                      adjustPair (pair, &_G.pairs[pairId].offset, offset);
                      return;
                    }
-                 if (pairId == PAIR_IY && abs (offset) < 127)
+                 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
                    {
                      return;
                    }
@@ -1158,6 +1166,22 @@ fetchHL (asmop * aop)
   fetchPair (PAIR_HL, aop);
 }
 
+static void
+setupPairFromSP (PAIR_ID id, int offset)
+{
+  wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
+
+  if (offset < INT8MIN || offset > INT8MAX)
+    {
+      emit2 ("ld hl,!immedword", offset);
+      emit2 ("add hl,sp");
+    }
+  else
+    {
+      emit2 ("!ldahlsp", offset);
+    }
+}
+
 static void
 setupPair (PAIR_ID pairId, asmop * aop, int offset)
 {
@@ -1215,7 +1239,7 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset)
          }
        else
          {
-           emit2 ("!ldahlsp", abso + _G.stack.pushed);
+            setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
          }
        _G.pairs[pairId].offset = abso;
        break;
@@ -2381,10 +2405,11 @@ emitCall (iCode * ic, bool ispcall)
              if (i)
                emit2 ("inc sp");
            }
-         spillCached ();
        }
     }
 
+  spillCached ();
+
   if (_G.stack.pushedDE) 
     {
       bool dInUse = bitVectBitValue(rInUse, D_IDX);
@@ -2579,7 +2604,9 @@ genFunction (iCode * ic)
   /* adjust the stack for the function */
   _G.stack.last = sym->stack;
 
-  if (sym->stack)
+  if (sym->stack && IS_GB && sym->stack > -INT8MIN)
+    emit2 ("!enterxl", sym->stack);
+  else if (sym->stack)
     emit2 ("!enterx", sym->stack);
   else
     emit2 ("!enter");
@@ -2605,7 +2632,11 @@ genEndFunction (iCode * ic)
 
       /* PENDING: calleeSave */
 
-      if (_G.stack.offset)
+      if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
+        {
+          emit2 ("!leavexl", _G.stack.offset);
+        }
+      else if (_G.stack.offset)
         {
           emit2 ("!leavex", _G.stack.offset);
         }
@@ -2862,7 +2893,7 @@ couldDestroyCarry (asmop *aop)
 static void
 shiftIntoPair (int idx, asmop *aop)
 {
-  PAIR_ID id;
+  PAIR_ID id = PAIR_INVALID;
 
   wassertl (IS_Z80, "Only implemented for the Z80");
   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
@@ -3009,6 +3040,15 @@ genPlus (iCode * ic)
       goto release;
     }
 
+  if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
+    {
+      fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+      emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+      spillCached();
+      commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+      goto release;
+    }
+
   /* Special case:
      ld hl,sp+n trashes C so we cant afford to do it during an
      add with stack based varibles.  Worst case is:
@@ -3320,8 +3360,92 @@ release:
 static void
 genMult (iCode * ic)
 {
+  int val;
+  int count, i;
+  /* If true then the final operation should be a subtract */
+  bool active = FALSE;
+
   /* Shouldn't occur - all done through function calls */
-  wassertl (0, "Multiplication is handled through support function calls");
+  aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
+  aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+  aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+  if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
+      AOP_SIZE (IC_RIGHT (ic)) > 2 ||
+      AOP_SIZE (IC_RESULT (ic)) > 2)
+    {
+      wassertl (0, "Multiplication is handled through support function calls");
+    }
+
+  /* Swap left and right such that right is a literal */
+  if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
+    {
+      operand *t = IC_RIGHT (ic);
+      IC_RIGHT (ic) = IC_LEFT (ic);
+      IC_LEFT (ic) = t;
+    }
+
+  wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
+
+  val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
+  //  wassertl (val > 0, "Multiply must be positive");
+  wassertl (val != 1, "Can't multiply by 1");
+
+  if (IS_Z80) {
+    _push (PAIR_DE);
+  }
+
+  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));
+      emit2 ("ld a,e");
+      emit2 ("rlc a");
+      emit2 ("sbc a,a");
+      emit2 ("ld d,a");
+    }
+  else
+    {
+      fetchPair (PAIR_DE, AOP (IC_LEFT (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 (i & 0x8000U)
+        {
+          if (active == FALSE)
+            {
+              emit2 ("ld l,e");
+              emit2 ("ld h,d");
+            }
+          else
+            {
+              emit2 ("add hl,de");
+            }
+          active = TRUE;
+        }
+      i <<= 1;
+    }
+
+  spillCached();
+
+  if (IS_Z80)
+    {
+      _pop (PAIR_DE);
+    }
+
+  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);
 }
 
 /*-----------------------------------------------------------------*/
@@ -3733,11 +3857,9 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
          if (size > 1)
            {
-             size--;
-             offset++;
-             while (size--)
+             while (--size)
                {
-                 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
+                 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
                }
            }
          else
@@ -5568,21 +5690,19 @@ genAddrOf (iCode * ic)
          spillCached ();
          if (sym->stack <= 0)
            {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
            }
          else
            {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
            }
-         emit2 ("ld d,h");
-         emit2 ("ld e,l");
+          commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
        }
       else
        {
          emit2 ("ld de,!hashedstr", sym->rname);
+          commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
        }
-      aopPut (AOP (IC_RESULT (ic)), "e", 0);
-      aopPut (AOP (IC_RESULT (ic)), "d", 1);
     }
   else
     {
@@ -5600,8 +5720,7 @@ genAddrOf (iCode * ic)
        {
          emit2 ("ld hl,#%s", sym->rname);
        }
-      aopPut (AOP (IC_RESULT (ic)), "l", 0);
-      aopPut (AOP (IC_RESULT (ic)), "h", 1);
+      commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
     }
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }