X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=826a2cf4114a071b472c5e33bd82f7907fab601e;hb=0b44824662442b40830512786321baa59f2d3a97;hp=9e88369d51596624c9c8b7069bf31639fa9529f3;hpb=faf36532f8fe1cff757958cb6a222c141f1eeaa4;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 9e88369d..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 = 1 + 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,17 +168,13 @@ 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 #define ACC_NAME _pairs[PAIR_AF].h -#define RESULTONSTACK(x) \ - (IC_RESULT(x) && IC_RESULT(x)->aop && \ - IC_RESULT(x)->aop->type == AOP_STK ) - enum { LSB, @@ -220,12 +224,60 @@ static struct lineNode *head; lineNode *current; int isInline; + allocTrace trace; } lines; + struct + { + allocTrace aops; + } trace; } _G; 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) { @@ -245,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) { @@ -268,6 +373,17 @@ _tidyUp (char *buf) } } +static lineNode * +_newLineNode (char *line) +{ + lineNode *pl; + + pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode))); + pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line)); + + return pl; +} + static void _vemit2 (const char *szFormat, va_list ap) { @@ -277,8 +393,8 @@ _vemit2 (const char *szFormat, va_list ap) _tidyUp (buffer); _G.lines.current = (_G.lines.current ? - connectLine (_G.lines.current, newLineNode (buffer)) : - (_G.lines.head = newLineNode (buffer))); + connectLine (_G.lines.current, _newLineNode (buffer)) : + (_G.lines.head = _newLineNode (buffer))); _G.lines.current->isInline = _G.lines.isInline; } @@ -336,8 +452,8 @@ _emit2 (const char *inst, const char *fmt,...) if (lbp && *lbp) { _G.lines.current = (_G.lines.current ? - connectLine (_G.lines.current, newLineNode (lb)) : - (_G.lines.head = newLineNode (lb))); + connectLine (_G.lines.current, _newLineNode (lb)) : + (_G.lines.head = _newLineNode (lb))); } _G.lines.current->isInline = _G.lines.isInline; va_end (ap); @@ -357,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) { @@ -388,22 +518,18 @@ 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; + } + } } - wassert (0); + wassertl (0, "Tried to get the pair name of something that isn't a pair"); return NULL; } @@ -427,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; } @@ -467,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) @@ -486,6 +616,7 @@ _pop (PAIR_ID pairId) { emit2 ("pop %s", _pairs[pairId].name); _G.stack.pushed -= 2; + spillPair (pairId); } /*-----------------------------------------------------------------*/ @@ -496,7 +627,7 @@ newAsmop (short type) { asmop *aop; - aop = Safe_calloc (1, sizeof (asmop)); + aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop))); aop->type = type; return aop; } @@ -518,13 +649,28 @@ 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) { - emitDebug ("; AOP_STK for %s", sym->rname); - sym->aop = aop = newAsmop (AOP_STK); + /* The pointer that is used depends on how big the offset is. + 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 < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type)))) + { + emitDebug ("; AOP_EXSTK for %s", sym->rname); + sym->aop = aop = newAsmop (AOP_EXSTK); + } + else + { + emitDebug ("; AOP_STK for %s", sym->rname); + sym->aop = aop = newAsmop (AOP_STK); + } + aop->size = getSize (sym->type); aop->aopu.aop_stk = sym->stack; return aop; @@ -534,8 +680,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) if (IS_FUNC (sym->type)) { sym->aop = aop = newAsmop (AOP_IMMD); - aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1); - strcpy (aop->aopu.aop_immd, sym->rname); + aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname)); aop->size = 2; return aop; } @@ -601,8 +746,7 @@ aopForRemat (symbol * sym) break; } - aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1); - strcpy (aop->aopu.aop_immd, buffer); + aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); return aop; } @@ -744,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) @@ -792,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) @@ -802,35 +958,37 @@ 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 { - wassert (0); + wassertl (0, "Marked as being allocated into A or HL but is actually in neither"); } 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; } @@ -863,6 +1021,11 @@ freeAsmop (operand * op, asmop * aaop, iCode * ic) aop->freed = 1; + if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE) + { + _pop (aop->aopu.aop_pairId); + } + dealloc: /* all other cases just dealloc */ if (op) @@ -876,6 +1039,7 @@ dealloc: SPIL_LOC (op)->aop = NULL; } } + } bool @@ -897,7 +1061,6 @@ char * aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { char *s = buffer; - char *rs; /* depending on type */ switch (aop->type) @@ -918,7 +1081,7 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); } - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_LIT: { @@ -947,19 +1110,31 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) else tsprintf (buffer, "!constword", v); - return gc_strdup(buffer); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } 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: @@ -1002,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) { @@ -1024,6 +1192,8 @@ requiresHL (asmop * aop) case AOP_IY: case AOP_HL: case AOP_STK: + case AOP_EXSTK: + case AOP_HLREG: return TRUE; default: return FALSE; @@ -1052,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; } @@ -1060,23 +1230,56 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) } } _G.pairs[pairId].last_type = left->type; - _G.pairs[pairId].base = gc_strdup (base); + _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); } +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: @@ -1106,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); @@ -1119,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 @@ -1129,23 +1355,67 @@ fetchHL (asmop * aop) } static void -setupPair (PAIR_ID pairId, asmop * aop, int offset) +setupPairFromSP (PAIR_ID id, int offset) { - assert (pairId == PAIR_HL || pairId == PAIR_IY); + 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) +{ switch (aop->type) { case AOP_IY: + wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL"); fetchLitPair (pairId, aop, 0); break; + case AOP_HL: + wassertl (pairId == PAIR_HL, "AOP_HL must be in HL"); + fetchLitPair (pairId, aop, offset); _G.pairs[pairId].offset = offset; break; + + case AOP_EXSTK: + wassertl (IS_Z80, "Only the Z80 has an extended stack"); + wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL"); + + { + int offset = aop->aopu.aop_stk + _G.stack.offset; + + if (_G.pairs[pairId].last_type == aop->type && + _G.pairs[pairId].offset == offset) + { + /* Already setup */ + } + else + { + /* PENDING: Do this better. */ + sprintf (buffer, "%d", offset + _G.stack.pushed); + emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer); + emit2 ("add %s,sp", _pairs[pairId].name); + _G.pairs[pairId].last_type = aop->type; + _G.pairs[pairId].offset = offset; + } + } + break; + case AOP_STK: { /* 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; @@ -1158,11 +1428,16 @@ 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; } + + case AOP_PAIRPTR: + adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset); + break; + default: wassert (0); } @@ -1190,7 +1465,7 @@ aopGet (asmop * aop, int offset, bool bit16) aop->type != AOP_LIT) { tsprintf (s, "!zero"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); } /* depending on type */ @@ -1213,24 +1488,24 @@ aopGet (asmop * aop, int offset, bool bit16) tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd); break; default: - wassert (0); + wassertl (0, "Fetching from beyond the limits of an immediate value."); } - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_DIR: wassert (IS_GB); emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_SFR: wassert (IS_GB); emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_REG: return aop->aopu.aop_reg[offset]->name; @@ -1240,14 +1515,21 @@ aopGet (asmop * aop, int offset, bool bit16) setupPair (PAIR_HL, aop, offset); tsprintf (s, "!*hl"); - return gc_strdup (s); + return traceAlloc(&_G.trace.aops, Safe_strdup (s)); case AOP_IY: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); tsprintf (s, "!*iyx", offset); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + + case AOP_EXSTK: + wassert (IS_Z80); + setupPair (PAIR_IY, aop, offset); + tsprintf (s, "!*iyx", offset, offset); + + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_STK: if (IS_GB) @@ -1262,10 +1544,10 @@ aopGet (asmop * aop, int offset, bool bit16) tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset); } - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); case AOP_CRY: - wassert (0); + wassertl (0, "Tried to fetch from a bit variable"); case AOP_ACC: if (!offset) @@ -1275,7 +1557,7 @@ aopGet (asmop * aop, int offset, bool bit16) else { tsprintf(s, "!zero"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); } case AOP_HLREG: @@ -1292,12 +1574,18 @@ aopGet (asmop * aop, int offset, bool bit16) v >>= (offset * 8); tsprintf (s, "!immedbyte", (unsigned int) v & 0xff); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); } case AOP_STR: aop->coff = offset; return aop->aopu.aop_str[offset]; + case AOP_PAIRPTR: + setupPair (aop->aopu.aop_pairId, aop, offset); + sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name); + + return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + default: break; } @@ -1384,14 +1672,17 @@ aopPut (asmop * aop, const char *s, int offset) case AOP_IY: wassert (!IS_GB); - setupPair (PAIR_IY, aop, offset); if (!canAssignToPtr (s)) { emit2 ("ld a,%s", s); + setupPair (PAIR_IY, aop, offset); emit2 ("ld !*iyx,a", offset); } else - emit2 ("ld !*iyx,%s", offset, s); + { + setupPair (PAIR_IY, aop, offset); + emit2 ("ld !*iyx,%s", offset, s); + } break; case AOP_HL: @@ -1407,6 +1698,21 @@ aopPut (asmop * aop, const char *s, int offset) emit2 ("ld !*hl,%s", s); break; + case AOP_EXSTK: + wassert (!IS_GB); + if (!canAssignToPtr (s)) + { + emit2 ("ld a,%s", s); + setupPair (PAIR_IY, aop, offset); + emit2 ("ld !*iyx,a", offset); + } + else + { + setupPair (PAIR_IY, aop, offset); + emit2 ("ld !*iyx,%s", offset, s); + } + break; + case AOP_STK: if (IS_GB) { @@ -1435,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; @@ -1443,13 +1751,13 @@ 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 { /* In bit space but not in C - cant happen */ - wassert (0); + wassertl (0, "Tried to write into a bit variable"); } break; @@ -1481,6 +1789,11 @@ aopPut (asmop * aop, const char *s, int offset) emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); break; + case AOP_PAIRPTR: + setupPair (aop->aopu.aop_pairId, aop, offset); + emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); + break; + default: werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type"); @@ -1496,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"); @@ -1505,10 +1819,21 @@ 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); + } + } +} /*-----------------------------------------------------------------*/ /* getDataSize - get the operand data size */ @@ -1521,7 +1846,7 @@ getDataSize (operand * op) if (size == 3) { /* pointer */ - wassert (0); + wassertl (0, "Somehow got a three byte data pointer"); } return size; } @@ -1534,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); @@ -1553,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 */ @@ -1582,7 +1949,7 @@ outBitCLong (operand * result, bool swap_sense) /* if the result is bit */ if (AOP_TYPE (result) == AOP_CRY) { - aopPut (AOP (result), "blah", 0); + wassertl (0, "Tried to write carry to a bit"); } else { @@ -1625,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 */ /*-----------------------------------------------------------------*/ @@ -1640,13 +2045,14 @@ genNot (iCode * ic) /* if in bit space then a special case */ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to negate a bit"); } /* if type float then do float */ if (IS_FLOAT (optype)) { - wassert (0); + genNotFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; } _toBoolean (IC_LEFT (ic)); @@ -1658,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); @@ -1682,7 +2089,7 @@ genCpl (iCode * ic) if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) { - wassert (0); + wassertl (0, "Left and the result are in bit space"); } size = AOP_SIZE (IC_RESULT (ic)); @@ -1732,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); @@ -1752,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 */ /*-----------------------------------------------------------------*/ @@ -1770,7 +2203,7 @@ genUminus (iCode * ic) if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) { - wassert (0); + wassertl (0, "Left and right are in bit space"); goto release; } @@ -1780,7 +2213,7 @@ genUminus (iCode * ic) /* if float then do float stuff */ if (IS_FLOAT (optype)) { - wassert (0); + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); goto release; } @@ -1832,7 +2265,7 @@ assignResultValue (operand * oper) int size = AOP_SIZE (oper); bool topInA = 0; - wassert (size <= 4); + wassertl (size <= 4, "Got a result that is bigger than four bytes"); topInA = requiresHL (AOP (oper)); if (IS_GB && size == 4 && requiresHL (AOP (oper))) @@ -1854,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) { @@ -1959,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)))); @@ -1976,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; @@ -2119,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) @@ -2193,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); } @@ -2223,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); @@ -2267,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; } @@ -2388,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. @@ -2407,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) @@ -2416,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"); } @@ -2481,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"); @@ -2496,18 +2955,22 @@ genEndFunction (iCode * ic) { symbol *sym = OP_SYMBOL (IC_LEFT (ic)); - if (IS_ISR (sym->etype)) + if (IFFUNC_ISISR (sym->type)) { - wassert (0); + 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); } @@ -2539,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; @@ -2584,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 { @@ -2655,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; @@ -2671,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--) { @@ -2681,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) @@ -2712,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 */ @@ -2737,7 +3231,7 @@ outBitAcc (operand * result) /* if the result is a bit */ if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to write A into a bit"); } else { @@ -2748,6 +3242,86 @@ outBitAcc (operand * result) } } +bool +couldDestroyCarry (asmop *aop) +{ + if (aop) + { + if (aop->type == AOP_EXSTK || aop->type == AOP_IY) + { + return TRUE; + } + } + return FALSE; +} + +static void +shiftIntoPair (int idx, asmop *aop) +{ + PAIR_ID id = PAIR_INVALID; + + wassertl (IS_Z80, "Only implemented for the Z80"); + // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK"); + + switch (idx) + { + case 0: + id = PAIR_HL; + break; + case 1: + id = PAIR_DE; + _push (PAIR_DE); + break; + default: + wassertl (0, "Internal error - hit default case"); + } + + emitDebug ("; Shift into pair idx %u", idx); + + if (id == PAIR_HL) + { + setupPair (PAIR_HL, aop, 0); + } + else + { + setupPair (PAIR_IY, aop, 0); + emit2 ("push iy"); + emit2 ("pop %s", _pairs[id].name); + } + + aop->type = AOP_PAIRPTR; + aop->aopu.aop_pairId = id; + _G.pairs[id].offset = 0; + _G.pairs[id].last_type = aop->type; +} + +static void +setupToPreserveCarry (asmop *result, asmop *left, asmop *right) +{ + wassert (left && right); + + if (IS_Z80) + { + if (couldDestroyCarry (right) && couldDestroyCarry (result)) + { + shiftIntoPair (0, right); + shiftIntoPair (1, result); + } + else if (couldDestroyCarry (right)) + { + shiftIntoPair (0, right); + } + else if (couldDestroyCarry (result)) + { + shiftIntoPair (0, result); + } + else + { + /* Fine */ + } + } +} + /*-----------------------------------------------------------------*/ /* genPlus - generates code for addition */ /*-----------------------------------------------------------------*/ @@ -2783,7 +3357,7 @@ genPlus (iCode * ic) AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY) { /* Cant happen */ - wassert (0); + wassertl (0, "Tried to add two bits"); } /* if left in bit space & right literal */ @@ -2791,7 +3365,7 @@ genPlus (iCode * ic) AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT) { /* Can happen I guess */ - wassert (0); + wassertl (0, "Tried to add a bit to a literal"); } /* if I can do an increment instead @@ -2822,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; } @@ -2902,6 +3512,8 @@ genPlus (iCode * ic) } } + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); + while (size--) { if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC) @@ -2967,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; @@ -3026,7 +3637,7 @@ genMinus (iCode * ic) if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to subtract two bits"); goto release; } @@ -3080,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; } @@ -3095,6 +3709,8 @@ genMinus (iCode * ic) } } + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); + /* if literal, add a,#-lit, else normal subb */ while (size--) { @@ -3122,7 +3738,9 @@ genMinus (iCode * ic) if (AOP_SIZE (IC_RESULT (ic)) == 3 && AOP_SIZE (IC_LEFT (ic)) == 3 && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)))) - wassert (0); + { + wassertl (0, "Tried to subtract on a long pointer"); + } release: freeAsmop (IC_LEFT (ic), NULL, ic); @@ -3136,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 */ - wassert (0); + 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); } /*-----------------------------------------------------------------*/ @@ -3147,7 +3851,7 @@ static void genDiv (iCode * ic) { /* Shouldn't occur - all done through function calls */ - wassert (0); + wassertl (0, "Division is handled through support function calls"); } /*-----------------------------------------------------------------*/ @@ -3186,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 */ @@ -3208,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 */ @@ -3225,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); @@ -3243,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 */ - wassert (0); - } - 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)) @@ -3297,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"); @@ -3321,6 +4024,43 @@ genCmp (operand * left, operand * right, } spillPair (PAIR_HL); } + else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left))) + { + setupPair (PAIR_HL, AOP (left), 0); + aopGet (AOP(right), LSB, FALSE); + + while (size--) + { + if (size == 0 && sign) + { + // Highest byte when signed needs the bits flipped + // Save the flags + emit2 ("push af"); + emit2 ("ld a,(hl)"); + emit2 ("xor !immedbyte", 0x80); + emit2 ("ld l,a"); + emit2 ("ld a,%d(iy)", offset); + emit2 ("xor !immedbyte", 0x80); + emit2 ("ld h,a"); + emit2 ("pop af"); + emit2 ("ld a,l"); + emit2 ("%s a,h", offset == 0 ? "sub" : "sbc"); + } + else + { + emit2 ("ld a,(hl)"); + emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset); + } + + if (size != 0) + { + emit2 ("inc hl"); + } + offset++; + } + spillPair (PAIR_HL); + spillPair (PAIR_IY); + } else { if (AOP_TYPE (right) == AOP_LIT) @@ -3349,6 +4089,7 @@ genCmp (operand * left, operand * right, goto release; } } + if (sign) { /* First setup h and l contaning the top most bytes XORed */ @@ -3397,15 +4138,115 @@ genCmp (operand * left, operand * right, else { /* Subtract through, propagating the carry */ - emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE)); + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE)); + offset++; } } } } +#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 @@ -3414,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 */ } } @@ -3499,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 && @@ -3510,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 @@ -3602,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. @@ -3621,7 +4486,7 @@ genCmpEq (iCode * ic, iCode * ifx) if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) { - wassert (0); + wassertl (0, "Tried to compare two bits"); } else { @@ -3651,10 +4516,12 @@ genCmpEq (iCode * ic, iCode * ifx) if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) { - wassert (0); + wassertl (0, "Tried to compare a bit to either a literal or another bit"); } else { + emitDebug(";4"); + gencjne (left, right, newiTempLabel (NULL)); if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) { @@ -3662,6 +4529,7 @@ genCmpEq (iCode * ic, iCode * ifx) } if (ifx) { + emitDebug(";5"); genIfxJump (ifx, "a"); goto release; } @@ -3669,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 */ @@ -3722,7 +4591,7 @@ genAndOp (iCode * ic) if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to and two bits"); } else { @@ -3759,7 +4628,7 @@ genOrOp (iCode * ic) if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to OR two bits"); } else { @@ -3868,7 +4737,7 @@ genAnd (iCode * ic, iCode * ifx) if (AOP_TYPE (left) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to perform an AND with a bit as an operand"); goto release; } @@ -3878,80 +4747,46 @@ genAnd (iCode * ic, iCode * ifx) (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY)) { - int posbit = isLiteralBit (lit); - /* left & 2^n */ - if (posbit) - { - posbit--; - _moveA (aopGet (AOP (left), posbit >> 3, FALSE)); - // bit = left & 2^n - if (size) - { - wassert (0); - emit2 ("mov c,acc.%d", posbit & 0x07); - } - // if(left & 2^n) - else - { - if (ifx) - { - sprintf (buffer, "%d", posbit & 0x07); - genIfxJump (ifx, buffer); - } - else - { - wassert (0); - } - goto release; - } - } - else - { - symbol *tlbl = newiTempLabel (NULL); - int sizel = AOP_SIZE (left); - if (size) - { - wassert (0); - emit2 ("setb c"); - } - while (sizel--) - { - if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L) - { - _moveA (aopGet (AOP (left), offset, FALSE)); - // byte == 2^n ? - if ((posbit = isLiteralBit (bytelit)) != 0) - { - wassert (0); - emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100); - } - else - { - if (bytelit != 0x0FFL) - emit2 ("and a,%s", - aopGet (AOP (right), offset, FALSE)); - else - /* For the flags */ - emit2 ("or a,a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - } - } + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + if (size) + { + /* PENDING: Test case for this. */ + emit2 ("scf"); + } + while (sizel--) + { + if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L) + { + _moveA (aopGet (AOP (left), offset, FALSE)); + if (bytelit != 0x0FFL) + { + emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE)); + } + else + { + /* For the flags */ + emit2 ("or a,a"); + } + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); + } offset++; - } - // bit = left & literal - if (size) - { - emit2 ("clr c"); - emit2 ("!tlabeldef", tlbl->key + 100); - } - // if(left & literal) - else - { - if (ifx) - jmpTrueOrFalse (ifx, tlbl); - goto release; - } - } + } + // bit = left & literal + if (size) + { + emit2 ("clr c"); + emit2 ("!tlabeldef", tlbl->key + 100); + } + // if(left & literal) + else + { + if (ifx) + { + jmpTrueOrFalse (ifx, tlbl); + } + goto release; + } outBitC (result); goto release; } @@ -3983,7 +4818,7 @@ genAnd (iCode * ic, iCode * ifx) { if (AOP_TYPE (left) == AOP_ACC) { - wassert (0); + wassertl (0, "Tried to perform an AND where the left operand is allocated into A"); } else { @@ -4000,7 +4835,7 @@ genAnd (iCode * ic, iCode * ifx) // left & result in different registers if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to AND where the result is in carry"); } else { @@ -4054,6 +4889,7 @@ genOr (iCode * ic, iCode * ifx) operand *left, *right, *result; int size, offset = 0; unsigned long lit = 0L; + int bytelit = 0; aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE); aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); @@ -4091,15 +4927,39 @@ genOr (iCode * ic, iCode * ifx) if (AOP_TYPE (left) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to OR where left is a bit"); goto release; } + // if(val | 0xZZ) - size = 0, ifx != FALSE - + // bit = val | 0xZZ - size = 1, ifx = FALSE - if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY)) { - wassert (0); + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + + if (size) + { + wassertl (0, "Result is assigned to a bit"); + } + /* PENDING: Modeled after the AND code which is inefficent. */ + while (sizel--) + { + 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); + + offset++; + } + if (ifx) + { + jmpTrueOrFalse (ifx, tlbl); + } goto release; } @@ -4139,7 +4999,7 @@ genOr (iCode * ic, iCode * ifx) // left & result in different registers if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Result of OR is in a bit"); } else for (; (size--); offset++) @@ -4225,15 +5085,39 @@ genXor (iCode * ic, iCode * ifx) if (AOP_TYPE (left) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to XOR a bit"); goto release; } + // if(val & 0xZZ) - size = 0, ifx != FALSE - + // bit = val & 0xZZ - size = 1, ifx = FALSE - if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY)) { - wassert (0); + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + + if (size) + { + /* PENDING: Test case for this. */ + wassertl (0, "Tried to XOR left against a literal with the result going into a bit"); + } + while (sizel--) + { + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); + offset++; + } + if (ifx) + { + jmpTrueOrFalse (ifx, tlbl); + } + else + { + wassertl (0, "Result of XOR was destined for a bit"); + } goto release; } @@ -4275,7 +5159,7 @@ genXor (iCode * ic, iCode * ifx) // left & result in different registers if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Result of XOR is in a bit"); } else for (; (size--); offset++) @@ -4383,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); @@ -4397,8 +5282,7 @@ genGetHbit (iCode * ic) else { emit2 ("rlc a"); - /* PENDING: For re-target. */ - emit2 ("and a,#1"); + emit2 ("and a,!one"); outAcc (result); } @@ -4486,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; @@ -5091,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))) @@ -5108,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); @@ -5128,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++); } @@ -5145,6 +6086,8 @@ genGenPointerGet (operand * left, } } + freeAsmop (left, NULL, ic); + release: freeAsmop (result, NULL, ic); } @@ -5172,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; } @@ -5187,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); @@ -5211,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 */ @@ -5228,7 +6226,6 @@ genGenPointerSet (operand * right, } else { - size = AOP_SIZE (right); offset = 0; while (size--) @@ -5330,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 { @@ -5353,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); } @@ -5401,7 +6395,7 @@ genAssign (iCode * ic) /* if the result is a bit */ if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to assign to a bit"); } /* general case */ @@ -5409,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) && @@ -5450,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. */ @@ -5485,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); @@ -5543,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; @@ -5557,7 +6560,7 @@ genCast (iCode * ic) /* if the result is a bit */ if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to cast to a bit"); } /* if they are the same size : or less */ @@ -5597,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++); @@ -5773,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 { @@ -5798,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++; @@ -5832,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)); @@ -5885,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 */ /*-----------------------------------------------------------------*/ @@ -5897,7 +7174,7 @@ genZ80Code (iCode * lic) iCode *ic; int cln = 0; - /* HACK */ + /* Hack */ if (IS_GB) { _fReturn = _gbz80_return; @@ -6155,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; @@ -6188,6 +7474,9 @@ genZ80Code (iCode * lic) } codeOutFile = fp; } + + freeTrace(&_G.lines.trace); + freeTrace(&_G.trace.aops); } /* @@ -6228,7 +7517,7 @@ fetchLitSpecial (asmop * aop, bool negate, bool xor) v &= 0xFFFF; tsprintf (buffer, "!immedword", v); - return gc_strdup (buffer); + return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); }