Lots.
[fw/sdcc] / src / z80 / gen.c
index 0782a420cd41d6de258f8052d67edee9279175fa..a46c959d975a03c6b3332235feb6aacfeaacefcc 100644 (file)
@@ -77,6 +77,8 @@ extern int ptrRegReq ;
 extern int nRegs;
 extern FILE *codeOutFile;
 set *sendSet = NULL;
+const char *_shortJP = "jp";
+
 #define RESULTONSTACK(x) \
                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
                          IC_RESULT(x)->aop->type == AOP_STK )
@@ -97,6 +99,8 @@ unsigned char   SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
 static int _lastStack = 0;
 static int _pushed = 0;
 static int _spoffset;
+static int _lastHLOff = 0;
+static asmop *_lastHL;
 
 #define LSB     0
 #define MSB16   1
@@ -235,7 +239,7 @@ static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
     if (sym->onStack || sym->iaccess) {
         sym->aop = aop = newAsmop(AOP_STK);
         aop->size = getSize(sym->type);
-
+       _lastHL = NULL;
        aop->aopu.aop_stk = sym->stack;
         return aop;
     }
@@ -249,6 +253,7 @@ static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
         return aop;
     }
 
+#if 0
     if (IS_GB) {
        /* if it is in direct space */
        if (IN_DIRSPACE(space)) {
@@ -259,12 +264,18 @@ static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
            return aop;
        }
     }
+#endif
 
     /* only remaining is far space */
     /* in which case DPTR gets the address */
-    sym->aop = aop = newAsmop(AOP_IY);
-    if (!IS_GB)
+    if (IS_GB) {
+       sym->aop = aop = newAsmop(AOP_HL);
+       _lastHL = NULL;
+    }
+    else {
+       sym->aop = aop = newAsmop(AOP_IY);
        emitcode ("ld","iy,#%s ; a", sym->rname);
+    }
     aop->size = getSize(sym->type);
     aop->aopu.aop_dir = sym->rname;
 
@@ -583,6 +594,35 @@ char *aopGetWord(asmop *aop, int offset)
     return aopGetWordLong(aop, offset, TRUE);
 }
 
