X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=826a2cf4114a071b472c5e33bd82f7907fab601e;hb=0b44824662442b40830512786321baa59f2d3a97;hp=298ffcb47132dbf61ad4cf61fccf6231228d2a79;hpb=904538934253171b501983a5377efad7ca65d848;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 298ffcb4..826a2cf4 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -60,7 +60,9 @@ 9. With asm optimised strings 17030 192 2223 10 and below are with asm strings off. - + + 10 Mucho optimisations 13562 201 1FCC + Apparent advantage of turning on regparams: 1. Cost of push Decent case is push of a constant @@ -120,7 +122,7 @@ enum { /* Set to enable debugging trace statements in the output assembly code. */ - DISABLE_DEBUG = 0, + DISABLE_DEBUG = 0 }; static char *_z80_return[] = @@ -135,6 +137,12 @@ static char **_fTmp; extern FILE *codeOutFile; +enum + { + INT8MIN = -128, + INT8MAX = 127 + }; + /** Enum covering all the possible register pairs. */ typedef enum @@ -160,8 +168,8 @@ static struct { "bc", "c", "b" }, { "de", "e", "d" }, { "hl", "l", "h" }, - { "iy", "iy.l?", "iy.h?" }, - { "ix", "ix.l?", "ix.h?" } + { "iy", "iyl", "iyh" }, + { "ix", "ixl", "ixh" } }; // PENDING @@ -227,6 +235,49 @@ static struct static const char *aopGet (asmop * aop, int offset, bool bit16); +static const char *aopNames[] = { + "AOP_INVALID", + "AOP_LIT", + "AOP_REG", + "AOP_DIR", + "AOP_SFR", + "AOP_STK", + "AOP_IMMD", + "AOP_STR", + "AOP_CRY", + "AOP_IY", + "AOP_HL", + "AOP_ACC", + "AOP_HLREG", + "AOP_SIMPLELIT", + "AOP_EXSTK", + "AOP_PAIRPT" +}; + +static bool +isLastUse (iCode *ic, operand *op) +{ + bitVect *uses = bitVectCopy (OP_USES (op)); + + while (!bitVectIsZero (uses)) + { + if (bitVectFirstBit (uses) == ic->key) + { + if (bitVectnBitsOn (uses) == 1) + { + return TRUE; + } + else + { + return FALSE; + } + } + bitVectUnSetBit (uses, bitVectFirstBit (uses)); + } + + return FALSE; +} + static PAIR_ID _getTempPairId(void) { @@ -246,6 +297,59 @@ _getTempPairName(void) return _pairs[_getTempPairId()].name; } +static bool +isPairInUse (PAIR_ID id, iCode *ic) +{ + if (id == PAIR_DE) + { + return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX); + } + else if (id == PAIR_BC) + { + return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX); + } + else + { + wassertl (0, "Only implemented for DE and BC"); + return TRUE; + } +} + +static bool +isPairInUseNotInRet(PAIR_ID id, iCode *ic) +{ + bitVect *rInUse; + + rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + + if (id == PAIR_DE) + { + return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX); + } + else + { + wassertl (0, "Only implemented for DE"); + return TRUE; + } +} + +static PAIR_ID +getFreePairId (iCode *ic) +{ + if (!isPairInUse (PAIR_BC, ic)) + { + return PAIR_BC; + } + else if (IS_Z80 && !isPairInUse (PAIR_DE, ic)) + { + return PAIR_DE; + } + else + { + return PAIR_INVALID; + } +} + static void _tidyUp (char *buf) { @@ -369,6 +473,20 @@ _emitMove(const char *to, const char *from) } } +void +aopDump(const char *plabel, asmop *aop) +{ + emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size); + switch (aop->type) + { + case AOP_STK: + emitDebug("; aop_stk %d", aop->aopu.aop_stk); + break; + default: + /* No information. */ + } +} + static void _moveA(const char *moveFrom) { @@ -400,20 +518,16 @@ getPairName (asmop * aop) break; } } - else if (aop->type == AOP_STR) + else if (aop->type == AOP_STR || aop->type == AOP_HLREG) { - switch (*aop->aopu.aop_str[0]) - { - case 'c': - return "bc"; - break; - case 'e': - return "de"; - break; - case 'l': - return "hl"; - break; - } + int i; + for (i = 0; i < NUM_PAIRS; i++) + { + if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0) + { + return _pairs[i].name; + } + } } wassertl (0, "Tried to get the pair name of something that isn't a pair"); return NULL; @@ -439,21 +553,17 @@ getPairId (asmop * aop) return PAIR_HL; } } - if (aop->type == AOP_STR) + else if (aop->type == AOP_STR || aop->type == AOP_HLREG) { - if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b")) - { - return PAIR_BC; - } - if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d")) - { - return PAIR_DE; - } - if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h")) - { - return PAIR_HL; - } - } + int i; + for (i = 0; i < NUM_PAIRS; i++) + { + if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h)) + { + return i; + } + } + } } return PAIR_INVALID; } @@ -479,6 +589,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 +616,7 @@ _pop (PAIR_ID pairId) { emit2 ("pop %s", _pairs[pairId].name); _G.stack.pushed -= 2; + spillPair (pairId); } /*-----------------------------------------------------------------*/ @@ -530,16 +649,18 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* if already has one */ if (sym->aop) - return sym->aop; + { + return sym->aop; + } /* Assign depending on the storage class */ 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); @@ -767,7 +888,9 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) /* if already has a asmop then continue */ if (op->aop) - return; + { + return; + } /* if the underlying symbol has a aop */ if (IS_SYMOP (op) && OP_SYMBOL (op)->aop) @@ -815,6 +938,16 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } + if (sym->ruonly) + { + int i; + aop = op->aop = sym->aop = newAsmop (AOP_STR); + aop->size = getSize (sym->type); + for (i = 0; i < 4; i++) + aop->aopu.aop_str[i] = _fReturn[i]; + return; + } + if (sym->accuse) { if (sym->accuse == ACCUSE_A) @@ -825,15 +958,22 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) aop->aopu.aop_str[0] = _pairs[PAIR_AF].h; } - else if (sym->accuse == ACCUSE_HL) + else if (sym->accuse == ACCUSE_SCRATCH) { - wassert (!IS_GB); aop = op->aop = sym->aop = newAsmop (AOP_HLREG); aop->size = getSize (sym->type); wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL"); aop->aopu.aop_str[0] = _pairs[PAIR_HL].l; aop->aopu.aop_str[1] = _pairs[PAIR_HL].h; } + else if (sym->accuse == ACCUSE_IY) + { + aop = op->aop = sym->aop = newAsmop (AOP_HLREG); + aop->size = getSize (sym->type); + wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY"); + aop->aopu.aop_str[0] = _pairs[PAIR_IY].l; + aop->aopu.aop_str[1] = _pairs[PAIR_IY].h; + } else { wassertl (0, "Marked as being allocated into A or HL but is actually in neither"); @@ -841,19 +981,14 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } - if (sym->ruonly) - { - int i; - aop = op->aop = sym->aop = newAsmop (AOP_STR); - aop->size = getSize (sym->type); - for (i = 0; i < 4; i++) - aop->aopu.aop_str[i] = _fReturn[i]; - return; - } - /* else spill location */ + if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) { + /* force a new aop if sizes differ */ + sym->usl.spillLoc->aop = NULL; + } sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, result, requires_a); + wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location"); aop->size = getSize (sym->type); return; } @@ -926,7 +1061,6 @@ char * aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { char *s = buffer; - char *rs; /* depending on type */ switch (aop->type) @@ -980,15 +1114,27 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) } else { - /* A float */ - Z80_FLOAT f; - convertFloat (&f, floatFromVal (val)); + union { + float f; + unsigned char c[4]; + } + fl; + unsigned int i; + + /* it is type float */ + fl.f = (float) floatFromVal (val); + +#ifdef _BIG_ENDIAN + i = fl.c[3-offset] | (fl.c[3-offset-1]<<8); +#else + i = fl.c[offset] | (fl.c[offset+1]<<8); +#endif if (with_hash) - tsprintf (buffer, "!immedword", f.w[offset / 2]); + tsprintf (buffer, "!immedword", i); else - tsprintf (buffer, "!constword", f.w[offset / 2]); - rs = Safe_calloc (1, strlen (buffer) + 1); - return strcpy (rs, buffer); + tsprintf (buffer, "!constword", i); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } } default: @@ -1031,13 +1177,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) { @@ -1054,6 +1193,7 @@ requiresHL (asmop * aop) case AOP_HL: case AOP_STK: case AOP_EXSTK: + case AOP_HLREG: return TRUE; default: return FALSE; @@ -1082,7 +1222,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; } @@ -1097,16 +1237,49 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) emit2 ("ld %s,!hashedstr", pair, l); } +static PAIR_ID +makeFreePairId (iCode *ic, bool *pisUsed) +{ + *pisUsed = FALSE; + + if (ic != NULL) + { + if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX)) + { + return PAIR_BC; + } + else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX)) + { + return PAIR_DE; + } + else + { + *pisUsed = TRUE; + return PAIR_HL; + } + } + else + { + *pisUsed = TRUE; + return PAIR_HL; + } +} + static void -fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) +fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset) { /* if this is remateriazable */ if (isLitWord (aop)) { fetchLitPair (pairId, aop, offset); } - else { + else + { + if (getPairId (aop) == pairId) + { + /* Do nothing */ + } /* we need to get it byte by byte */ - if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) { + else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) { aopGet (aop, offset, FALSE); switch (aop->size - offset) { case 1: @@ -1136,10 +1309,33 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) emit2("ld %s,!zero", _pairs[pairId].h); } } - else { + else if (pairId == PAIR_IY) + { + if (isPair (aop)) + { + emit2 ("push %s", _pairs[getPairId(aop)].name); + emit2 ("pop iy"); + } + else + { + bool isUsed; + PAIR_ID id = makeFreePairId (ic, &isUsed); + if (isUsed) + _push (id); + /* Can't load into parts, so load into HL then exchange. */ + emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE)); + emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE)); + emit2 ("push %s", _pairs[id].name); + emit2 ("pop iy"); + if (isUsed) + _pop (id); + } + } + 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) spillPair (PAIR_HL); @@ -1149,7 +1345,7 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) static void fetchPair (PAIR_ID pairId, asmop * aop) { - fetchPairLong (pairId, aop, 0); + fetchPairLong (pairId, aop, NULL, 0); } static void @@ -1158,6 +1354,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) { @@ -1203,6 +1415,7 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset) { /* Doesnt include _G.stack.pushed */ int abso = aop->aopu.aop_stk + offset + _G.stack.offset; + if (aop->aopu.aop_stk > 0) { abso += _G.stack.param_offset; @@ -1215,7 +1428,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; @@ -1528,7 +1741,9 @@ aopPut (asmop * aop, const char *s, int offset) emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset); } else - emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s); + { + emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s); + } } break; @@ -1536,7 +1751,7 @@ aopPut (asmop * aop, const char *s, int offset) /* if bit variable */ if (!aop->aopu.aop_dir) { - emit2 ("ld a,#0"); + emit2 ("ld a,!zero"); emit2 ("rla"); } else @@ -1594,7 +1809,8 @@ aopPut (asmop * aop, const char *s, int offset) static void commitPair (asmop * aop, PAIR_ID id) { - if (id == PAIR_HL && requiresHL (aop)) + /* PENDING: Verify this. */ + if (id == PAIR_HL && requiresHL (aop) && IS_GB) { emit2 ("ld a,l"); emit2 ("ld d,h"); @@ -1603,8 +1819,19 @@ commitPair (asmop * aop, PAIR_ID id) } else { - aopPut (aop, _pairs[id].l, 0); - aopPut (aop, _pairs[id].h, 1); + /* Special cases */ + if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2) + { + char *l = aopGetLitWordLong (aop, 0, FALSE); + wassert (l); + + emit2 ("ld (%s),%s", l, _pairs[id].name); + } + else + { + aopPut (aop, _pairs[id].l, 0); + aopPut (aop, _pairs[id].h, 1); + } } } @@ -1632,6 +1859,7 @@ movLeft2Result (operand * left, int offl, operand * result, int offr, int sign) { const char *l; + if (!sameRegs (AOP (left), AOP (result)) || (offl != offr)) { l = aopGet (AOP (left), offl, FALSE); @@ -1651,6 +1879,47 @@ movLeft2Result (operand * left, int offl, } } +static void +movLeft2ResultLong (operand * left, int offl, + operand * result, int offr, int sign, + int size) +{ + if (size == 1) + { + movLeft2Result (left, offl, result, offr, sign); + } + else + { + wassertl (offl == 0 && offr == 0, "Only implemented for zero offset"); + wassertl (size == 2, "Only implemented for two bytes or one"); + + if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL) + { + emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE)); + emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE)); + emit2 ("ld l,a"); + } + else if ( getPairId ( AOP (result)) == PAIR_IY) + { + PAIR_ID id = getPairId (AOP (left)); + if (id != PAIR_INVALID) + { + emit2("push %s", _pairs[id].name); + emit2("pop iy"); + } + else + { + /* PENDING */ + emitDebug("Error"); + } + } + else + { + movLeft2Result (left, offl, result, offr, sign); + movLeft2Result (left, offl+1, result, offr+1, sign); + } + } +} /** Put Acc into a register set */ @@ -1723,6 +1992,44 @@ _toBoolean (operand * oper) } } +/*-----------------------------------------------------------------*/ +/* genNotFloat - generates not for float operations */ +/*-----------------------------------------------------------------*/ +static void +genNotFloat (operand * op, operand * res) +{ + int size, offset; + symbol *tlbl; + + emitDebug ("; genNotFloat"); + + /* we will put 127 in the first byte of + the result */ + aopPut (AOP (res), "!immedbyte", 0x7F); + size = AOP_SIZE (op) - 1; + offset = 1; + + _moveA (aopGet (op->aop, offset++, FALSE)); + + while (size--) + { + emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE)); + } + + tlbl = newiTempLabel (NULL); + aopPut (res->aop, "!one", 1); + emit2 ("!shortjp z !tlabel", tlbl->key + 100); + aopPut (res->aop, "!zero", 1); + + emitLabel(tlbl->key + 100); + + size = res->aop->size - 2; + offset = 2; + /* put zeros in the rest */ + while (size--) + aopPut (res->aop, "!zero", offset++); +} + /*-----------------------------------------------------------------*/ /* genNot - generate code for ! operation */ /*-----------------------------------------------------------------*/ @@ -1744,7 +2051,8 @@ genNot (iCode * ic) /* if type float then do float */ if (IS_FLOAT (optype)) { - wassertl (0, "Tried to negate a float"); + genNotFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; } _toBoolean (IC_LEFT (ic)); @@ -1756,6 +2064,7 @@ genNot (iCode * ic) emit2 ("sub a,!one"); outBitC (IC_RESULT (ic)); + release: /* release the aops */ freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -1830,7 +2139,7 @@ _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd) aopPut ( AOP (IC_RESULT (ic)), "a", MSB16); aopPut ( AOP (IC_RESULT (ic)), "e", LSB); - fetchPairLong (PAIR_DE, left, MSB24); + fetchPairLong (PAIR_DE, left, NULL, MSB24); aopGet (right, MSB24, FALSE); _pop (PAIR_AF); @@ -1850,6 +2159,32 @@ _gbz80_emitAddSubLong (iCode *ic, bool isAdd) _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd); } +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void +genUminusFloat (operand * op, operand * result) +{ + int size, offset = 0; + + emitDebug("; genUminusFloat"); + + /* for this we just need to flip the + first it then copy the rest in place */ + size = AOP_SIZE (op) - 1; + + _moveA(aopGet (AOP (op), MSB32, FALSE)); + + emit2("xor a,!immedbyte", 0x80); + aopPut (AOP (result), "a", MSB32); + + while (size--) + { + aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset); + offset++; + } +} + /*-----------------------------------------------------------------*/ /* genUminus - unary minus code generation */ /*-----------------------------------------------------------------*/ @@ -1878,7 +2213,7 @@ genUminus (iCode * ic) /* if float then do float stuff */ if (IS_FLOAT (optype)) { - wassertl (0, "Tried to do a unary minus on a float"); + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); goto release; } @@ -1952,6 +2287,25 @@ assignResultValue (operand * oper) } } +/** Simple restore that doesn't take into account what is used in the + return. +*/ +static void +_restoreRegsAfterCall(void) +{ + if (_G.stack.pushedDE) + { + _pop ( PAIR_DE); + _G.stack.pushedDE = FALSE; + } + if (_G.stack.pushedBC) + { + _pop ( PAIR_BC); + _G.stack.pushedBC = FALSE; + } + _G.saves.saved = FALSE; +} + static void _saveRegsForCall(iCode *ic, int sendSetSize) { @@ -2057,7 +2411,7 @@ genIpush (iCode * ic) size = AOP_SIZE (IC_LEFT (ic)); - if (isPair (AOP (IC_LEFT (ic)))) + if (isPair (AOP (IC_LEFT (ic))) && size == 2) { _G.stack.pushed += 2; emit2 ("push %s", getPairName (AOP (IC_LEFT (ic)))); @@ -2074,11 +2428,11 @@ genIpush (iCode * ic) } if (size == 4) { - fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2); + 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)), 0); + fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0); emit2 ("push hl"); spillPair (PAIR_HL); _G.stack.pushed += 2; @@ -2217,9 +2571,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) static void emitCall (iCode * ic, bool ispcall) { - sym_link *detype = getSpec (operandType (IC_LEFT (ic))); - - bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + sym_link *dtype = operandType (IC_LEFT (ic)); /* if caller saves & we have not saved then */ if (!ic->regsSaved) @@ -2291,7 +2643,7 @@ emitCall (iCode * ic, bool ispcall) if (ispcall) { - if (IS_BANKEDCALL (detype)) + if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype))) { werror (W_INDIR_BANKED); } @@ -2321,7 +2673,7 @@ emitCall (iCode * ic, bool ispcall) char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name; - if (IS_BANKEDCALL (detype)) + if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype))) { emit2 ("call banked_call"); emit2 ("!dws", name); @@ -2365,76 +2717,83 @@ emitCall (iCode * ic, bool ispcall) else { spillCached (); - if (i > 6) + if (i > 8) { - emit2 ("ld hl,#%d", i); - emit2 ("add hl,sp"); - emit2 ("ld sp,hl"); + emit2 ("ld iy,!immedword", i); + emit2 ("add iy,sp"); + emit2 ("ld sp,iy"); } else { while (i > 1) { - emit2 ("pop hl"); + emit2 ("pop af"); i -= 2; } if (i) - emit2 ("inc sp"); + { + emit2 ("inc sp"); + } } - spillCached (); } } + spillCached (); + if (_G.stack.pushedDE) { - bool dInUse = bitVectBitValue(rInUse, D_IDX); - bool eInUse = bitVectBitValue(rInUse, E_IDX); + bool dInRet = bitVectBitValue(ic->rUsed, D_IDX); + bool eInRet = bitVectBitValue(ic->rUsed, E_IDX); - if (dInUse && eInUse) + if (dInRet && eInRet) { - _pop (PAIR_DE); + wassertl (0, "Shouldn't push DE if it's wiped out by the return"); } - else if (dInUse) + else if (dInRet) { - _pop(PAIR_HL); - emit2 ("ld d,h"); + /* Only restore E */ + emit2 ("ld a,d"); + _pop (PAIR_DE); + emit2 ("ld d,a"); } - else if (eInUse) + else if (eInRet) { - _pop(PAIR_HL); - emit2 ("ld e,l"); + /* Only restore D */ + _pop (PAIR_AF); + emit2 ("ld d,a"); } else { - wassertl (0, "Neither D or E were in use but it was pushed."); + _pop (PAIR_DE); } _G.stack.pushedDE = FALSE; } if (_G.stack.pushedBC) { - bool bInUse = bitVectBitValue(rInUse, B_IDX); - bool cInUse = bitVectBitValue(rInUse, C_IDX); + bool bInRet = bitVectBitValue(ic->rUsed, B_IDX); + bool cInRet = bitVectBitValue(ic->rUsed, C_IDX); - // If both B and C are used in the return value, then we won't get - // here. - if (bInUse && cInUse) + if (bInRet && cInRet) { - _pop (PAIR_BC); + wassertl (0, "Shouldn't push BC if it's wiped out by the return"); } - else if (bInUse) + else if (bInRet) { - _pop(PAIR_HL); - emit2 ("ld b,h"); + /* Only restore C */ + emit2 ("ld a,b"); + _pop (PAIR_BC); + emit2 ("ld b,a"); } - else if (cInUse) + else if (cInRet) { - _pop(PAIR_HL); - emit2 ("ld c,l"); + /* Only restore B */ + _pop (PAIR_AF); + emit2 ("ld b,a"); } else { - wassertl (0, "Neither B or C were in use but it was pushed."); + _pop (PAIR_BC); } _G.stack.pushedBC = FALSE; } @@ -2486,14 +2845,14 @@ static void genFunction (iCode * ic) { symbol *sym = OP_SYMBOL (IC_LEFT (ic)); - sym_link *fetype; + sym_link *ftype; #if CALLEE_SAVES bool bcInUse = FALSE; bool deInUse = FALSE; #endif - setArea (IS_NONBANKED (sym->etype)); + setArea (IFFUNC_NONBANKED (sym->type)); /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere else. @@ -2505,8 +2864,8 @@ genFunction (iCode * ic) /* Create the function header */ emit2 ("!functionheader", sym->name); - /* PENDING: portability. */ - emit2 ("__%s_start:", sym->rname); + sprintf (buffer, "%s_start", sym->rname); + emit2 ("!labeldef", buffer); emit2 ("!functionlabeldef", sym->rname); if (options.profile) @@ -2514,14 +2873,14 @@ genFunction (iCode * ic) emit2 ("!profileenter"); } - fetype = getSpec (operandType (IC_LEFT (ic))); + ftype = operandType (IC_LEFT (ic)); /* if critical function then turn interrupts off */ - if (SPEC_CRTCL (fetype)) + if (IFFUNC_ISCRITICAL (ftype)) emit2 ("!di"); /* if this is an interrupt service routine then save all potentially used registers. */ - if (IS_ISR (sym->etype)) + if (IFFUNC_ISISR (sym->type)) { emit2 ("!pusha"); } @@ -2579,7 +2938,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"); @@ -2594,18 +2955,22 @@ genEndFunction (iCode * ic) { symbol *sym = OP_SYMBOL (IC_LEFT (ic)); - if (IS_ISR (sym->etype)) + if (IFFUNC_ISISR (sym->type)) { wassertl (0, "Tried to close an interrupt support function"); } else { - if (SPEC_CRTCL (sym->etype)) + if (IFFUNC_ISCRITICAL (sym->type)) emit2 ("!ei"); /* 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); } @@ -2637,8 +3002,8 @@ genEndFunction (iCode * ic) /* Both baned and non-banked just ret */ emit2 ("ret"); - /* PENDING: portability. */ - emit2 ("__%s_end:", sym->rname); + sprintf (buffer, "%s_end", sym->rname); + emit2 ("!labeldef", buffer); } _G.flushStatics = 1; _G.stack.pushed = 0; @@ -2682,7 +3047,7 @@ genRet (iCode * ic) if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic)))) { fetchPair (PAIR_DE, AOP (IC_LEFT (ic))); - fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2); + fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2); } else { @@ -2753,14 +3118,27 @@ genPlusIncr (iCode * ic) { if (isLitWord (AOP (IC_LEFT (ic)))) { - fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount); + fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount); return TRUE; } if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2) { - fetchPair (resultId, AOP (IC_RIGHT (ic))); - emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); - return TRUE; + if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL) + { + PAIR_ID freep = getFreePairId (ic); + if (freep != PAIR_INVALID) + { + fetchPair (freep, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", _pairs[freep].name); + return TRUE; + } + } + else + { + fetchPair (resultId, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); + return TRUE; + } } if (icount > 5) return FALSE; @@ -2769,8 +3147,7 @@ genPlusIncr (iCode * ic) { if (icount > 2) return FALSE; - movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0); - movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0); + movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2); } while (icount--) { @@ -2779,6 +3156,13 @@ genPlusIncr (iCode * ic) return TRUE; } + if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2) + { + fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount); + commitPair (AOP (IC_RESULT (ic)), PAIR_HL); + return TRUE; + } + /* if the literal value of the right hand side is greater than 4 then it is not worth it */ if (icount > 4) @@ -2810,6 +3194,18 @@ genPlusIncr (iCode * ic) AOP_SIZE (IC_LEFT (ic)) > 1) return FALSE; + /* If the result is in a register then we can load then increment. + */ + if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG) + { + aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB); + while (icount--) + { + emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE)); + } + return TRUE; + } + /* we can if the aops of the left & result match or if they are in registers and the registers are the same */ @@ -2862,7 +3258,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"); @@ -3000,12 +3396,48 @@ genPlus (iCode * ic) } } - if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL) + if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL) { /* Fetch into HL then do the add */ + PAIR_ID left = getPairId (AOP (IC_LEFT (ic))); + PAIR_ID right = getPairId (AOP (IC_RIGHT (ic))); + spillPair (PAIR_HL); + + if (left == PAIR_HL && right != PAIR_INVALID) + { + emit2 ("add hl,%s", _pairs[right].name); + goto release; + } + else if (right == PAIR_HL && left != PAIR_INVALID) + { + emit2 ("add hl,%s", _pairs[left].name); + goto release; + } + else if (right != PAIR_INVALID && right != PAIR_HL) + { + fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic)))); + goto release; + } + else if (left != PAIR_INVALID && left != PAIR_HL) + { + fetchPair (PAIR_HL, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); + goto release; + } + else + { + /* Can't do it */ + } + } + + if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL) + { 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; } @@ -3147,8 +3579,7 @@ genMinusDec (iCode * ic) /* If result is a pair */ if (isPair (AOP (IC_RESULT (ic)))) { - movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0); - movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0); + movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2); while (icount--) emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic)))); return TRUE; @@ -3260,7 +3691,10 @@ genMinus (iCode * ic) emit2 ("ld a,%s", _pairs[left].h); emit2 ("sbc a,%s", _pairs[right].h); - aopPut (AOP (IC_RESULT (ic)), "a", 1); + if ( AOP_SIZE (IC_RESULT (ic)) > 1) + { + aopPut (AOP (IC_RESULT (ic)), "a", 1); + } aopPut (AOP (IC_RESULT (ic)), "e", 0); goto release; } @@ -3320,8 +3754,94 @@ 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 && isPairInUseNotInRet (PAIR_DE, ic)) { + _push (PAIR_DE); + _G.stack.pushedDE = TRUE; + } + + 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 && _G.stack.pushedDE) + { + _pop (PAIR_DE); + _G.stack.pushedDE = FALSE; + } + + 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); } /*-----------------------------------------------------------------*/ @@ -3370,6 +3890,14 @@ genIfxJump (iCode * ic, char *jval) { inst = "nc"; } + else if (!strcmp (jval, "m")) + { + inst = "m"; + } + else if (!strcmp (jval, "p")) + { + inst = "p"; + } else { /* The buffer contains the bit on A that we should test */ @@ -3392,6 +3920,14 @@ genIfxJump (iCode * ic, char *jval) { inst = "c"; } + else if (!strcmp (jval, "m")) + { + inst = "p"; + } + else if (!strcmp (jval, "p")) + { + inst = "m"; + } else { /* The buffer contains the bit on A that we should test */ @@ -3409,6 +3945,12 @@ genIfxJump (iCode * ic, char *jval) else if (!strcmp (jval, "nc")) { } + else if (!strcmp (jval, "m")) + { + } + else if (!strcmp (jval, "p")) + { + } else { emit2 ("bit %s,a", jval); @@ -3427,30 +3969,7 @@ _getPairIdName (PAIR_ID id) } #endif -/** Generic compare for > or < - */ -static void -genCmp (operand * left, operand * right, - operand * result, iCode * ifx, int sign) -{ - int size, offset = 0; - unsigned long lit = 0L; - bool swap_sense = FALSE; - - /* if left & right are bit variables */ - if (AOP_TYPE (left) == AOP_CRY && - AOP_TYPE (right) == AOP_CRY) - { - /* Cant happen on the Z80 */ - wassertl (0, "Tried to compare two bits"); - } - else - { - /* subtract right from left if at the - end the carry flag is set then we know that - left is greater than right */ - size = max (AOP_SIZE (left), AOP_SIZE (right)); - +#if OLD /* if unsigned char cmp with lit, just compare */ if ((size == 1) && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR)) @@ -3481,10 +4000,10 @@ genCmp (operand * left, operand * right, // Save the flags emit2 ("push af"); emit2 ("ld a,(de)"); - emit2 ("xor #0x80"); + emit2 ("xor !immedbyte", 0x80); emit2 ("ld e,a"); emit2 ("ld a,(hl)"); - emit2 ("xor #0x80"); + emit2 ("xor !immedbyte", 0x80); emit2 ("ld d,a"); emit2 ("pop af"); emit2 ("ld a,e"); @@ -3518,10 +4037,10 @@ genCmp (operand * left, operand * right, // Save the flags emit2 ("push af"); emit2 ("ld a,(hl)"); - emit2 ("xor #0x80"); + emit2 ("xor !immedbyte", 0x80); emit2 ("ld l,a"); emit2 ("ld a,%d(iy)", offset); - emit2 ("xor #0x80"); + emit2 ("xor !immedbyte", 0x80); emit2 ("ld h,a"); emit2 ("pop af"); emit2 ("ld a,l"); @@ -3625,10 +4144,109 @@ genCmp (operand * left, operand * right, } } } +#endif + +/** Generic compare for > or < + */ +static void +genCmp (operand * left, operand * right, + operand * result, iCode * ifx, int sign) +{ + int size, offset = 0; + unsigned long lit = 0L; + bool swap_sense = FALSE; + + /* if left & right are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && + AOP_TYPE (right) == AOP_CRY) + { + /* Cant happen on the Z80 */ + wassertl (0, "Tried to compare two bits"); + } + else + { + /* Do a long subtract of right from left. */ + size = max (AOP_SIZE (left), AOP_SIZE (right)); + + if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left))) + { + // On the Gameboy we can't afford to adjust HL as it may trash the carry. + // Pull left into DE and right into HL + aopGet (AOP(left), LSB, FALSE); + emit2 ("ld d,h"); + emit2 ("ld e,l"); + aopGet (AOP(right), LSB, FALSE); + + while (size--) + { + emit2 ("ld a,(de)"); + emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc"); + + if (size != 0) + { + emit2 ("inc hl"); + emit2 ("inc de"); + } + offset++; + } + spillPair (PAIR_HL); + goto release; + } + + if (AOP_TYPE (right) == AOP_LIT) + { + lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + /* optimize if(x < 0) or if(x >= 0) */ + if (lit == 0) + { + if (!sign) + { + /* No sign so it's always false */ + _clearCarry(); + } + else + { + /* Just load in the top most bit */ + _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); + if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx) + { + genIfxJump (ifx, "7"); + return; + } + else + { + if (!sign) + { + emit2 ("rlc a"); + } + if (ifx) + { + genIfxJump (ifx, swap_sense ? "c" : "nc"); + return; + } + } + } + goto release; + } + } + + while (size--) + { + _moveA (aopGet (AOP (left), offset, FALSE)); + /* Subtract through, propagating the carry */ + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE)); + offset++; + } + } release: if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) { + if (sign) + { + /* Shift the sign bit up into carry */ + emit2 ("rlca"); + } outBitCLong (result, swap_sense); } else @@ -3637,9 +4255,33 @@ release: ifx conditional branch then generate code a little differently */ if (ifx) - genIfxJump (ifx, swap_sense ? "nc" : "c"); + { + if (sign) + { + if (IS_GB) + { + emit2 ("rlca"); + genIfxJump (ifx, swap_sense ? "nc" : "c"); + } + else + { + genIfxJump (ifx, swap_sense ? "p" : "m"); + } + } + else + { + genIfxJump (ifx, swap_sense ? "nc" : "c"); + } + } else - outBitCLong (result, swap_sense); + { + if (sign) + { + /* Shift the sign bit up into carry */ + emit2 ("rlca"); + } + outBitCLong (result, swap_sense); + } /* leave the result in acc */ } } @@ -3722,7 +4364,9 @@ gencjneshort (operand * left, operand * right, symbol * lbl) } if (AOP_TYPE (right) == AOP_LIT) - lit = (unsigned long) floatFromVal (AOP (right)->aopu.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 && @@ -3733,11 +4377,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 @@ -3825,7 +4467,7 @@ genCmpEq (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); - emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic))); + emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic))); /* Swap operands if it makes the operation easier. ie if: 1. Left is a literal. @@ -3878,6 +4520,8 @@ genCmpEq (iCode * ic, iCode * ifx) } else { + emitDebug(";4"); + gencjne (left, right, newiTempLabel (NULL)); if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) { @@ -3885,6 +4529,7 @@ genCmpEq (iCode * ic, iCode * ifx) } if (ifx) { + emitDebug(";5"); genIfxJump (ifx, "a"); goto release; } @@ -3892,6 +4537,7 @@ genCmpEq (iCode * ic, iCode * ifx) then put the result in place */ if (AOP_TYPE (result) != AOP_CRY) { + emitDebug(";6"); outAcc (result); } /* leave the result in acc */ @@ -4621,6 +5267,7 @@ genGetHbit (iCode * ic) operand *left, *result; left = IC_LEFT (ic); result = IC_RESULT (ic); + aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); @@ -4635,8 +5282,7 @@ genGetHbit (iCode * ic) else { emit2 ("rlc a"); - /* PENDING: For re-target. */ - emit2 ("and a,#1"); + emit2 ("and a,!one"); outAcc (result); } @@ -4724,9 +5370,13 @@ shiftL2Left2Result (operand * left, int offl, movLeft2Result (left, offl, result, offr, 0); movLeft2Result (left, offl + 1, result, offr + 1, 0); } - /* PENDING: for now just see if it'll work. */ - /*if (AOP(result)->type == AOP_REG) { */ - { + + if (shCount == 1 && getPairId (AOP (result)) == PAIR_HL) + { + emit2 ("add hl,hl"); + } + else + { int size = 2; int offset = 0; symbol *tlbl, *tlbl1; @@ -5329,7 +5979,9 @@ genGenPointerGet (operand * left, aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); - if (isPair (AOP (left)) && AOP_SIZE (result) == 1) + size = AOP_SIZE (result); + + if (isPair (AOP (left)) && size == 1) { /* Just do it */ if (isPtrPair (AOP (left))) @@ -5346,18 +5998,68 @@ genGenPointerGet (operand * left, goto release; } + if (getPairId (AOP (left)) == PAIR_IY) + { + /* Just do it */ + offset = 0; + while (size--) + { + char at[20]; + tsprintf (at, "!*iyx", offset); + aopPut (AOP (result), at, offset); + offset++; + } + + freeAsmop (left, NULL, ic); + goto release; + } + /* For now we always load into IY */ /* if this is remateriazable */ fetchPair (pair, AOP (left)); - /* so iy now contains the address */ - freeAsmop (left, NULL, ic); - /* if bit then unpack */ if (IS_BITVAR (retype)) { wassert (0); } + else if (getPairId (AOP (result)) == PAIR_HL) + { + wassertl (size == 2, "HL must be of size 2"); + emit2 ("ld a,!*hl"); + emit2 ("inc hl"); + emit2 ("ld h,!*hl"); + emit2 ("ld l,a"); + } + else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left)) + { + size = AOP_SIZE (result); + offset = 0; + + while (size--) + { + /* PENDING: make this better */ + if (!IS_GB && AOP_TYPE (result) == AOP_REG) + { + aopPut (AOP (result), "!*hl", offset++); + } + else + { + emit2 ("ld a,!*pair", _pairs[pair].name); + aopPut (AOP (result), "a", offset++); + } + if (size) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + /* Fixup HL back down */ + for (size = AOP_SIZE (result)-1; size; size--) + { + emit2 ("dec %s", _pairs[pair].name); + } + } else { size = AOP_SIZE (result); @@ -5366,7 +6068,8 @@ genGenPointerGet (operand * left, while (size--) { /* PENDING: make this better */ - if (!IS_GB && AOP (result)->type == AOP_REG) + if (!IS_GB && + (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG)) { aopPut (AOP (result), "!*hl", offset++); } @@ -5383,6 +6086,8 @@ genGenPointerGet (operand * left, } } + freeAsmop (left, NULL, ic); + release: freeAsmop (result, NULL, ic); } @@ -5410,7 +6115,7 @@ genPointerGet (iCode * ic) bool isRegOrLit (asmop * aop) { - if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD) + if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG) return TRUE; return FALSE; } @@ -5425,15 +6130,17 @@ genGenPointerSet (operand * right, int size, offset; sym_link *retype = getSpec (operandType (right)); PAIR_ID pairId = PAIR_HL; - + aopOp (result, ic, FALSE, FALSE); aopOp (right, ic, FALSE, FALSE); if (IS_GB) pairId = PAIR_DE; + size = AOP_SIZE (right); + /* Handle the exceptions first */ - if (isPair (AOP (result)) && (AOP_SIZE (right) == 1)) + if (isPair (AOP (result)) && size == 1) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -5449,6 +6156,59 @@ genGenPointerSet (operand * right, } goto release; } + + if ( getPairId( AOP (result)) == PAIR_IY) + { + /* Just do it */ + const char *l = aopGet (AOP (right), 0, FALSE); + + offset = 0; + while (size--) + { + if (canAssignToPtr (l)) + { + emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE)); + } + else + { + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("ld !*iyx,a", offset); + } + offset++; + } + goto release; + } + else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)) + { + offset = 0; + + while (size--) + { + const char *l = aopGet (AOP (right), offset, FALSE); + if (isRegOrLit (AOP (right)) && !IS_GB) + { + emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l); + } + else + { + _moveA (l); + emit2 ("ld !*pair,a", _pairs[PAIR_HL].name); + } + if (size) + { + emit2 ("inc %s", _pairs[PAIR_HL].name); + _G.pairs[PAIR_HL].offset++; + } + offset++; + } + + /* Fixup HL back down */ + for (size = AOP_SIZE (right)-1; size; size--) + { + emit2 ("dec %s", _pairs[PAIR_HL].name); + } + goto release; + } /* if the operand is already in dptr then we do nothing else we move the value to dptr */ @@ -5466,7 +6226,6 @@ genGenPointerSet (operand * right, } else { - size = AOP_SIZE (right); offset = 0; while (size--) @@ -5568,21 +6327,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 { @@ -5591,17 +6348,16 @@ genAddrOf (iCode * ic) { /* if it has an offset then we need to compute it */ if (sym->stack > 0) - emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset); + emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset); else - emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset); + emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset); emit2 ("add hl,sp"); } else { - emit2 ("ld hl,#%s", sym->rname); + emit2 ("ld hl,!hashedstr", 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); } @@ -5647,10 +6403,13 @@ genAssign (iCode * ic) offset = 0; if (AOP_TYPE (right) == AOP_LIT) - lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + { + lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + } + if (isPair (AOP (result))) { - fetchPair (getPairId (AOP (result)), AOP (right)); + fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB); } else if ((size > 1) && (AOP_TYPE (result) != AOP_REG) && @@ -5688,6 +6447,12 @@ genAssign (iCode * ic) offset++; } } + else if (size == 2 && AOP_TYPE (right) == AOP_IY) + { + emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir); + aopPut (AOP (result), "l", LSB); + aopPut (AOP (result), "h", MSB16); + } else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB) { /* Special case. Load into a and d, then load out. */ @@ -5723,7 +6488,7 @@ genAssign (iCode * ic) while (size--) { /* PENDING: do this check better */ - if (requiresHL (AOP (right)) && requiresHL (AOP (result))) + if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result))) { _moveA (aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); @@ -5781,7 +6546,7 @@ static void genCast (iCode * ic) { operand *result = IC_RESULT (ic); - sym_link *ctype = operandType (IC_LEFT (ic)); + sym_link *rtype = operandType (IC_RIGHT (ic)); operand *right = IC_RIGHT (ic); int size, offset; @@ -5835,7 +6600,7 @@ genCast (iCode * ic) /* now depending on the sign of the destination */ size = AOP_SIZE (result) - AOP_SIZE (right); /* Unsigned or not an integral type - right fill with zeros */ - if (SPEC_USIGN (ctype) || !IS_SPEC (ctype)) + if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY) { while (size--) aopPut (AOP (result), "!zero", offset++); @@ -6011,7 +6776,7 @@ _rleAppend(RLECTX *self, int c) /* Yes, worthwhile. */ /* Commit whatever was in the buffer. */ _rleCommit(self); - emit2(".db -%u,0x%02X", self->runLen, self->last); + emit2("!db !immed-%u,!immedbyte", self->runLen, self->last); } else { @@ -6036,7 +6801,7 @@ _rleAppend(RLECTX *self, int c) /* Commit whatever was in the buffer. */ _rleCommit(self); - emit2 (".db -%u,0x%02X", self->runLen, self->last); + emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last); self->runLen = 0; } self->runLen++; @@ -6070,16 +6835,10 @@ genArrayInit (iCode * ic) aopOp (IC_LEFT(ic), ic, FALSE, FALSE); - if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) - { - /* Emit the support function call and the destination address. */ - emit2("call __initrleblock"); - emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0)); - } - else - { - wassertl (0, "Unexpected operand to genArrayInit.\n"); - } + _saveRegsForCall(ic, 0); + + fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); + emit2 ("call __initrleblock"); type = operandType(IC_LEFT(ic)); @@ -6123,9 +6882,289 @@ genArrayInit (iCode * ic) /* Mark the end of the run. */ emit2(".db 0"); + _restoreRegsAfterCall(); + + spillCached (); + freeAsmop (IC_LEFT(ic), NULL, ic); } +static void +_swap (PAIR_ID one, PAIR_ID two) +{ + if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE)) + { + emit2 ("ex de,hl"); + } + else + { + emit2 ("ld a,%s", _pairs[one].l); + emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l); + emit2 ("ld %s,a", _pairs[two].l); + emit2 ("ld a,%s", _pairs[one].h); + emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h); + emit2 ("ld %s,a", _pairs[two].h); + } +} + +/* 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) +{ + PAIR_ID ids[NUM_PAIRS][NUM_PAIRS]; + PAIR_ID dest[3] = { + PAIR_BC, PAIR_HL, PAIR_DE + }; + int i, j, nunity = 0; + memset (ids, PAIR_INVALID, sizeof (ids)); + + /* 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); + ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE; + } + + /* Count the number of unity or iTemp assigns. */ + for (i = 0; i < 3; i++) + { + if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE) + { + nunity++; + } + } + + if (nunity == 3) + { + /* Any order, fall through. */ + } + else if (nunity == 2) + { + /* One is assigned. Pull it out and assign. */ + for (i = 0; i < 3; i++) + { + for (j = 0; j < NUM_PAIRS; j++) + { + if (ids[dest[i]][j] == TRUE) + { + /* Found it. See if it's the right one. */ + if (j == PAIR_INVALID || j == dest[i]) + { + /* Keep looking. */ + } + else + { + fetchPair(dest[i], AOP (pparams[i])); + goto done; + } + } + } + } + } + else if (nunity == 1) + { + /* Find the pairs to swap. */ + for (i = 0; i < 3; i++) + { + for (j = 0; j < NUM_PAIRS; j++) + { + if (ids[dest[i]][j] == TRUE) + { + if (j == PAIR_INVALID || j == dest[i]) + { + /* Keep looking. */ + } + else + { + _swap (j, dest[i]); + goto done; + } + } + } + } + } + else + { + int next = getPairId (AOP (pparams[0])); + emit2 ("push %s", _pairs[next].name); + + if (next == dest[1]) + { + fetchPair (dest[1], AOP (pparams[1])); + fetchPair (dest[2], AOP (pparams[2])); + } + else + { + fetchPair (dest[2], AOP (pparams[2])); + fetchPair (dest[1], AOP (pparams[1])); + } + emit2 ("pop %s", _pairs[dest[0]].name); + } + done: + /* Finally pull out all of the iTemps */ + for (i = 0; i < 3; i++) + { + if (ids[dest[i]][PAIR_INVALID] == 1) + { + fetchPair (dest[i], AOP (pparams[i])); + } + } +} + +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"); + to = pparams[2]; + from = pparams[1]; + count = pparams[0]; + + deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX); + + setupForBuiltin3 (ic, nParams, pparams); + + emit2 ("ldir"); + + freeAsmop (count, NULL, ic->next->next); + freeAsmop (from, NULL, ic); + + _restoreRegsAfterCall(); + + /* 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); + movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2); + freeAsmop (IC_RESULT (ic), NULL, ic); + } + + freeAsmop (to, NULL, ic->next); +} + +/*-----------------------------------------------------------------*/ +/* genBuiltIn - calls the appropriate function to generating code */ +/* for a built in function */ +/*-----------------------------------------------------------------*/ +static void genBuiltIn (iCode *ic) +{ + operand *bi_parms[MAX_BUILTIN_ARGS]; + int nbi_parms; + iCode *bi_iCode; + symbol *bif; + + /* get all the arguments for a built in function */ + bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms); + + /* 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) + { + genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms); + } + else + { + wassertl (0, "Unknown builtin function encountered"); + } +} + /*-----------------------------------------------------------------*/ /* genZ80Code - generate code for Z80 based controllers */ /*-----------------------------------------------------------------*/ @@ -6393,11 +7432,20 @@ genZ80Code (iCode * lic) break; case SEND: - emitDebug ("; addSet"); - addSet (&_G.sendSet, ic); + if (ic->builtinSEND) + { + emitDebug ("; genBuiltIn"); + genBuiltIn(ic); + } + else + { + emitDebug ("; addSet"); + addSet (&_G.sendSet, ic); + } break; case ARRAYINIT: + emitDebug ("; genArrayInit"); genArrayInit(ic); break;