+static void setupHL(asmop *aop, int offset)
+{
+    if (_lastHL != aop) {
+       switch (aop->type) {
+       case AOP_HL:
+           emitcode("ld", "hl,#%s+%d", aop->aopu.aop_dir, offset);
+           break;
+       case AOP_STK:
+           /* In some cases we can still inc or dec hl */
+           emitcode("lda", "hl,%d+%d+%d(sp)", aop->aopu.aop_stk+offset, _pushed, _spoffset);
+           break;
+       default:
+           assert(0);
+       }
+       _lastHL = aop;
+       _lastHLOff = offset;
+    }
+    else {
+       while (offset < _lastHLOff) {
+           emitcode("dec", "hl");
+           _lastHLOff--;
+       }
+       while (offset > _lastHLOff) {
+           emitcode("inc", "hl");
+           _lastHLOff++;
+       }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* aopGet - for fetching value of the aop                          */
 /*-----------------------------------------------------------------*/
@@ -625,6 +665,14 @@ static char *aopGet (asmop *aop, int offset, bool bit16)
     case AOP_REG:
        return aop->aopu.aop_reg[offset]->name;
 
+    case AOP_HL:
+       assert(IS_GB);
+       setupHL(aop, offset);
+       sprintf(s, "(hl)");
+       ALLOC_ATOMIC(rs, strlen(s)+1);
+       strcpy(rs,s);
+       return rs;
+
     case AOP_IY:
        sprintf(s,"%d(iy)", offset);
        ALLOC_ATOMIC(rs,strlen(s)+1);
@@ -633,10 +681,7 @@ static char *aopGet (asmop *aop, int offset, bool bit16)
 
     case AOP_STK:
        if (IS_GB) {
-           /* We cant really optimise this as we cant afford to
-              change the flags.
-           */
-           emitcode("lda", "hl,%d+%d+%d(sp)", aop->aopu.aop_stk+offset, _pushed, _spoffset);
+           setupHL(aop, offset);
            sprintf(s, "(hl)");
        }
        else {
@@ -735,14 +780,24 @@ static void aopPut (asmop *aop, char *s, int offset)
        else
            emitcode("ld", "%d(iy),%s", offset, s);
        break;
-       
+    
+    case AOP_HL:
+       assert(IS_GB);
+       if (!strcmp(s, "(hl)")) {
+           emitcode("ld", "a,(hl)");
+           s = "a";
+       }
+       setupHL(aop, offset);
+       emitcode("ld", "(hl),%s", s);
+       break;
+
     case AOP_STK:
        if (IS_GB) {
            if (!strcmp("(hl)", s)) {
                emitcode("ld", "a,(hl)");
                s = "a";
            }
-           emitcode("lda", "hl,%d+%d+%d(sp)", aop->aopu.aop_stk+offset, _pushed, _spoffset);
+           setupHL(aop, offset);
            if (!canAssignToPtr(s)) {
                emitcode("ld", "a,%s", s);
                emitcode("ld", "(hl),a");
@@ -1018,6 +1073,7 @@ release:
 static bool requiresHL(asmop *aop)
 {
     switch (aop->type) {
+    case AOP_HL:
     case AOP_STK:
        return TRUE;
     default:
@@ -1044,8 +1100,9 @@ void assignResultValue(operand * oper)
 static void fetchHL(asmop *aop)
 {
     if (IS_GB && requiresHL(aop)) {
-       emitcode("ld", "a,%s", aopGet(aop, 0, FALSE));
-       emitcode("ld", "h,%s", aopGet(aop, 1, FALSE));
+       aopGet(aop, 0, FALSE);
+       emitcode("ld", "a,(hl+)");
+       emitcode("ld", "h,(hl)");
        emitcode("ld", "l,a");
     }
     else {
@@ -1165,8 +1222,6 @@ static void genIpop (iCode *ic)
  */
 static void emitCall (iCode *ic, bool ispcall)
 {
-    int isPrintf = 0;
-
     /* if caller saves & we have not saved then */
     if (!ic->regsSaved) {
        /* PENDING */
@@ -1199,14 +1254,15 @@ static void emitCall (iCode *ic, bool ispcall)
 
        emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100));
        emitcode("push", "hl");
+       _pushed += 2;
 
        aopOp(IC_LEFT(ic),ic,FALSE);
-       emitcode("ld", "l,%s", aopGet(AOP(IC_LEFT(ic)), 0,FALSE));
-       emitcode("ld", "h,%s", aopGet(AOP(IC_LEFT(ic)), 1,FALSE));
+       fetchHL(AOP(IC_LEFT(ic)));
        freeAsmop(IC_LEFT(ic),NULL,ic); 
        
        emitcode("jp", "(hl)");
        emitcode("","%05d$:",(rlbl->key+100));
+       _pushed -= 2;
     }
     else {
        /* make the call */
@@ -1214,9 +1270,6 @@ static void emitCall (iCode *ic, bool ispcall)
            OP_SYMBOL(IC_LEFT(ic))->rname :
            OP_SYMBOL(IC_LEFT(ic))->name;
        emitcode("call", "%s", name);
-       if (!strcmp(name, "__printf"))
-           isPrintf = 1;
-
     }
 
     /* if we need assign a result value */
@@ -1237,22 +1290,24 @@ static void emitCall (iCode *ic, bool ispcall)
     /* adjust the stack for parameters if required */
     if (IC_LEFT(ic)->parmBytes) {
        int i = IC_LEFT(ic)->parmBytes;
-       emitcode("", ";parmBytes = %u\n", i);
-       if (isPrintf)
-           i+=2;
        _pushed -= i;
-       if (i>6) {
-           emitcode("ld", "hl,#%d", i);
-           emitcode("add", "hl,sp");
-           emitcode("ld", "sp,hl");
+       if (IS_GB) {
+           emitcode("lda", "sp,%d(sp)", i);
        }
        else {
-           while (i>1) {
-               emitcode("pop", "hl");
-               i-=2;
+           if (i>6) {
+               emitcode("ld", "hl,#%d", i);
+               emitcode("add", "hl,sp");
+               emitcode("ld", "sp,hl");
+           }
+           else {
+               while (i>1) {
+                   emitcode("pop", "hl");
+                   i-=2;
+               }
+               if (i) 
+                   emitcode("inc", "sp");
            }
-           if (i) 
-               emitcode("inc", "sp");
        }
     }
 
@@ -1334,9 +1389,14 @@ static void genFunction (iCode *ic)
     _lastStack = sym->stack;
 
     if (sym->stack) {
-       emitcode("ld", "hl,#-%d", sym->stack);
-       emitcode("add", "hl,sp");
-       emitcode("ld", "sp,hl");
+       if (IS_GB) {
+           emitcode("lda", "sp,-%d(sp)", sym->stack);
+       }
+       else {
+           emitcode("ld", "hl,#-%d", sym->stack);
+           emitcode("add", "hl,sp");
+           emitcode("ld", "sp,hl");
+       }
     }
     _spoffset = sym->stack;
 }
@@ -1409,7 +1469,12 @@ static void genRet (iCode *ic)
     size = AOP_SIZE(IC_LEFT(ic));
     
     if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
+       if (IS_GB) {
+           emitcode("ld", "de,%s", l);
+       }
+       else {
            emitcode("ld", "hl,%s", l);
+       }
     }
     else {
        while (size--) {
@@ -1497,7 +1562,7 @@ static bool genPlusIncr (iCode *ic)
         (icount == 1)) {
         symbol *tlbl = newiTempLabel(NULL);
        emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
-       emitcode("jp", "nz," LABEL_STR ,tlbl->key+100);
+       emitcode(_shortJP, "nz," LABEL_STR ,tlbl->key+100);
     
        emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
        if(size == 4) {
@@ -1545,7 +1610,7 @@ void outBitAcc(operand *result)
        assert(0);
     }
     else {
-        emitcode("jp","z," LABEL_STR ,tlbl->key+100);
+        emitcode(_shortJP,"z," LABEL_STR ,tlbl->key+100);
         emitcode("ld","a,%s",one);
         emitcode("", LABEL_STR ":",tlbl->key+100);
         outAcc(result);
@@ -2121,7 +2186,7 @@ static void gencjne(operand *left, operand *right, symbol *lbl)
 
     /* PENDING: ?? */
     emitcode("ld","a,%s",one);
-    emitcode("jp", LABEL_STR ,tlbl->key+100);
+    emitcode(_shortJP, LABEL_STR ,tlbl->key+100);
     emitcode("", LABEL_STR ":",lbl->key+100);
     emitcode("xor","a,a");
     emitcode("", LABEL_STR ":",tlbl->key+100);
@@ -2162,7 +2227,7 @@ static void genCmpEq (iCode *ic, iCode *ifx)
             } else {
                /* PENDING: do this better */
                 symbol *lbl = newiTempLabel(NULL);
-                emitcode("jp", LABEL_STR ,lbl->key+100);
+                emitcode(_shortJP, LABEL_STR ,lbl->key+100);
                 emitcode("", LABEL_STR ":",tlbl->key+100);                
                 emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100);
                 emitcode("", LABEL_STR ":",lbl->key+100);             
@@ -2243,7 +2308,7 @@ static void genAndOp (iCode *ic)
     } else {
         tlbl = newiTempLabel(NULL);
         toBoolean(left);    
-        emitcode("jp","z," LABEL_STR ,tlbl->key+100);
+        emitcode(_shortJP, "z," LABEL_STR ,tlbl->key+100);
         toBoolean(right);
         emitcode("", LABEL_STR ":",tlbl->key+100);
         outBitAcc(result);
@@ -2276,9 +2341,9 @@ static void genOrOp (iCode *ic)
     } else {
         tlbl = newiTempLabel(NULL);
         toBoolean(left);
-        emitcode("jp","nz," LABEL_STR,tlbl->key+100);
+        emitcode(_shortJP, "nz," LABEL_STR,tlbl->key+100);
         toBoolean(right);
-        emitcode("", LABEL_STR,tlbl->key+100);
+        emitcode("", LABEL_STR ":",tlbl->key+100);
         outBitAcc(result);
     }
 
@@ -2307,6 +2372,26 @@ int isLiteralBit(unsigned long lit)
     return 0;
 }
 
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse -                                                */
+/*-----------------------------------------------------------------*/
+static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
+{
+    // ugly but optimized by peephole
+    if(IC_TRUE(ic)){
+        symbol *nlbl = newiTempLabel(NULL);
+        emitcode("jp", LABEL_STR, nlbl->key+100);                 
+        emitcode("", LABEL_STR ":",tlbl->key+100);
+        emitcode("jp",LABEL_STR,IC_TRUE(ic)->key+100);
+        emitcode("", LABEL_STR ":",nlbl->key+100);
+    }
+    else{
+        emitcode("jp", LABEL_STR, IC_FALSE(ic)->key+100);
+        emitcode("", LABEL_STR ":",tlbl->key+100);
+    }
+    ic->generated = 1;
+}
+
 /*-----------------------------------------------------------------*/
 /* genAnd  - code for and                                          */
 /*-----------------------------------------------------------------*/
@@ -2420,11 +2505,7 @@ static void genAnd (iCode *ic, iCode *ifx)
             // if(left & literal)
             else{
                 if(ifx)
-#if 0
                     jmpTrueOrFalse(ifx, tlbl);
-#else
-               assert(0);
-#endif
                 goto release ;
             }
         }
@@ -2578,7 +2659,7 @@ static void genOr (iCode *ic, iCode *ifx)
                    MOVA(aopGet(AOP(right),offset,FALSE));
                    emitcode("or","a,%s ; 7",
                             aopGet(AOP(left),offset,FALSE));
-                   aopPut(AOP(result),"a ; 8",0);
+                   aopPut(AOP(result),"a ; 8", offset);
                }
             }
         }
@@ -2810,7 +2891,7 @@ static void shiftR2Left2Result (operand *left, int offl,
                emitcode("ld","a,#%u+1", shCount);
                tlbl = newiTempLabel(NULL);
                tlbl1 = newiTempLabel(NULL);
-               emitcode("jp", LABEL_STR ,tlbl1->key+100); 
+               emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
                emitcode("", LABEL_STR ":",tlbl->key+100);    
            }
 
@@ -2823,7 +2904,7 @@ static void shiftR2Left2Result (operand *left, int offl,
            if (shCount>1) {
                emitcode("", LABEL_STR ":",tlbl1->key+100);
                emitcode("dec", "a");
-               emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
+               emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
            }
     }
 }
@@ -2855,7 +2936,7 @@ static void shiftL2Left2Result (operand *left, int offl,
            emitcode("ld","a,#%u+1", shCount);
            tlbl = newiTempLabel(NULL);
            tlbl1 = newiTempLabel(NULL);
-           emitcode("jp", LABEL_STR ,tlbl1->key+100); 
+           emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
            emitcode("", LABEL_STR ":",tlbl->key+100);    
        }
 
@@ -2867,7 +2948,7 @@ static void shiftL2Left2Result (operand *left, int offl,
        if (shCount>1) {
            emitcode("", LABEL_STR ":",tlbl1->key+100);
            emitcode("dec", "a");
-           emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
+           emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
        }
     }
 }
@@ -3107,7 +3188,7 @@ static void genLeftShift (iCode *ic)
     offset = 0 ;   
     tlbl1 = newiTempLabel(NULL);
 
-    emitcode("jp", LABEL_STR ,tlbl1->key+100); 
+    emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
     emitcode("", LABEL_STR ":",tlbl->key+100);    
     l = aopGet(AOP(result),offset,FALSE);
     emitcode("or", "a,a");
@@ -3117,7 +3198,7 @@ static void genLeftShift (iCode *ic)
     }
     emitcode("", LABEL_STR ":",tlbl1->key+100);
     emitcode("dec", "a");
-    emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
+    emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
 
     freeAsmop(left,NULL,ic);
     freeAsmop(result,NULL,ic);
@@ -3291,6 +3372,10 @@ static void genGenPointerGet (operand *left,
 {
     int size, offset ;
     link *retype = getSpec(operandType(result));
+    const char *ptr = "hl";
+
+    if (IS_GB)
+       ptr = "de";
 
     aopOp(left,ic,FALSE);
     aopOp(result,ic,FALSE);
@@ -3306,9 +3391,14 @@ static void genGenPointerGet (operand *left,
     /* For now we always load into IY */
     /* if this is remateriazable */
     if (AOP_TYPE(left) == AOP_IMMD)
-       emitcode("ld","hl,%s",aopGet(AOP(left),0,TRUE));
+       emitcode("ld","%s,%s", ptr, aopGet(AOP(left),0,TRUE));
     else { /* we need to get it byte by byte */
-       fetchHL(AOP(left));
+       if (IS_GB) {
+           emitcode("ld", "e,%s", aopGet(AOP(left), 0, FALSE));
+           emitcode("ld", "d,%s", aopGet(AOP(left), 1, FALSE));
+       }
+       else
+           fetchHL(AOP(left));
     }
     /* so iy now contains the address */
     freeAsmop(left,NULL,ic);
@@ -3323,15 +3413,15 @@ static void genGenPointerGet (operand *left,
 
         while (size--) {
            /* PENDING: make this better */
-           if (AOP(result)->type == AOP_REG) {
+           if (!IS_GB && AOP(result)->type == AOP_REG) {
                aopPut(AOP(result),"(hl)",offset++);
            }
            else {
-               emitcode("ld", "a,(hl)", offset);
+               emitcode("ld", "a,(%s)", ptr, offset);
                aopPut(AOP(result),"a",offset++);
            }
            if (size) {
-               emitcode("inc", "hl");
+               emitcode("inc", "%s", ptr);
            }
         }
     }
@@ -3374,10 +3464,14 @@ static void genGenPointerSet (operand *right,
 {    
     int size, offset ;
     link *retype = getSpec(operandType(right));
+    const char *ptr = "hl";
 
     aopOp(result,ic,FALSE);
     aopOp(right,ic,FALSE);
 
+    if (IS_GB)
+       ptr = "de";
+
     /* Handle the exceptions first */
     if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
        /* Just do it */
@@ -3394,11 +3488,17 @@ static void genGenPointerSet (operand *right,
         /* if this is remateriazable */
         if (AOP_TYPE(result) == AOP_IMMD) {
            emitcode("", "; Error 2");
-           emitcode("ld", "hl,%s", aopGet(AOP(result), 0, TRUE));
+           emitcode("ld", "%s,%s", ptr, aopGet(AOP(result), 0, TRUE));
         }
         else { /* we need to get it byte by byte */
-           /* PENDING: do this better */
-           fetchHL(AOP(result));
+           if (IS_GB) {
+               emitcode("ld", "e,%s", aopGet(AOP(result), 0, TRUE));
+               emitcode("ld", "d,%s", aopGet(AOP(result), 1, TRUE));
+           }
+           else {
+               /* PENDING: do this better */
+               fetchHL(AOP(result));
+           }
         }
     }
     /* so hl know contains the address */
@@ -3414,16 +3514,15 @@ static void genGenPointerSet (operand *right,
 
         while (size--) {
             char *l = aopGet(AOP(right),offset,FALSE);
-
-           if (isRegOrLit(AOP(right))) {
-               emitcode("ld", "(hl),%s", l);
+           if (isRegOrLit(AOP(right)) && !IS_GB) {
+               emitcode("ld", "(%s),%s", ptr, l);
            }
            else {
                MOVA(l);
-               emitcode("ld", "(hl),a", offset);
+               emitcode("ld", "(%s),a", ptr, offset);
            }
            if (size) {
-               emitcode("inc", "hl");
+               emitcode("inc", ptr);
            }
            offset++;
         }
@@ -3501,7 +3600,7 @@ static void genAddrOf (iCode *ic)
     if (sym->onStack) {
         /* if it has an offset  then we need to compute it */
        if (IS_GB) {
-           emitcode("lda", "hl,%d+%d(sp)", sym->stack, _spoffset);
+           emitcode("lda", "hl,%d+%d+%d(sp)", sym->stack, _pushed, _spoffset);
            emitcode("ld", "d,h");
            emitcode("ld", "e,l");
            aopPut(AOP(IC_RESULT(ic)), "e", 0);
@@ -3595,6 +3694,13 @@ static void genAssign (iCode *ic)
                       offset);
            offset++;
        }
+    }
+    else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
+       /* Special case.  Load into a and d, then load out. */
+       MOVA(aopGet(AOP(right), 0, FALSE));
+       emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
+       aopPut(AOP(result), "a", 0);
+       aopPut(AOP(result), "e", 1);
     } else {
        while (size--) {
            aopPut(AOP(result),
@@ -3629,6 +3735,7 @@ static void genJumpTab (iCode *ic)
     emitcode("ld", "hl,#" LABEL_STR, jtab->key+100);
     emitcode("add", "hl,de");
     emitcode("add", "hl,de");
+    emitcode("add", "hl,de");
     freeAsmop(IC_JTCOND(ic),NULL,ic);
     if (!IS_GB)
        emitcode("pop", "de");
@@ -3755,10 +3862,12 @@ void genZ80Code (iCode *lic)
     if (IS_GB) {
        _fReturn = _gbz80_return;
        _fTmp = _gbz80_return;
+       _shortJP = "jr";
     }
     else {
        _fReturn = _z80_return;
        _fTmp = _z80_return;
+       _shortJP = "jp";
     }
 
     lineHead = lineCurr = NULL;