X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=72d5726683ebcc6742b85efb135b77742e0331a3;hb=195ee3f3ee25ce2c5f2a59fbd2779c4cb80527c3;hp=ffef364818ec9c0c860d9fd2d5943f6694de1c8e;hpb=2ee35049f829fc523bab32504f31cfdef6745757;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index ffef3648..72d57266 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -1,25 +1,7 @@ /*------------------------------------------------------------------------- gen.c - Z80 specific code generator. - - Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock: - ticks dhry size - Base with asm strcpy / strcmp / memcpy: 23198 141 1A14 - Improved WORD push 22784 144 19AE - With label1 on 22694 144 197E - With label2 on 22743 144 198A - With label3 on 22776 144 1999 - With label4 on 22776 144 1999 - With all 'label' on 22661 144 196F - With loopInvariant on 20919 156 19AB - With loopInduction on Breaks 198B - With all working on 20796 158 196C - Slightly better genCmp(signed) 20597 159 195B - Better reg packing, first peephole 20038 163 1873 - With assign packing 19281 165 1849 - 5/3/00 17741 185 17B6 - With reg params for mul and div 16234 202 162D - - Michael Hope 2000 + + Michael Hope 2000 Based on the mcs51 generator - Sandeep Dutta . sandeep.dutta@usa.net (1998) and - Jean-Louis VERN.jlvern@writeme.com (1999) @@ -45,13 +27,70 @@ -------------------------------------------------------------------------*/ +/* + Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock: + ticks dhry size + Base with asm strcpy / strcmp / memcpy: 23198 141 1A14 + Improved WORD push 22784 144 19AE + With label1 on 22694 144 197E + With label2 on 22743 144 198A + With label3 on 22776 144 1999 + With label4 on 22776 144 1999 + With all 'label' on 22661 144 196F + With loopInvariant on 20919 156 19AB + With loopInduction on Breaks 198B + With all working on 20796 158 196C + Slightly better genCmp(signed) 20597 159 195B + Better reg packing, first peephole 20038 163 1873 + With assign packing 19281 165 1849 + 5/3/00 17741 185 17B6 + With reg params for mul and div 16234 202 162D + + 1. Starting again at 3 Aug 01 34965 93 219C + No asm strings + Includes long mul/div in code + 2. Optimised memcpy for acc use 32102 102 226B + 3. Optimised strcpy for acc use 27819 117 2237 + 3a Optimised memcpy fun + 4. Optimised strcmp fun 21999 149 2294 + 5. Optimised strcmp further 21660 151 228C + 6. Optimised memcpy by unroling 20885 157 2201 + 7. After turning loop induction on 19862 165 236D + 8. Same as 7 but with more info + 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 + - ld hl,#n; push hl: (10+11)*nargs + 2. Cost of pull from stack + Using asm with ld hl, etc + - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs + 10+11+(7+6+7+6)*nargs + 3. Cost of fixing stack + - pop hl*nargs + 10*nargs + + So cost is (10+11+7+6+7+10)*nargs+10+11 + = 51*nargs+21 + = 123 for mul, div, strcmp, strcpy + Saving of (98298+32766+32766+32766)*123 = 24181308 + At 192 d/s for 682411768t, speed up to 199. Hmm. +*/ + #include #include #include #include -#ifdef HAVE_SYS_ISA_DEFS_H -#include +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp #endif #include "z80.h" @@ -61,7 +100,7 @@ #include "SDCCglue.h" #include "newalloc.h" -/* this is the down and dirty file with all kinds of kludgy & hacky +/* This is the down and dirty file with all kinds of kludgy & hacky stuff. This is what it is all about CODE GENERATION for a specific MCU. Some of the routines may be reusable, will have to see */ @@ -73,7 +112,7 @@ PENDING: What if the parameter is a long? Everything is caller saves. i.e. the caller must save any registers that it wants to preserve over the call. - The return value is returned in DEHL. DE is normally used as a + GB: The return value is returned in DEHL. DE is normally used as a working register pair. Caller saves allows it to be used for a return value. va args functions do not use register parameters. All arguments @@ -81,6 +120,13 @@ IX is used as an index register to the top of the local variable area. ix-0 is the top most local variable. */ + +enum +{ + /* Set to enable debugging trace statements in the output assembly code. */ + DISABLE_DEBUG = 0 +}; + static char *_z80_return[] = {"l", "h", "e", "d"}; static char *_gbz80_return[] = @@ -93,6 +139,14 @@ static char **_fTmp; extern FILE *codeOutFile; +enum + { + INT8MIN = -128, + INT8MAX = 127 + }; + +/** Enum covering all the possible register pairs. + */ typedef enum { PAIR_INVALID, @@ -116,17 +170,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, @@ -135,12 +185,17 @@ enum MSB32 }; +/** Code generator persistent data. + */ static struct { + /** Used to optimised setting up of a pair by remebering what it + contains and adjusting instead of reloading where possible. + */ struct { AOP_TYPE last_type; - const char *lit; + const char *base; int offset; } pairs[NUM_PAIRS]; struct @@ -152,12 +207,22 @@ static struct int pushedBC; int pushedDE; } stack; + + struct + { + int pushedBC; + int pushedDE; + } calleeSaves; + + bool omitFramePtr; int frameId; int receiveOffset; bool flushStatics; bool in_home; const char *lastFunctionName; - + iCode *current_iCode; + bool preserveCarry; + set *sendSet; struct @@ -171,12 +236,134 @@ static struct lineNode *head; lineNode *current; int isInline; + int isDebug; + 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", + "AOP_DUMMY" +}; + +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) +{ + if (IS_GB) + { + return PAIR_DE; + } + else + { + return PAIR_HL; + } +} + +static const char * +_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) { @@ -200,22 +387,72 @@ _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) +{ + char buffer[INITIAL_INLINEASM]; + + tvsprintf (buffer, sizeof(buffer), szFormat, ap); + + _tidyUp (buffer); + _G.lines.current = (_G.lines.current ? + connectLine (_G.lines.current, _newLineNode (buffer)) : + (_G.lines.head = _newLineNode (buffer))); + + _G.lines.current->isInline = _G.lines.isInline; + _G.lines.current->isDebug = _G.lines.isDebug; + _G.lines.current->ic = _G.current_iCode; +} + static void emit2 (const char *szFormat,...) { - char buffer[256]; va_list ap; va_start (ap, szFormat); - tvsprintf (buffer, szFormat, ap); + _vemit2 (szFormat, ap); - _tidyUp (buffer); - _G.lines.current = (_G.lines.current ? - connectLine (_G.lines.current, newLineNode (buffer)) : - (_G.lines.head = newLineNode (buffer))); + va_end (ap); +} - _G.lines.current->isInline = _G.lines.isInline; +static void +emitDebug (const char *szFormat,...) +{ + if (!DISABLE_DEBUG) + { + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); + } +} + +/*-----------------------------------------------------------------*/ +/* z80_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +z80_emitDebuggerSymbol (char * debugSym) +{ + _G.lines.isDebug = 1; + emit2 ("%s !equ .", debugSym); + emit2 ("!global", debugSym); + _G.lines.isDebug = 0; } /*-----------------------------------------------------------------*/ @@ -226,7 +463,7 @@ _emit2 (const char *inst, const char *fmt,...) { va_list ap; char lb[INITIAL_INLINEASM]; - char *lbp = lb; + unsigned char *lbp = lb; va_start (ap, fmt); @@ -244,17 +481,18 @@ _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; + _G.lines.current->ic = _G.current_iCode; va_end (ap); } static void _emitMove(const char *to, const char *from) { - if (strcasecmp(to, from) != 0) + if (STRCASECMP(to, from) != 0) { emit2("ld %s,%s", to, from); } @@ -265,6 +503,35 @@ _emitMove(const char *to, const char *from) } } +void +aopDump(const char *plabel, asmop *aop) +{ + int i; + char regbuf[9]; + char *rbp = regbuf; + + emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size); + switch (aop->type) + { + case AOP_EXSTK: + case AOP_STK: + emitDebug("; aop_stk %d", aop->aopu.aop_stk); + break; + case AOP_REG: + for (i=aop->size-1;i>=0;i--) + *rbp++ = *(aop->aopu.aop_reg[i]->name); + *rbp = '\0'; + emitDebug("; reg = %s", regbuf); + break; + case AOP_PAIRPTR: + emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name); + + default: + /* No information. */ + break; + } +} + static void _moveA(const char *moveFrom) { @@ -296,22 +563,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; } @@ -335,21 +598,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; } @@ -361,6 +620,22 @@ isPair (asmop * aop) return (getPairId (aop) != PAIR_INVALID); } +/** Returns TRUE if the registers used in aop cannot be split into high + and low halves */ +bool +isUnsplitable (asmop * aop) +{ + switch (getPairId (aop)) + { + case PAIR_IX: + case PAIR_IY: + return TRUE; + default: + return FALSE; + } + return FALSE; +} + bool isPtrPair (asmop * aop) { @@ -375,6 +650,38 @@ isPtrPair (asmop * aop) return FALSE; } } + +static void +spillPair (PAIR_ID pairId) +{ + _G.pairs[pairId].last_type = AOP_INVALID; + _G.pairs[pairId].base = NULL; +} + +/* Given a register name, spill the pair (if any) the register is part of */ +static void +spillPairReg (const char *regname) +{ + if (strlen(regname)==1) + { + switch (*regname) + { + case 'h': + case 'l': + spillPair(PAIR_HL); + break; + case 'd': + case 'e': + spillPair(PAIR_DE); + break; + case 'b': + case 'c': + spillPair(PAIR_BC); + break; + } + } +} + /** Push a register pair onto the stack */ void genPairPush (asmop * aop) @@ -382,28 +689,75 @@ genPairPush (asmop * aop) emit2 ("push %s", getPairName (aop)); } - -/*-----------------------------------------------------------------*/ -/* newAsmop - creates a new asmOp */ -/*-----------------------------------------------------------------*/ -static asmop * -newAsmop (short type) +static void +_push (PAIR_ID pairId) { - asmop *aop; - - aop = Safe_calloc (1, sizeof (asmop)); - aop->type = type; - return aop; + emit2 ("push %s", _pairs[pairId].name); + _G.stack.pushed += 2; } -/*-----------------------------------------------------------------*/ -/* aopForSym - for a true symbol */ -/*-----------------------------------------------------------------*/ -static asmop * -aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) +static void +_pop (PAIR_ID pairId) { - asmop *aop; - memmap *space; + emit2 ("pop %s", _pairs[pairId].name); + _G.stack.pushed -= 2; + spillPair (pairId); +} + +void +genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair) +{ + switch (dstPair) + { + case PAIR_IX: + case PAIR_IY: + case PAIR_AF: + _push(srcPair); + _pop(dstPair); + break; + case PAIR_BC: + case PAIR_DE: + case PAIR_HL: + if (srcPair == PAIR_IX || srcPair == PAIR_IY) + { + _push(srcPair); + _pop(dstPair); + } + else + { + emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l); + emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h); + } + default: + wassertl (0, "Tried to move a nonphysical pair"); + } + _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type; + _G.pairs[dstPair].base = _G.pairs[srcPair].base; + _G.pairs[dstPair].offset = _G.pairs[srcPair].offset; +} + + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop * +newAsmop (short type) +{ + asmop *aop; + + aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop))); + aop->type = type; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) +{ + asmop *aop; + memmap *space; wassert (ic); wassert (sym); @@ -413,13 +767,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) { - emit2 ("; 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 && (_G.omitFramePtr || 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; @@ -429,30 +798,45 @@ 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; } - if (IS_GB) + if( IN_REGSP( space )) + { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */ + if (IS_GB) { /* if it is in direct space */ - if (IN_REGSP (space) && !requires_a) - { - sym->aop = aop = newAsmop (AOP_SFR); - aop->aopu.aop_dir = sym->rname; - aop->size = getSize (sym->type); - emit2 ("; AOP_SFR for %s", sym->rname); - return aop; - } + if( !requires_a ) + { + sym->aop = aop = newAsmop (AOP_SFR); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + emitDebug ("; AOP_SFR for %s", sym->rname); + return aop; + } + } + else + { /*.p.t.20030716 adding SFR support to the Z80 port */ + aop = newAsmop (AOP_SFR); + sym->aop = aop; + aop->aopu.aop_dir = sym->rname; + aop->size = getSize( sym->type ); + aop->paged = FUNC_REGBANK(sym->type); + aop->bcInUse = isPairInUse( PAIR_BC, ic ); + aop->deInUse = isPairInUse( PAIR_DE, ic ); + emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse ); + + return( aop ); } + } /* only remaining is far space */ /* in which case DPTR gets the address */ if (IS_GB) { - emit2 ("; AOP_HL for %s", sym->rname); + emitDebug ("; AOP_HL for %s", sym->rname); sym->aop = aop = newAsmop (AOP_HL); } else @@ -496,8 +880,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; } @@ -564,10 +947,10 @@ operandsEqu (operand * op1, operand * op2) if (sym1 == sym2) return 1; - if (strcmp (sym1->rname, sym2->rname) == 0) + if (sym1->rname[0] && sym2->rname[0] + && strcmp (sym1->rname, sym2->rname) == 0) return 2; - /* if left is a tmp & right is not */ if (IS_ITEMP (op1) && !IS_ITEMP (op2) && @@ -639,12 +1022,24 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) /* if already has a asmop then continue */ if (op->aop) - return; + { + if (op->aop->type == AOP_SFR) + { + op->aop->bcInUse = isPairInUse( PAIR_BC, ic ); + op->aop->deInUse = isPairInUse( PAIR_DE, ic ); + } + return; + } /* if the underlying symbol has a aop */ if (IS_SYMOP (op) && OP_SYMBOL (op)->aop) { op->aop = OP_SYMBOL (op)->aop; + if (op->aop->type == AOP_SFR) + { + op->aop->bcInUse = isPairInUse( PAIR_BC, ic ); + op->aop->deInUse = isPairInUse( PAIR_DE, ic ); + } return; } @@ -687,6 +1082,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) @@ -697,35 +1102,44 @@ 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); + if (sym->usl.spillLoc) + { + if (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); aop->size = getSize (sym->type); - for (i = 0; i < 4; i++) - aop->aopu.aop_str[i] = _fReturn[i]; return; - } - - /* else spill location */ - sym->aop = op->aop = aop = - aopForSym (ic, sym->usl.spillLoc, result, requires_a); + } + + /* else must be a dummy iTemp */ + sym->aop = op->aop = aop = newAsmop (AOP_DUMMY); aop->size = getSize (sym->type); return; } @@ -758,6 +1172,16 @@ 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); + } + + if (getPairId (aop) == PAIR_HL) + { + spillPair (PAIR_HL); + } + dealloc: /* all other cases just dealloc */ if (op) @@ -771,6 +1195,7 @@ dealloc: SPIL_LOC (op)->aop = NULL; } } + } bool @@ -791,13 +1216,6 @@ isLitWord (asmop * aop) char * aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { - char *s = buffer; - char *rs; - -#if 0 - if (aop->size != 2 && aop->type != AOP_HL) - return NULL; -#endif /* depending on type */ switch (aop->type) { @@ -806,12 +1224,22 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) case AOP_IMMD: /* PENDING: for re-target */ if (with_hash) - tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset); + { + tsprintf (buffer, sizeof(buffer), + "!hashedstr + %d", aop->aopu.aop_immd, offset); + } + else if (offset == 0) + { + tsprintf (buffer, sizeof(buffer), + "%s", aop->aopu.aop_immd); + } else - tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + { + tsprintf (buffer, sizeof(buffer), + "%s + %d", aop->aopu.aop_immd, offset); + } + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + case AOP_LIT: { value *val = aop->aopu.aop_lit; @@ -822,26 +1250,48 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) unsigned long v = (unsigned long) floatFromVal (val); if (offset == 2) - v >>= 16; + { + v >>= 16; + } + else if (offset == 0) + { + // OK + } + else + { + wassertl(0, "Encountered an invalid offset while fetching a literal"); + } if (with_hash) - tsprintf (buffer, "!immedword", v); + tsprintf (buffer, sizeof(buffer), "!immedword", v); else - tsprintf (buffer, "!constword", v); - rs = Safe_calloc (1, strlen (buffer) + 1); - return strcpy (rs, buffer); + tsprintf (buffer, sizeof(buffer), "!constword", v); + + 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 WORDS_BIGENDIAN + 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, sizeof(buffer), "!immedword", i); else - tsprintf (buffer, "!constword", f.w[offset / 2]); - rs = Safe_calloc (1, strlen (buffer) + 1); - return strcpy (rs, buffer); + tsprintf (buffer, sizeof(buffer), "!constword", i); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } } default: @@ -884,13 +1334,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].lit = NULL; -} - static void spillCached (void) { @@ -906,40 +1349,22 @@ requiresHL (asmop * aop) case AOP_IY: case AOP_HL: case AOP_STK: + case AOP_EXSTK: + case AOP_HLREG: return TRUE; default: return FALSE; } } -static char * -fetchLitSpecial (asmop * aop, bool negate, bool xor) -{ - unsigned long v; - value *val = aop->aopu.aop_lit; - - wassert (aop->type == AOP_LIT); - wassert (!IS_FLOAT (val->type)); - - v = (unsigned long) floatFromVal (val); - - if (xor) - v ^= 0x8000; - if (negate) - v = 0-v; - v &= 0xFFFF; - - tsprintf (buffer, "!immedword", v); - return gc_strdup (buffer); -} - static void fetchLitPair (PAIR_ID pairId, asmop * left, int offset) { - const char *l; + const char *l, *base; const char *pair = _pairs[pairId].name; - l = aopGetLitWordLong (left, 0, FALSE); - wassert (l && pair); + l = aopGetLitWordLong (left, offset, FALSE); + base = aopGetLitWordLong (left, 0, FALSE); + wassert (l && pair && base); if (isPtr (pair)) { @@ -947,14 +1372,14 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) { if (_G.pairs[pairId].last_type == left->type) { - if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l)) + if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base)) { if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3) { adjustPair (pair, &_G.pairs[pairId].offset, offset); return; } - if (pairId == PAIR_IY && abs (offset) < 127) + if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX)) { return; } @@ -962,53 +1387,72 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) } } _G.pairs[pairId].last_type = left->type; - _G.pairs[pairId].lit = gc_strdup (l); + _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base)); _G.pairs[pairId].offset = offset; } - if (IS_GB && pairId == PAIR_DE && 0) + /* 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 (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l)) - { - if (abs (_G.pairs[pairId].offset - offset) < 3) - { - adjustPair (pair, &_G.pairs[pairId].offset, offset); - return; - } - } - _G.pairs[pairId].last_type = left->type; - _G.pairs[pairId].lit = gc_strdup (l); - _G.pairs[pairId].offset = offset; + 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; + } } - /* Both a lit on the right and a true symbol on the left */ - if (offset) - emit2 ("ld %s,!hashedstr + %u", pair, l, offset); else - emit2 ("ld %s,!hashedstr", pair, l); + { + *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) { + switch (aop->size - offset) { case 1: emit2 ("ld l,!*hl"); emit2 ("ld h,!immedbyte", 0); break; case 2: + // PENDING: Requires that you are only fetching two bytes. + case 4: emit2 ("!ldahli"); emit2 ("ld h,!*hl"); emit2 ("ld l,a"); break; default: - emit2 ("; WARNING: mlh woosed out. This code is invalid."); + wassertl (0, "Attempted to fetch too much data into HL"); + break; } } else if (IS_Z80 && aop->type == AOP_IY) { @@ -1022,10 +1466,38 @@ 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 if (isUnsplitable(aop)) + { + emit2("push %s", _pairs[getPairId(aop)].name); + emit2("pop %s", _pairs[pairId].name); + } + 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); @@ -1035,7 +1507,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 @@ -1045,23 +1517,83 @@ 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 (_G.preserveCarry) + { + _push (PAIR_AF); + offset += 2; + } + + if (offset < INT8MIN || offset > INT8MAX) + { + emit2 ("ld hl,!immedword", offset); + emit2 ("add hl,sp"); + } + else + { + emit2 ("!ldahlsp", offset); + } + + if (_G.preserveCarry) + { + _pop (PAIR_AF); + offset -= 2; + } +} +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. */ + if (_G.preserveCarry) + _push (PAIR_AF); + 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; + if (_G.preserveCarry) + _pop (PAIR_AF); + } + } + 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; @@ -1074,11 +1606,18 @@ 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: + if (pairId != aop->aopu.aop_pairId) + genMovePairPair(aop->aopu.aop_pairId, pairId); + adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset); + break; + default: wassert (0); } @@ -1098,55 +1637,83 @@ emitLabel (int key) static const char * aopGet (asmop * aop, int offset, bool bit16) { - char *s = buffer; + // char *s = buffer; /* offset is greater than size then zero */ /* PENDING: this seems a bit screwed in some pointer cases. */ if (offset > (aop->size - 1) && aop->type != AOP_LIT) { - tsprintf (s, "!zero"); - return gc_strdup(s); + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } /* depending on type */ switch (aop->type) { + case AOP_DUMMY: + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + case AOP_IMMD: /* PENDING: re-target */ if (bit16) - tsprintf (s, "!immedwords", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd); else switch (offset) { case 2: - tsprintf (s, "!bankimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd); break; case 1: - tsprintf (s, "!msbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd); break; case 0: - tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!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(buffer)); case AOP_DIR: wassert (IS_GB); - emit2 ("ld a,(%s+%d) ; x", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); + SNPRINTF (buffer, sizeof(buffer), "a"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_SFR: - wassert (IS_GB); - emit2 ("ldh a,(%s+%d) ; x", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + if( IS_GB ) + { + // wassert (IS_GB); + emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); + SNPRINTF (buffer, sizeof(buffer), "a"); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + } + else + { /*.p.t.20030716 handling for i/o port read access for Z80 */ + if( aop->paged ) + { /* banked mode */ + /* reg A goes to address bits 15-8 during "in a,(x)" instruction */ + emit2( "ld a,!msbimmeds", aop->aopu.aop_dir); + emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir); + } + else if( z80_opts.port_mode == 180 ) + { /* z180 in0/out0 mode */ + emit2( "in0 a,(%s)", aop->aopu.aop_dir ); + } + else + { /* 8 bit mode */ + emit2( "in a,(%s)", aop->aopu.aop_dir ); + } + + SNPRINTF (buffer, sizeof(buffer), "a"); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + } case AOP_REG: return aop->aopu.aop_reg[offset]->name; @@ -1154,34 +1721,42 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_HL: wassert (IS_GB); setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); - return gc_strdup (s); + return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); case AOP_IY: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); - tsprintf (s, "!*iyx", offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + + case AOP_EXSTK: + wassert (IS_Z80); + setupPair (PAIR_IY, aop, offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset); - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_STK: if (IS_GB) { setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); } else { if (aop->aopu.aop_stk >= 0) offset += _G.stack.param_offset; - tsprintf (s, "!*ixx ; x", aop->aopu.aop_stk + offset); + tsprintf (buffer, sizeof(buffer), + "!*ixx", aop->aopu.aop_stk + offset); } - return gc_strdup(s); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_CRY: - wassert (0); + wassertl (0, "Tried to fetch from a bit variable"); case AOP_ACC: if (!offset) @@ -1190,8 +1765,8 @@ aopGet (asmop * aop, int offset, bool bit16) } else { - tsprintf(s, "!zero"); - return gc_strdup(s); + tsprintf(buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } case AOP_HLREG: @@ -1201,10 +1776,34 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_LIT: return aopLiteral (aop->aopu.aop_lit, offset); + case AOP_SIMPLELIT: + { + unsigned long v = aop->aopu.aop_simplelit; + + v >>= (offset * 8); + tsprintf (buffer, sizeof(buffer), + "!immedbyte", (unsigned int) v & 0xff); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + } case AOP_STR: aop->coff = offset; return aop->aopu.aop_str[offset]; + case AOP_PAIRPTR: + setupPair (aop->aopu.aop_pairId, aop, offset); + if (aop->aopu.aop_pairId==PAIR_IX) + SNPRINTF (buffer, sizeof(buffer), + "!*ixx", 0); + else if (aop->aopu.aop_pairId==PAIR_IY) + SNPRINTF (buffer, sizeof(buffer), + "!*iyx", 0); + else + SNPRINTF (buffer, sizeof(buffer), + "(%s)", _pairs[aop->aopu.aop_pairId].name); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + default: break; } @@ -1259,13 +1858,17 @@ aopPut (asmop * aop, const char *s, int offset) } // PENDING - tsprintf(buffer2, s); + tsprintf(buffer2, sizeof(buffer2), s); s = buffer2; /* will assign value to value */ /* depending on where it is ofcourse */ switch (aop->type) { + case AOP_DUMMY: + _moveA (s); /* in case s is volatile */ + break; + case AOP_DIR: /* Direct. Hmmm. */ wassert (IS_GB); @@ -1275,10 +1878,47 @@ aopPut (asmop * aop, const char *s, int offset) break; case AOP_SFR: - wassert (IS_GB); - if (strcmp (s, "a")) - emit2 ("ld a,%s", s); - emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset); + if( IS_GB ) + { + // wassert (IS_GB); + if (strcmp (s, "a")) + emit2 ("ld a,%s", s); + emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset); + } + else + { /*.p.t.20030716 handling for i/o port read access for Z80 */ + if (aop->paged) + { /* banked mode */ + if (aop->bcInUse) + emit2( "push bc" ); + + if (strlen(s) != 1 + || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e' + && s[0] != 'h' && s[0] != 'l')) + { + emit2( "ld a,%s", s ); + s = "a"; + } + + emit2( "ld bc,#%s", aop->aopu.aop_dir ); + emit2( "out (c),%s", s ); + + if( aop->bcInUse ) + emit2( "pop bc" ); + else + spillPair (PAIR_BC); + } + else if( z80_opts.port_mode == 180 ) + { /* z180 in0/out0 mode */ + emit2( "ld a,%s", s ); + emit2( "out0 (%s),a", aop->aopu.aop_dir ); + } + else + { /* 8 bit mode */ + emit2( "ld a,%s", s ); + emit2( "out (%s),a", aop->aopu.aop_dir ); + } + } break; case AOP_REG: @@ -1287,18 +1927,22 @@ aopPut (asmop * aop, const char *s, int offset) else emit2 ("ld %s,%s", aop->aopu.aop_reg[offset]->name, s); + spillPairReg(aop->aopu.aop_reg[offset]->name); break; 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: @@ -1314,8 +1958,23 @@ aopPut (asmop * aop, const char *s, int offset) emit2 ("ld !*hl,%s", s); break; - case AOP_STK: - if (IS_GB) + 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) { /* PENDING: re-target */ if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]")) @@ -1342,7 +2001,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; @@ -1350,13 +2011,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; @@ -1366,6 +2027,7 @@ aopPut (asmop * aop, const char *s, int offset) { emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); } + spillPairReg(aop->aopu.aop_str[offset]); break; case AOP_ACC: @@ -1374,19 +2036,32 @@ aopPut (asmop * aop, const char *s, int offset) break; if (offset > 0) { - - emit2 ("; Error aopPut AOP_ACC"); + wassertl (0, "Tried to access past the end of A"); } else { if (strcmp (aop->aopu.aop_str[offset], s)) - emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + { + emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); + } } break; case AOP_HLREG: wassert (offset < 2); emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); + break; + + case AOP_PAIRPTR: + setupPair (aop->aopu.aop_pairId, aop, offset); + if (aop->aopu.aop_pairId==PAIR_IX) + emit2 ("ld !*ixx,%s", 0, s); + else if (aop->aopu.aop_pairId==PAIR_IY) + emit2 ("ld !*ixy,%s", 0, s); + else + emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); break; default: @@ -1399,12 +2074,13 @@ aopPut (asmop * aop, const char *s, int offset) #define AOP(op) op->aop #define AOP_TYPE(op) AOP(op)->type #define AOP_SIZE(op) AOP(op)->size -#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY)) +#define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR))) 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"); @@ -1413,8 +2089,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); + } } } @@ -1429,7 +2116,7 @@ getDataSize (operand * op) if (size == 3) { /* pointer */ - wassert (0); + wassertl (0, "Somehow got a three byte data pointer"); } return size; } @@ -1441,7 +2128,8 @@ static void movLeft2Result (operand * left, int offl, operand * result, int offr, int sign) { - const char *l; + const char *l; + if (!sameRegs (AOP (left), AOP (result)) || (offl != offr)) { l = aopGet (AOP (left), offl, FALSE); @@ -1452,11 +2140,57 @@ movLeft2Result (operand * left, int offl, } else { - wassert (0); + if (getDataSize (left) == offl + 1) + { + emit2 ("ld a,%s", l); + aopPut (AOP (result), "a", offr); + } } } } +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"); + spillPair (PAIR_HL); + } + 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 */ @@ -1486,8 +2220,7 @@ outBitCLong (operand * result, bool swap_sense) /* if the result is bit */ if (AOP_TYPE (result) == AOP_CRY) { - emit2 ("; Note: outBitC form 1"); - aopPut (AOP (result), "blah", 0); + wassertl (0, "Tried to write carry to a bit"); } else { @@ -1509,7 +2242,7 @@ outBitC (operand * result) /* toBoolean - emit code for orl a,operator(sizeop) */ /*-----------------------------------------------------------------*/ void -toBoolean (operand * oper) +_toBoolean (operand * oper) { int size = AOP_SIZE (oper); int offset = 0; @@ -1530,13 +2263,13 @@ toBoolean (operand * oper) } } + /*-----------------------------------------------------------------*/ /* genNot - generate code for ! operation */ /*-----------------------------------------------------------------*/ static void genNot (iCode * ic) { - sym_link *optype = operandType (IC_LEFT (ic)); /* assign asmOps to operand & result */ aopOp (IC_LEFT (ic), ic, FALSE, TRUE); @@ -1545,16 +2278,10 @@ genNot (iCode * ic) /* if in bit space then a special case */ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) { - wassert (0); - } - - /* if type float then do float */ - if (IS_FLOAT (optype)) - { - wassert (0); + wassertl (0, "Tried to negate a bit"); } - toBoolean (IC_LEFT (ic)); + _toBoolean (IC_LEFT (ic)); /* Not of A: If A == 0, !A = 1 @@ -1587,7 +2314,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)); @@ -1604,6 +2331,85 @@ genCpl (iCode * ic) freeAsmop (IC_RESULT (ic), NULL, ic); } +static void +_gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd) +{ + /* Logic: + ld de,right.lw + setup hl to left + de = hl - de + push flags + store de into result + pop flags + ld de,right.hw + setup hl + de = hl -de + store de into result + */ + const char *first = isAdd ? "add" : "sub"; + const char *later = isAdd ? "adc" : "sbc"; + + wassertl (IS_GB, "Code is only relevent to the gbz80"); + wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes"); + + fetchPair (PAIR_DE, left); + + emit2 ("ld a,e"); + emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE)); + emit2 ("ld e,a"); + emit2 ("ld a,d"); + emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE)); + + _push (PAIR_AF); + aopPut ( AOP (IC_RESULT (ic)), "a", MSB16); + aopPut ( AOP (IC_RESULT (ic)), "e", LSB); + + fetchPairLong (PAIR_DE, left, NULL, MSB24); + aopGet (right, MSB24, FALSE); + + _pop (PAIR_AF); + emit2 ("ld a,e"); + emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE)); + emit2 ("ld e,a"); + emit2 ("ld a,d"); + emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE)); + + aopPut ( AOP (IC_RESULT (ic)), "a", MSB32); + aopPut ( AOP (IC_RESULT (ic)), "e", MSB24); +} + +static void +_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 bit 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 */ /*-----------------------------------------------------------------*/ @@ -1622,7 +2428,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; } @@ -1632,12 +2438,23 @@ genUminus (iCode * ic) /* if float then do float stuff */ if (IS_FLOAT (optype)) { - wassert (0); + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); goto release; } /* otherwise subtract from zero */ size = AOP_SIZE (IC_LEFT (ic)); + + if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB) + { + /* Create a new asmop with value zero */ + asmop *azero = newAsmop (AOP_SIMPLELIT); + azero->aopu.aop_simplelit = 0; + azero->size = size; + _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE); + goto release; + } + offset = 0; _clearCarry(); while (size--) @@ -1664,21 +2481,6 @@ release: freeAsmop (IC_RESULT (ic), NULL, ic); } -static void -_push (PAIR_ID pairId) -{ - emit2 ("push %s", _pairs[pairId].name); - _G.stack.pushed += 2; -} - -static void -_pop (PAIR_ID pairId) -{ - emit2 ("pop %s", _pairs[pairId].name); - _G.stack.pushed -= 2; -} - - /*-----------------------------------------------------------------*/ /* assignResultValue - */ /*-----------------------------------------------------------------*/ @@ -1688,21 +2490,16 @@ 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 0 - if (!IS_GB) - wassert (size <= 2); -#endif if (IS_GB && size == 4 && requiresHL (AOP (oper))) { /* We do it the hard way here. */ _push (PAIR_HL); aopPut (AOP (oper), _fReturn[0], 0); aopPut (AOP (oper), _fReturn[1], 1); - emit2 ("pop de"); - _G.stack.pushed -= 2; + _pop (PAIR_DE); aopPut (AOP (oper), _fReturn[0], 2); aopPut (AOP (oper), _fReturn[1], 3); } @@ -1715,6 +2512,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) { @@ -1745,26 +2561,15 @@ _saveRegsForCall(iCode *ic, int sendSetSize) bool bcInRet = FALSE, deInRet = FALSE; bitVect *rInUse; -#if 1 - rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); -#else - if (IC_RESULT(ic)) - { - rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic))); - } - else - { - /* Has no result, so in use is all of in use */ - rInUse = ic->rMask; - } -#endif + rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), + z80_rUmaskForOp (IC_RESULT(ic))); deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX); bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX); deSending = (sendSetSize > 1); - emit2 ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); + emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); if (bcInUse && bcInRet == FALSE) { _push(PAIR_BC); @@ -1796,42 +2601,6 @@ genIpush (iCode * ic) if (!ic->parmPush) { wassertl(0, "Encountered an unsupported spill push."); -#if 0 - /* and the item is spilt then do nothing */ - if (OP_SYMBOL (IC_LEFT (ic))->isspilt) - return; - - aopOp (IC_LEFT (ic), ic, FALSE, FALSE); - size = AOP_SIZE (IC_LEFT (ic)); - /* push it on the stack */ - if (isPair (AOP (IC_LEFT (ic)))) - { - emit2 ("push %s", getPairName (AOP (IC_LEFT (ic)))); - _G.stack.pushed += 2; - } - else - { - offset = size; - while (size--) - { - /* Simple for now - load into A and PUSH AF */ - if (AOP (IC_LEFT (ic))->type == AOP_IY) - { - char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE); - wassert (l); - emit2 ("ld a,(%s)", l); - } - else - { - l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE); - emit2 ("ld a,%s", l); - } - emit2 ("push af"); - emit2 ("inc sp"); - _G.stack.pushed++; - } - } -#endif return; } @@ -1868,7 +2637,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)))); @@ -1885,11 +2654,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; @@ -1998,7 +2767,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) { if (pairId == PAIR_DE) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "e")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "d")) @@ -2006,7 +2775,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) } else if (pairId == PAIR_BC) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "c")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "b")) @@ -2028,9 +2797,8 @@ _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); + bool bInRet, cInRet, dInRet, eInRet; + sym_link *dtype = operandType (IC_LEFT (ic)); /* if caller saves & we have not saved then */ if (!ic->regsSaved) @@ -2102,7 +2870,7 @@ emitCall (iCode * ic, bool ispcall) if (ispcall) { - if (IS_BANKEDCALL (detype)) + if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype))) { werror (W_INDIR_BANKED); } @@ -2110,7 +2878,6 @@ emitCall (iCode * ic, bool ispcall) if (isLitWord (AOP (IC_LEFT (ic)))) { - emit2 ("; Special case where the pCall is to a constant"); emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE)); } else @@ -2133,7 +2900,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); @@ -2147,7 +2914,7 @@ emitCall (iCode * ic, bool ispcall) } spillCached (); - /* Mark the regsiters as restored. */ + /* Mark the registers as restored. */ _G.saves.saved = FALSE; /* if we need assign a result value */ @@ -2177,76 +2944,92 @@ 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 (); } } - if (_G.stack.pushedDE) + spillCached (); + if (IC_RESULT (ic)) + { + bitVect *result = z80_rUmaskForOp (IC_RESULT (ic)); + bInRet = bitVectBitValue(result, B_IDX); + cInRet = bitVectBitValue(result, C_IDX); + dInRet = bitVectBitValue(result, D_IDX); + eInRet = bitVectBitValue(result, E_IDX); + } + else { - bool dInUse = bitVectBitValue(rInUse, D_IDX); - bool eInUse = bitVectBitValue(rInUse, E_IDX); + bInRet = FALSE; + cInRet = FALSE; + dInRet = FALSE; + eInRet = FALSE; + } - if (dInUse && eInUse) + if (_G.stack.pushedDE) + { + 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); - - // 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; } @@ -2291,72 +3074,74 @@ resultRemat (iCode * ic) extern set *publics; -/* Steps: - o Check genFunction - o Check emitCall and clean up - o Check genReturn - o Check return puller - - PENDING: Remove this. -*/ - /*-----------------------------------------------------------------*/ /* genFunction - generated code for function entry */ /*-----------------------------------------------------------------*/ static void genFunction (iCode * ic) { + bool stackParm; + 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. */ _G.receiveOffset = 0; -#if 0 - /* PENDING: hack */ - if (!IS_STATIC (sym->etype)) - { - addSetIfnotP (&publics, sym); - } -#endif - /* Record the last function name for debugging. */ _G.lastFunctionName = sym->rname; /* Create the function header */ emit2 ("!functionheader", sym->name); - /* PENDING: portability. */ - emit2 ("__%s_start:", sym->rname); + if (!IS_STATIC(sym->etype)) + { + sprintf (buffer, "%s_start", sym->rname); + emit2 ("!labeldef", buffer); + } emit2 ("!functionlabeldef", sym->rname); - fetype = getSpec (operandType (IC_LEFT (ic))); + if (options.profile) + { + emit2 ("!profileenter"); + } - /* if critical function then turn interrupts off */ - if (SPEC_CRTCL (fetype)) - emit2 ("!di"); + ftype = operandType (IC_LEFT (ic)); /* if this is an interrupt service routine then save all potentially used registers. */ - if (IS_ISR (sym->etype)) + if (IFFUNC_ISISR (sym->type)) + { + if (!FUNC_ISNAKED( sym->type )) + { + emit2 ("!pusha"); + } + } + else { - emit2 ("!pusha"); + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (sym->type)) + { + emit2 ("!di"); + } } /* PENDING: callee-save etc */ _G.stack.param_offset = 0; -#if CALLEE_SAVES + if (z80_opts.calleeSavesBC) + { + bcInUse = TRUE; + } + /* Detect which registers are used. */ - if (sym->regsUsed) + if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed) { int i; for (i = 0; i < sym->regsUsed->size; i++) @@ -2389,7 +3174,7 @@ genFunction (iCode * ic) _G.stack.param_offset += 2; } - _G.stack.pushedBC = bcInUse; + _G.calleeSaves.pushedBC = bcInUse; if (deInUse) { @@ -2397,16 +3182,39 @@ genFunction (iCode * ic) _G.stack.param_offset += 2; } - _G.stack.pushedDE = deInUse; -#endif + _G.calleeSaves.pushedDE = deInUse; /* adjust the stack for the function */ _G.stack.last = sym->stack; - - if (sym->stack) + + stackParm = FALSE; + for (sym = setFirstItem (istack->syms); sym; + sym = setNextItem (istack->syms)) + { + if (sym->_isparm && !IS_REGPARM (sym->etype)) + { + stackParm = TRUE; + break; + } + } + sym = OP_SYMBOL (IC_LEFT (ic)); + + _G.omitFramePtr = options.ommitFramePtr; + if (IS_Z80 && !stackParm && !sym->stack) + { + /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */ + /* the above !sym->stack condition can be removed. -- EEP */ + if (sym->stack) + emit2 ("!ldaspsp", -sym->stack); + _G.omitFramePtr = TRUE; + } + else if (sym->stack && IS_GB && sym->stack > -INT8MIN) + emit2 ("!enterxl", sym->stack); + else if (sym->stack) emit2 ("!enterx", sym->stack); - else + else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */ emit2 ("!enter"); + _G.stack.offset = sym->stack; } @@ -2418,47 +3226,84 @@ genEndFunction (iCode * ic) { symbol *sym = OP_SYMBOL (IC_LEFT (ic)); - if (IS_ISR (sym->etype)) + + /* PENDING: calleeSave */ + if (IS_Z80 && _G.omitFramePtr) { - wassert (0); + if (_G.stack.offset) + emit2 ("!ldaspsp", _G.stack.offset); } - else + else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX) { - if (SPEC_CRTCL (sym->etype)) - emit2 ("!ei"); - - /* PENDING: calleeSave */ + emit2 ("!leavexl", _G.stack.offset); + } + else if (_G.stack.offset) + { + emit2 ("!leavex", _G.stack.offset); + } + else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */ + { + emit2 ("!leave"); + } + + if (_G.calleeSaves.pushedDE) + { + emit2 ("pop de"); + _G.calleeSaves.pushedDE = FALSE; + } - if (_G.stack.offset) - { - emit2 ("!leavex", _G.stack.offset); - } - else - { - emit2 ("!leave"); - } + if (_G.calleeSaves.pushedBC) + { + emit2 ("pop bc"); + _G.calleeSaves.pushedBC = FALSE; + } -#if CALLEE_SAVES - if (_G.stack.pushedDE) - { - emit2 ("pop de"); - _G.stack.pushedDE = FALSE; - } + if (options.profile) + { + emit2 ("!profileexit"); + } - if (_G.stack.pushedDE) + /* if this is an interrupt service routine then restore all potentially used registers. */ + if (IFFUNC_ISISR (sym->type)) + { + if (!FUNC_ISNAKED( sym->type )) { - emit2 ("pop bc"); - _G.stack.pushedDE = FALSE; + emit2 ("!popa"); } -#endif + } + else + { + /* if critical function then turn interrupts back on */ + if (IFFUNC_ISCRITICAL (sym->type)) + emit2 ("!ei"); + } - /* Both baned and non-banked just ret */ + if (options.debug && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + if (IFFUNC_ISISR (sym->type)) + { + /* "critical interrupt" is used to imply NMI handler */ + if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type)) + emit2 ("retn"); + else + emit2 ("reti"); + } + else + { + /* Both banked and non-banked just ret */ emit2 ("ret"); - - /* PENDING: portability. */ - emit2 ("__%s_end:", sym->rname); } - _G.flushStatics = 1; + + if (!IS_STATIC(sym->etype)) + { + sprintf (buffer, "%s_end", sym->rname); + emit2 ("!labeldef", buffer); + } + + _G.flushStatics = 1; _G.stack.pushed = 0; _G.stack.offset = 0; } @@ -2484,6 +3329,9 @@ genRet (iCode * ic) aopOp (IC_LEFT (ic), ic, FALSE, FALSE); size = AOP_SIZE (IC_LEFT (ic)); + aopDump("IC_LEFT", AOP(IC_LEFT(ic))); + + #if 0 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0)))) { if (IS_GB) @@ -2495,12 +3343,17 @@ genRet (iCode * ic) emit2 ("ld hl,%s", l); } } + #endif + if (size==2) + { + fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic))); + } else { 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 { @@ -2509,7 +3362,8 @@ genRet (iCode * ic) l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); if (strcmp (_fReturn[offset], l)) - emit2 ("ld %s,%s", _fReturn[offset++], l); + emit2 ("ld %s,%s", _fReturn[offset], l); + offset++; } } } @@ -2562,7 +3416,7 @@ genPlusIncr (iCode * ic) if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) return FALSE; - emit2 ("; genPlusIncr"); + emitDebug ("; genPlusIncr"); icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); @@ -2571,14 +3425,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; @@ -2587,8 +3454,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--) { @@ -2597,6 +3463,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) @@ -2628,13 +3501,27 @@ 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 */ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) { while (icount--) - emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + { + emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + } return TRUE; } @@ -2651,7 +3538,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 { @@ -2662,6 +3549,91 @@ 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); + /* check result again, in case right == result */ + if (couldDestroyCarry (result)) + shiftIntoPair (1, result); + } + else if (couldDestroyCarry (right)) + { + if (getPairId (result) == PAIR_HL) + _G.preserveCarry = TRUE; + else + shiftIntoPair (0, right); + } + else if (couldDestroyCarry (result)) + { + shiftIntoPair (0, result); + } + else + { + /* Fine */ + } + } +} + /*-----------------------------------------------------------------*/ /* genPlus - generates code for addition */ /*-----------------------------------------------------------------*/ @@ -2683,7 +3655,7 @@ genPlus (iCode * ic) in ACC */ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) || - (AOP_NEEDSACC (IC_LEFT (ic))) || + (AOP_NEEDSACC (IC_RIGHT (ic))) || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC) { operand *t = IC_RIGHT (ic); @@ -2697,7 +3669,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 */ @@ -2705,7 +3677,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 @@ -2713,7 +3685,7 @@ genPlus (iCode * ic) if (genPlusIncr (ic) == TRUE) goto release; - emit2 ("; genPlusIncr failed"); + emitDebug ("; Can't optimise plus by inc, falling back to the normal way"); size = getDataSize (IC_RESULT (ic)); @@ -2721,10 +3693,11 @@ genPlus (iCode * ic) if (isPair (AOP (IC_RESULT (ic)))) { char *left, *right; - left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE); right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE); - if (left && right) + + if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT && + left && right) { /* It's a pair */ /* PENDING: fix */ @@ -2735,12 +3708,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; } @@ -2804,12 +3813,18 @@ genPlus (iCode * ic) commitPair (AOP (IC_RESULT (ic)), PAIR_HL); goto release; } - else if (size == 4) - { - emit2 ("; WARNING: This add is probably broken.\n"); - } } + if (size == 4) + { + /* Be paranoid on the GB with 4 byte variables due to how C + can be trashed by lda hl,n(sp). + */ + _gbz80_emitAddSubLong (ic, TRUE); + goto release; + } } + + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); while (size--) { @@ -2837,6 +3852,7 @@ genPlus (iCode * ic) } release: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -2864,26 +3880,6 @@ genMinusDec (iCode * ic) size = getDataSize (IC_RESULT (ic)); -#if 0 - /* if increment 16 bits in register */ - if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && - (size > 1) && - (icount == 1)) - { - symbol *tlbl = newiTempLabel (NULL); - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE)); - emit2 ("jp np," LABEL_STR, tlbl->key + 100); - - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE)); - if (size == 4) - { - wassert (0); - } - emitLabel (tlbl->key + 100); - return TRUE; - } -#endif - /* if decrement 16 bits in register */ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && isPair (AOP (IC_RESULT (ic)))) @@ -2896,13 +3892,29 @@ 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; } + /* if increment 16 bits in register */ + if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && + (size == 2) + ) + { + fetchPair (_getTempPairId(), AOP (IC_RESULT (ic))); + + while (icount--) { + emit2 ("dec %s", _getTempPairName()); + } + + commitPair (AOP (IC_RESULT (ic)), _getTempPairId()); + + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ if (AOP_SIZE (IC_RESULT (ic)) > 1 || AOP_SIZE (IC_LEFT (ic)) > 1) @@ -2938,7 +3950,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; } @@ -2992,17 +4004,26 @@ 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; } - else if (size == 4) - { - emit2 ("; WARNING: This sub is probably broken.\n"); - } } + if (size == 4) + { + /* Be paranoid on the GB with 4 byte variables due to how C + can be trashed by lda hl,n(sp). + */ + _gbz80_emitAddSubLong (ic, FALSE); + goto release; + } } + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); + /* if literal, add a,#-lit, else normal subb */ while (size--) { @@ -3030,9 +4051,12 @@ 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: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -3044,8 +4068,104 @@ release: static void genMult (iCode * ic) { + int val; + int count, i; + /* If true then the final operation should be a subtract */ + bool active = FALSE; + bool byteResult; + /* 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); + + byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1); + + 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)); + if (!byteResult) + { + 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"); + if (!byteResult) + 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; + } + + if (byteResult) + aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0); + else + commitPair ( AOP (IC_RESULT (ic)), PAIR_HL); + + freeAsmop (IC_LEFT (ic), NULL, ic); + freeAsmop (IC_RIGHT (ic), NULL, ic); + freeAsmop (IC_RESULT (ic), NULL, ic); } /*-----------------------------------------------------------------*/ @@ -3055,7 +4175,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"); } /*-----------------------------------------------------------------*/ @@ -3094,6 +4214,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 */ @@ -3116,6 +4244,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 */ @@ -3133,6 +4269,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); @@ -3143,36 +4285,15 @@ genIfxJump (iCode * ic, char *jval) ic->generated = 1; } +#if DISABLED static const char * _getPairIdName (PAIR_ID id) { return _pairs[id].name; } +#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)) @@ -3186,52 +4307,91 @@ genCmp (operand * left, operand * right, else emit2 ("cp %s", aopGet (AOP (right), offset, FALSE)); } + else if (size == 4 && 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--) + { + if (size == 0 && sign) + { + // Highest byte when signed needs the bits flipped + // Save the flags + emit2 ("push af"); + emit2 ("ld a,(de)"); + emit2 ("xor !immedbyte", 0x80); + emit2 ("ld e,a"); + emit2 ("ld a,(hl)"); + emit2 ("xor !immedbyte", 0x80); + emit2 ("ld d,a"); + emit2 ("pop af"); + emit2 ("ld a,e"); + emit2 ("%s a,d", offset == 0 ? "sub" : "sbc"); + } + else + { + 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); + } + 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 { - /* Special cases: - On the GB: - If the left or the right is a lit: - Load -lit into HL, add to right via, check sense. - */ - if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT)) + if (AOP_TYPE (right) == AOP_LIT) { - PAIR_ID id = PAIR_DE; - asmop *lit = AOP (right); - asmop *op = AOP (left); - swap_sense = TRUE; - - if (AOP_TYPE (left) == AOP_LIT) - { - swap_sense = FALSE; - lit = AOP (left); - op = AOP (right); - } - if (sign) - { - emit2 ("ld e,%s", aopGet (op, 0, 0)); - emit2 ("ld a,%s", aopGet (op, 1, 0)); - emit2 ("xor a,!immedbyte", 0x80); - emit2 ("ld d,a"); - } - else - { - id = getPairId (op); - if (id == PAIR_INVALID) - { - fetchPair (PAIR_DE, op); - id = PAIR_DE; - } - } - spillPair (PAIR_HL); - emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign)); - emit2 ("add hl,%s", _getPairIdName (id)); - 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 == 0L) + lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + /* optimize if(x < 0) or if(x >= 0) */ + if (lit == 0L) { if (!sign) { @@ -3253,6 +4413,7 @@ genCmp (operand * left, operand * right, goto release; } } + if (sign) { /* First setup h and l contaning the top most bytes XORed */ @@ -3285,12 +4446,6 @@ genCmp (operand * left, operand * right, emit2 ("ld %s,a", _fTmp[1]); fDidXor = TRUE; } - if (!fDidXor) - _clearCarry(); - } - else - { - _clearCarry(); } while (size--) { @@ -3302,20 +4457,120 @@ genCmp (operand * left, operand * right, if (sign && size == 0) { emit2 ("ld a,%s", _fTmp[0]); - emit2 ("sbc a,%s", _fTmp[1]); + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]); } else { /* Subtract through, propagating the carry */ - emit2 ("sbc a,%s ; 2", 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 @@ -3324,9 +4579,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 */ } } @@ -3409,7 +4688,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 && @@ -3420,11 +4701,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 @@ -3437,7 +4716,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { while (size--) { - emit2 ("ld a,%s ; 2", aopGet (AOP (left), offset, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE)); if ((AOP_TYPE (right) == AOP_LIT) && lit == 0) emit2 ("or a,a"); else @@ -3462,7 +4741,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) emit2 ("jp nz,!tlabel", lbl->key + 100); else { - emit2 ("cp %s ; 4", aopGet (AOP (right), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (right), offset, FALSE)); emit2 ("jp nz,!tlabel", lbl->key + 100); } offset++; @@ -3475,7 +4754,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) while (size--) { _moveA (aopGet (AOP (right), offset, FALSE)); - emit2 ("cp %s ; 5", aopGet (AOP (left), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (left), offset, FALSE)); emit2 ("!shortjp nz,!tlabel", lbl->key + 100); offset++; } @@ -3512,7 +4791,7 @@ genCmpEq (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); - emit2("; 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. @@ -3531,7 +4810,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 { @@ -3561,10 +4840,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)) { @@ -3572,6 +4853,7 @@ genCmpEq (iCode * ic, iCode * ifx) } if (ifx) { + emitDebug(";5"); genIfxJump (ifx, "a"); goto release; } @@ -3579,6 +4861,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 */ @@ -3632,14 +4915,14 @@ genAndOp (iCode * ic) if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to and two bits"); } else { tlbl = newiTempLabel (NULL); - toBoolean (left); + _toBoolean (left); emit2 ("!shortjp z,!tlabel", tlbl->key + 100); - toBoolean (right); + _toBoolean (right); emitLabel (tlbl->key + 100); outBitAcc (result); } @@ -3669,14 +4952,14 @@ genOrOp (iCode * ic) if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to OR two bits"); } else { tlbl = newiTempLabel (NULL); - toBoolean (left); + _toBoolean (left); emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - toBoolean (right); + _toBoolean (right); emitLabel (tlbl->key + 100); outBitAcc (result); } @@ -3746,18 +5029,9 @@ genAnd (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); -#ifdef DEBUG_TYPE - emit2 ("; Type res[%d] = l[%d]&r[%d]", - AOP_TYPE (result), - AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", - AOP_SIZE (result), - AOP_SIZE (left), AOP_SIZE (right)); -#endif - /* if left is a literal & right is not then exchange them */ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || - AOP_NEEDSACC (left)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -3787,7 +5061,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; } @@ -3797,80 +5071,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; } @@ -3902,7 +5142,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 { @@ -3919,7 +5159,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 { @@ -3973,23 +5213,15 @@ 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); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); -#if 1 - emit2 ("; Type res[%d] = l[%d]&r[%d]", - AOP_TYPE (result), - AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", - AOP_SIZE (result), - AOP_SIZE (left), AOP_SIZE (right)); -#endif - /* if left is a literal & right is not then exchange them */ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || - AOP_NEEDSACC (left)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -4019,15 +5251,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; } @@ -4067,7 +5323,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++) @@ -4123,7 +5379,7 @@ genXor (iCode * ic, iCode * ifx) /* if left is a literal & right is not then exchange them */ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || - AOP_NEEDSACC (left)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -4153,15 +5409,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; } @@ -4176,9 +5456,9 @@ genXor (iCode * ic, iCode * ifx) continue; else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); + aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); } } @@ -4190,10 +5470,10 @@ genXor (iCode * ic, iCode * ifx) } else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); + aopGet (AOP (right), offset, FALSE)); + aopPut (AOP (result), "a", offset); } } } @@ -4203,7 +5483,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++) @@ -4228,9 +5508,9 @@ genXor (iCode * ic, iCode * ifx) } else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); + aopGet (AOP (right), offset, FALSE)); } aopPut (AOP (result), "a", offset); } @@ -4302,53 +5582,97 @@ genRLC (iCode * ic) wassert (0); } +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void +genGetHbit (iCode * ic) +{ + operand *left, *result; + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, FALSE); + + /* get the highest order byte into a */ + emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); + + if (AOP_TYPE (result) == AOP_CRY) + { + emit2 ("rl a"); + outBitC (result); + } + else + { + emit2 ("rlc a"); + emit2 ("and a,!one"); + outAcc (result); + } + + + freeAsmop (left, NULL, ic); + freeAsmop (result, NULL, ic); +} + +static void +emitRsh2 (asmop *aop, int size, int is_signed) +{ + int offset = 0; + + while (size--) + { + const char *l = aopGet (aop, size, FALSE); + if (offset == 0) + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } + else + { + emit2 ("rr %s", l); + } + offset++; + } +} + /*-----------------------------------------------------------------*/ /* shiftR2Left2Result - shift right two bytes from left to result */ /*-----------------------------------------------------------------*/ static void shiftR2Left2Result (operand * left, int offl, operand * result, int offr, - int shCount, int sign) + int shCount, int is_signed) { + int size = 2; + symbol *tlbl, *tlbl1; + movLeft2Result (left, offl, result, offr, 0); movLeft2Result (left, offl + 1, result, offr + 1, 0); - if (sign) + /* if (AOP(result)->type == AOP_REG) { */ + + tlbl = newiTempLabel (NULL); + tlbl1 = newiTempLabel (NULL); + + /* Left is already in result - so now do the shift */ + if (shCount <= 4) { - wassert (0); + while (shCount--) + { + emitRsh2 (AOP (result), size, is_signed); + } } else { - /* if (AOP(result)->type == AOP_REG) { */ - int size = 2; - int offset = 0; - symbol *tlbl, *tlbl1; - const char *l; - - tlbl = newiTempLabel (NULL); - tlbl1 = newiTempLabel (NULL); + emit2 ("ld a,!immedbyte+1", shCount); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); + emitLabel (tlbl->key + 100); - /* Left is already in result - so now do the shift */ - if (shCount > 1) - { - emit2 ("ld a,!immedbyte+1", shCount); - emit2 ("!shortjp !tlabel", tlbl1->key + 100); - emitLabel (tlbl->key + 100); - } + emitRsh2 (AOP (result), size, is_signed); - emit2 ("or a,a"); - offset = size; - while (size--) - { - l = aopGet (AOP (result), --offset, FALSE); - emit2 ("rr %s", l); - } - if (shCount > 1) - { - emitLabel (tlbl1->key + 100); - emit2 ("dec a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - } + emitLabel (tlbl1->key + 100); + emit2 ("dec a"); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); } } @@ -4370,9 +5694,16 @@ 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 (getPairId (AOP (result)) == PAIR_HL) + { + while (shCount--) + { + emit2 ("add hl,hl"); + } + } + else + { int size = 2; int offset = 0; symbol *tlbl, *tlbl1; @@ -4381,25 +5712,56 @@ shiftL2Left2Result (operand * left, int offl, tlbl = newiTempLabel (NULL); tlbl1 = newiTempLabel (NULL); - /* Left is already in result - so now do the shift */ - if (shCount > 1) - { - emit2 ("ld a,!immedbyte+1", shCount); - emit2 ("!shortjp !tlabel", tlbl1->key + 100); - emitLabel (tlbl->key + 100); - } - - emit2 ("or a,a"); - while (size--) + if (AOP (result)->type == AOP_REG) { - l = aopGet (AOP (result), offset++, FALSE); - emit2 ("rl %s", l); + while (shCount--) + { + for (offset = 0; offset < size; offset++) + { + l = aopGet (AOP (result), offset, FALSE); + + if (offset == 0) + { + emit2 ("sla %s", l); + } + else + { + emit2 ("rl %s", l); + } + } + } } - if (shCount > 1) + else { - emitLabel (tlbl1->key + 100); - emit2 ("dec a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); + /* Left is already in result - so now do the shift */ + if (shCount > 1) + { + emit2 ("ld a,!immedbyte+1", shCount); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); + emitLabel (tlbl->key + 100); + } + + while (size--) + { + l = aopGet (AOP (result), offset, FALSE); + + if (offset == 0) + { + emit2 ("sla %s", l); + } + else + { + emit2 ("rl %s", l); + } + + offset++; + } + if (shCount > 1) + { + emitLabel (tlbl1->key + 100); + emit2 ("dec a"); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); + } } } } @@ -4412,41 +5774,79 @@ AccRol (int shCount) { shCount &= 0x0007; // shCount : 0..7 +#if 0 switch (shCount) { case 0: break; case 1: - emit2 ("rl a"); + emit2 ("sla a"); break; case 2: - emit2 ("rl a"); + emit2 ("sla a"); emit2 ("rl a"); break; case 3: - emit2 ("rl a"); + emit2 ("sla a"); emit2 ("rl a"); emit2 ("rl a"); break; case 4: - emit2 ("rl a"); + emit2 ("sla a"); emit2 ("rl a"); emit2 ("rl a"); emit2 ("rl a"); break; case 5: - emit2 ("rr a"); + emit2 ("srl a"); emit2 ("rr a"); emit2 ("rr a"); break; case 6: - emit2 ("rr a"); + emit2 ("srl a"); emit2 ("rr a"); break; case 7: - emit2 ("rr a"); + emit2 ("srl a"); + break; + } +#else + switch (shCount) + { + case 0: + break; + case 1: + emit2 ("rlca"); + break; + case 2: + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 3: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 4: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 5: + emit2 ("rrca"); + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 6: + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 7: + emit2 ("rrca"); break; } +#endif } /*-----------------------------------------------------------------*/ @@ -4517,7 +5917,7 @@ genlshTwo (operand * result, operand * left, int shCount) { movLeft2Result (left, LSB, result, MSB16, 0); aopPut (AOP (result), "!zero", 0); - shiftL1Left2Result (left, MSB16, result, MSB16, shCount); + shiftL1Left2Result (left, LSB, result, MSB16, shCount); } else { @@ -4572,11 +5972,6 @@ genLeftShiftLiteral (operand * left, size = getSize (operandType (result)); -#if VIEW_SIZE - emit2 ("; shift left result %d, left %d", size, - AOP_SIZE (left)); -#endif - /* I suppose that the left size >= result size */ if (shCount == 0) { @@ -4646,9 +6041,12 @@ genLeftShift (iCode * ic) aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _push (PAIR_AF); + /* now move the left to the result if they are not the same */ -#if 1 + if (!sameRegs (AOP (left), AOP (result))) { @@ -4661,31 +6059,32 @@ genLeftShift (iCode * ic) offset++; } } -#else - size = AOP_SIZE (result); - offset = 0; - while (size--) - { - l = aopGet (AOP (left), offset, FALSE); - aopPut (AOP (result), l, offset); - offset++; - } -#endif - tlbl = newiTempLabel (NULL); size = AOP_SIZE (result); offset = 0; tlbl1 = newiTempLabel (NULL); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _pop (PAIR_AF); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); l = aopGet (AOP (result), offset, FALSE); - emit2 ("or a,a"); + while (size--) { - l = aopGet (AOP (result), offset++, FALSE); - emit2 ("rl %s", l); + l = aopGet (AOP (result), offset, FALSE); + + if (offset == 0) + { + emit2 ("sla %s", l); + } + else + { + emit2 ("rl %s", l); + } + offset++; } emitLabel (tlbl1->key + 100); emit2 ("dec a"); @@ -4699,7 +6098,7 @@ genLeftShift (iCode * ic) /* genrshOne - left shift two bytes by known amount != 0 */ /*-----------------------------------------------------------------*/ static void -genrshOne (operand * result, operand * left, int shCount) +genrshOne (operand * result, operand * left, int shCount, int is_signed) { /* Errk */ int size = AOP_SIZE (result); @@ -4709,19 +6108,22 @@ genrshOne (operand * result, operand * left, int shCount) wassert (shCount < 8); l = aopGet (AOP (left), 0, FALSE); + if (AOP (result)->type == AOP_REG) { aopPut (AOP (result), l, 0); l = aopGet (AOP (result), 0, FALSE); while (shCount--) - emit2 ("srl %s", l); + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } } else { _moveA (l); while (shCount--) { - emit2 ("srl a"); + emit2 ("%s a", is_signed ? "sra" : "srl"); } aopPut (AOP (result), "a", 0); } @@ -4758,7 +6160,10 @@ shiftR1Left2Result (operand * left, int offl, _moveA (aopGet (AOP (left), offl, FALSE)); if (sign) { - wassert (0); + while (shCount--) + { + emit2 ("%s a", sign ? "sra" : "srl"); + } } else { @@ -4787,7 +6192,19 @@ genrshTwo (operand * result, operand * left, { movLeft2Result (left, MSB16, result, LSB, sign); } - aopPut (AOP (result), "!zero", 1); + if (sign) + { + /* Sign extend the result */ + _moveA(aopGet (AOP (result), 0, FALSE)); + emit2 ("rlc a"); + emit2 ("sbc a,a"); + + aopPut (AOP (result), ACC_NAME, MSB16); + } + else + { + aopPut (AOP (result), "!zero", 1); + } } /* 1 <= shCount <= 7 */ else @@ -4803,7 +6220,8 @@ static void genRightShiftLiteral (operand * left, operand * right, operand * result, - iCode * ic) + iCode * ic, + int sign) { int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit); int size; @@ -4815,34 +6233,40 @@ genRightShiftLiteral (operand * left, size = getSize (operandType (result)); - emit2 ("; shift right result %d, left %d", size, - AOP_SIZE (left)); - /* I suppose that the left size >= result size */ if (shCount == 0) { wassert (0); } - else if (shCount >= (size * 8)) + else if (shCount >= (size * 8)) { + const char *s; + if (!SPEC_USIGN(getSpec(operandType(left)))) { + _moveA(aopGet (AOP (left), 0, FALSE)); + emit2 ("rlc a"); + emit2 ("sbc a,a"); + s=ACC_NAME; + } else { + s="!zero"; + } while (size--) - aopPut (AOP (result), "!zero", size); + aopPut (AOP (result), s, size); + } else { switch (size) { case 1: - genrshOne (result, left, shCount); + genrshOne (result, left, shCount, sign); break; case 2: - /* PENDING: sign support */ - genrshTwo (result, left, shCount, FALSE); + genrshTwo (result, left, shCount, sign); break; case 4: - wassert (0); + wassertl (0, "Asked to shift right a long which should be a function call"); break; default: - wassert (0); + wassertl (0, "Entered default case in right shift delegate"); } } freeAsmop (left, NULL, ic); @@ -4886,17 +6310,23 @@ genRightShift (iCode * ic) as efficiently as possible */ if (AOP_TYPE (right) == AOP_LIT) { - genRightShiftLiteral (left, right, result, ic); + genRightShiftLiteral (left, right, result, ic, is_signed); return; } + emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); + emit2 ("inc a"); + freeAsmop (right, NULL, ic); + aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _push (PAIR_AF); + /* now move the left to the result if they are not the same */ - if (!sameRegs (AOP (left), AOP (result)) && - AOP_SIZE (result) > 1) + if (!sameRegs (AOP (left), AOP (result))) { size = AOP_SIZE (result); @@ -4909,14 +6339,13 @@ genRightShift (iCode * ic) } } - emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); - emit2 ("inc a"); - freeAsmop (right, NULL, ic); - tlbl = newiTempLabel (NULL); tlbl1 = newiTempLabel (NULL); size = AOP_SIZE (result); offset = size - 1; + + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _pop (PAIR_AF); emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); @@ -4925,14 +6354,13 @@ genRightShift (iCode * ic) l = aopGet (AOP (result), offset--, FALSE); if (first) { - if (is_signed) - emit2 ("sra %s", l); - else - emit2 ("srl %s", l); + emit2 ("%s %s", is_signed ? "sra" : "srl", l); first = 0; } else - emit2 ("rr %s", l); + { + emit2 ("rr %s", l); + } } emitLabel (tlbl1->key + 100); emit2 ("dec a"); @@ -4942,6 +6370,82 @@ genRightShift (iCode * ic) freeAsmop (result, NULL, ic); } + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, int pair) +{ + int offset = 0; /* result byte offset */ + int rsize; /* result size */ + int rlen = 0; /* remaining bitfield length */ + sym_link *etype; /* bitfield type information */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + + emitDebug ("; genUnpackBits"); + + etype = getSpec (operandType (result)); + rsize = getSize (operandType (result)); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + AccRsh (bstr); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen)); + aopPut (AOP (result), "a", offset++); + goto finish; + } + + /* TODO: what if pair == PAIR_DE ? */ + if (getPairId (AOP (result)) == PAIR_HL) + { + wassertl (rsize == 2, "HL must be of size 2"); + emit2 ("ld a,!*hl"); + emit2 ("inc hl"); + emit2 ("ld h,!*hl"); + emit2 ("ld l,a"); + emit2 ("ld a,h"); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen)); + emit2 ("ld h,a"); + spillPair (PAIR_HL); + return; + } + + /* Bit field did not fit in a byte. Copy all + but the partial byte at the end. */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + aopPut (AOP (result), "a", offset++); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* Handle the partial byte at the end */ + if (rlen) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen)); + aopPut (AOP (result), "a", offset++); + } + +finish: + if (offset < rsize) + { + rsize -= offset; + while (rsize--) + aopPut (AOP (result), "!zero", offset++); + } +} + /*-----------------------------------------------------------------*/ /* genGenPointerGet - get value from generic pointer space */ /*-----------------------------------------------------------------*/ @@ -4959,12 +6463,15 @@ 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 && !IS_BITVAR (retype)) { /* Just do it */ if (isPtrPair (AOP (left))) { - tsprintf (buffer, "!*pair", getPairName (AOP (left))); + tsprintf (buffer, sizeof(buffer), + "!*pair", getPairName (AOP (left))); aopPut (AOP (result), buffer, 0); } else @@ -4976,17 +6483,71 @@ genGenPointerGet (operand * left, goto release; } + if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype)) + { + /* Just do it */ + offset = 0; + while (size--) + { + char at[20]; + tsprintf (at, sizeof(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); + genUnpackBits (result, pair); + freeAsmop (left, NULL, ic); + goto release; + //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"); + spillPair (PAIR_HL); + } + 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 { @@ -4996,7 +6557,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++); } @@ -5013,6 +6575,8 @@ genGenPointerGet (operand * left, } } + freeAsmop (left, NULL, ic); + release: freeAsmop (result, NULL, ic); } @@ -5040,11 +6604,154 @@ 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; } + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, + operand * right, + int pair, + iCode *ic) +{ + int offset = 0; /* source byte offset */ + int rlen = 0; /* remaining bitfield length */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + int litval; /* source literal value (if AOP_LIT) */ + unsigned char mask; /* bitmask within current byte */ + int extraPair; /* a tempory register */ + bool needPopExtra=0; /* need to restore original value of temp reg */ + + emitDebug ("; genPackBits",""); + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + mask = ((unsigned char) (0xFF << (blen + bstr)) | + (unsigned char) (0xFF >> (8 - bstr))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with a bitfield length <8 and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval <<= bstr; + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + emit2 ("ld !*pair,a", _pairs[pair].name); + return; + } + else + { + /* Case with a bitfield length <8 and arbitrary source + */ + _moveA (aopGet (AOP (right), 0, FALSE)); + /* shift and mask source value */ + AccLsh (bstr); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = PAIR_BC; + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (needPopExtra) + _pop (extraPair); + return; + } + } + + /* Bit length is greater than 7 bits. In this case, copy */ + /* all except the partial byte at the end */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) ); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* If there was a partial byte at the end */ + if (rlen) + { + mask = (((unsigned char) -1 << rlen) & 0xff); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with partial byte and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval >>= (blen-rlen); + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + } + else + { + /* Case with partial byte and arbitrary source + */ + _moveA (aopGet (AOP (right), offset++, FALSE)); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = getPairId (AOP (right)); + if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID)) + extraPair = PAIR_BC; + + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + if (needPopExtra) + _pop (extraPair); + + } + emit2 ("ld !*pair,a", _pairs[pair].name); + } +} + + /*-----------------------------------------------------------------*/ /* genGenPointerSet - stores the value into a pointer location */ /*-----------------------------------------------------------------*/ @@ -5054,16 +6761,23 @@ genGenPointerSet (operand * right, { int size, offset; sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (result)); PAIR_ID pairId = PAIR_HL; - + bool isBitvar; + aopOp (result, ic, FALSE, FALSE); aopOp (right, ic, FALSE, FALSE); if (IS_GB) pairId = PAIR_DE; + size = AOP_SIZE (right); + + isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype); + emitDebug("; isBitvar = %d", isBitvar); + /* Handle the exceptions first */ - if (isPair (AOP (result)) && (AOP_SIZE (right) == 1)) + if (isPair (AOP (result)) && size == 1 && !isBitvar) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -5079,30 +6793,85 @@ genGenPointerSet (operand * right, } goto release; } - - /* if the operand is already in dptr - then we do nothing else we move the value to dptr */ - if (AOP_TYPE (result) != AOP_STR) + + if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar) { - fetchPair (pairId, AOP (result)); - } - /* so hl know contains the address */ - freeAsmop (result, NULL, ic); + /* Just do it */ + const char *l = aopGet (AOP (right), 0, FALSE); - /* if bit then unpack */ - if (IS_BITVAR (retype)) - { - wassert (0); - } - else - { - size = AOP_SIZE (right); offset = 0; - - while (size--) - { - const char *l = aopGet (AOP (right), offset, FALSE); - if (isRegOrLit (AOP (right)) && !IS_GB) + 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) + && !isBitvar) + { + 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 */ + if (AOP_TYPE (result) != AOP_STR) + { + fetchPair (pairId, AOP (result)); + } + /* so hl now contains the address */ + freeAsmop (result, NULL, ic); + + /* if bit then unpack */ + if (isBitvar) + { + genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic); + goto release; + //wassert (0); + } + else + { + offset = 0; + + while (size--) + { + const char *l = aopGet (AOP (right), offset, FALSE); + if (isRegOrLit (AOP (right)) && !IS_GB) { emit2 ("ld !*pair,%s", _pairs[pairId].name, l); } @@ -5156,7 +6925,7 @@ genIfx (iCode * ic, iCode * popIc) /* get the value into acc */ if (AOP_TYPE (cond) != AOP_CRY) - toBoolean (cond); + _toBoolean (cond); else isbit = 1; /* the result is now in the accumulator */ @@ -5198,21 +6967,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 { @@ -5221,17 +6988,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); } @@ -5249,14 +7015,12 @@ genAssign (iCode * ic) result = IC_RESULT (ic); right = IC_RIGHT (ic); -#if 1 /* Dont bother assigning if they are the same */ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) { - emit2 ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); + emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); return; } -#endif aopOp (right, ic, FALSE, FALSE); aopOp (result, ic, TRUE, FALSE); @@ -5264,14 +7028,14 @@ genAssign (iCode * ic) /* if they are the same registers */ if (sameRegs (AOP (right), AOP (result))) { - emit2 ("; (registers are the same)"); + emitDebug ("; (registers are the same)"); goto release; } /* if the result is a bit */ if (AOP_TYPE (result) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to assign to a bit"); } /* general case */ @@ -5279,10 +7043,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) && @@ -5320,6 +7087,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. */ @@ -5328,12 +7101,34 @@ genAssign (iCode * ic) aopPut (AOP (result), "a", 0); aopPut (AOP (result), "e", 1); } + else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB) + { + /* Special case - simple memcpy */ + aopGet (AOP (right), LSB, FALSE); + emit2 ("ld d,h"); + emit2 ("ld e,l"); + aopGet (AOP (result), LSB, FALSE); + + while (size--) + { + emit2 ("ld a,(de)"); + /* Peephole will optimise this. */ + emit2 ("ld (hl),a"); + + if (size != 0) + { + emit2 ("inc hl"); + emit2 ("inc de"); + } + } + spillPair (PAIR_HL); + } else { 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); @@ -5391,7 +7186,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; @@ -5405,7 +7200,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 */ @@ -5429,16 +7224,7 @@ genCast (iCode * ic) goto release; } - /* PENDING: should be OK. */ -#if 0 - /* if the result is of type pointer */ - if (IS_PTR (ctype)) - { - wassert (0); - } -#endif - - /* so we now know that the size of destination is greater + /* So we now know that the size of destination is greater than the size of the source */ /* we move to result for the size of source */ size = AOP_SIZE (right); @@ -5454,7 +7240,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 (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY) { while (size--) aopPut (AOP (result), "!zero", offset++); @@ -5465,7 +7251,6 @@ genCast (iCode * ic) const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE); _moveA (l); - emit2 ("; genCast: sign extend untested."); emit2 ("rla "); emit2 ("sbc a,a"); while (size--) @@ -5506,6 +7291,577 @@ genReceive (iCode * ic) freeAsmop (IC_RESULT (ic), NULL, ic); } +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + operand *op; + int size, offset; + + op = IC_RIGHT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* general case */ + size = AOP_SIZE (op); + offset = 0; + + while (size--) + { + _moveA (aopGet (AOP (op), offset, FALSE)); + offset++; + } + + freeAsmop (op, NULL, ic); + } + + op = IC_LEFT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* general case */ + size = AOP_SIZE (op); + offset = 0; + + while (size--) + { + _moveA (aopGet (AOP (op), offset, FALSE)); + offset++; + } + + freeAsmop (op, NULL, ic); + } +} + +enum + { + /** Maximum number of bytes to emit per line. */ + DBEMIT_MAX_RUN = 8 + }; + +/** Context for the byte output chunker. */ +typedef struct +{ + unsigned char buffer[DBEMIT_MAX_RUN]; + int pos; +} DBEMITCTX; + + +/** Flushes a byte chunker by writing out all in the buffer and + reseting. +*/ +static void +_dbFlush(DBEMITCTX *self) +{ + char line[256]; + + if (self->pos > 0) + { + int i; + sprintf(line, ".db 0x%02X", self->buffer[0]); + + for (i = 1; i < self->pos; i++) + { + sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]); + } + emit2(line); + } + self->pos = 0; +} + +/** Write out another byte, buffering until a decent line is + generated. +*/ +static void +_dbEmit(DBEMITCTX *self, int c) +{ + if (self->pos == DBEMIT_MAX_RUN) + { + _dbFlush(self); + } + self->buffer[self->pos++] = c; +} + +/** Context for a simple run length encoder. */ +typedef struct +{ + unsigned last; + unsigned char buffer[128]; + int pos; + /** runLen may be equivalent to pos. */ + int runLen; +} RLECTX; + +enum + { + RLE_CHANGE_COST = 4, + RLE_MAX_BLOCK = 127 + }; + +/** Flush the buffer of a run length encoder by writing out the run or + data that it currently contains. +*/ +static void +_rleCommit(RLECTX *self) +{ + int i; + if (self->pos != 0) + { + DBEMITCTX db; + memset(&db, 0, sizeof(db)); + + emit2(".db %u", self->pos); + + for (i = 0; i < self->pos; i++) + { + _dbEmit(&db, self->buffer[i]); + } + _dbFlush(&db); + } + /* Reset */ + self->pos = 0; +} + +/* Encoder design: + Can get either a run or a block of random stuff. + Only want to change state if a good run comes in or a run ends. + Detecting run end is easy. + Initial state? + + Say initial state is in run, len zero, last zero. Then if you get a + few zeros then something else then a short run will be output. + Seems OK. While in run mode, keep counting. While in random mode, + keep a count of the run. If run hits margin, output all up to run, + restart, enter run mode. +*/ + +/** Add another byte into the run length encoder, flushing as + required. The run length encoder uses the Amiga IFF style, where + a block is prefixed by its run length. A positive length means + the next n bytes pass straight through. A negative length means + that the next byte is repeated -n times. A zero terminates the + chunks. +*/ +static void +_rleAppend(RLECTX *self, unsigned c) +{ + int i; + + if (c != self->last) + { + /* The run has stopped. See if it is worthwhile writing it out + as a run. Note that the random data comes in as runs of + length one. + */ + if (self->runLen > RLE_CHANGE_COST) + { + /* Yes, worthwhile. */ + /* Commit whatever was in the buffer. */ + _rleCommit(self); + emit2("!db !immed-%u,!immedbyte", self->runLen, self->last); + } + else + { + /* Not worthwhile. Append to the end of the random list. */ + for (i = 0; i < self->runLen; i++) + { + if (self->pos >= RLE_MAX_BLOCK) + { + /* Commit. */ + _rleCommit(self); + } + self->buffer[self->pos++] = self->last; + } + } + self->runLen = 1; + self->last = c; + } + else + { + if (self->runLen >= RLE_MAX_BLOCK) + { + /* Commit whatever was in the buffer. */ + _rleCommit(self); + + emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last); + self->runLen = 0; + } + self->runLen++; + } +} + +static void +_rleFlush(RLECTX *self) +{ + _rleAppend(self, -1); + _rleCommit(self); + self->pos = 0; + self->last = 0; + self->runLen = 0; +} + +/** genArrayInit - Special code for initialising an array with constant + data. +*/ +static void +genArrayInit (iCode * ic) +{ + literalList *iLoop; + int ix; + int elementSize = 0, eIndex, i; + unsigned val, lastVal; + sym_link *type; + RLECTX rle; + + memset(&rle, 0, sizeof(rle)); + + aopOp (IC_LEFT(ic), ic, FALSE, FALSE); + + _saveRegsForCall(ic, 0); + + fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); + emit2 ("call __initrleblock"); + + type = operandType(IC_LEFT(ic)); + + if (type && type->next) + { + if (IS_SPEC(type->next) || IS_PTR(type->next)) + { + elementSize = getSize(type->next); + } + else if (IS_ARRAY(type->next) && type->next->next) + { + elementSize = getSize(type->next->next); + } + else + { + printTypeChainRaw (type, NULL); + wassertl (0, "Can't determine element size in genArrayInit."); + } + } + else + { + wassertl (0, "Can't determine element size in genArrayInit."); + } + + wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit."); + + iLoop = IC_ARRAYILIST(ic); + lastVal = (unsigned)-1; + + /* Feed all the bytes into the run length encoder which will handle + the actual output. + This works well for mixed char data, and for random int and long + data. + */ + while (iLoop) + { + ix = iLoop->count; + + for (i = 0; i < ix; i++) + { + for (eIndex = 0; eIndex < elementSize; eIndex++) + { + val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff; + _rleAppend(&rle, val); + } + } + + iLoop = iLoop->next; + } + + _rleFlush(&rle); + /* 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 */ /*-----------------------------------------------------------------*/ @@ -5515,7 +7871,7 @@ genZ80Code (iCode * lic) iCode *ic; int cln = 0; - /* HACK */ + /* Hack */ if (IS_GB) { _fReturn = _gbz80_return; @@ -5528,15 +7884,32 @@ genZ80Code (iCode * lic) } _G.lines.head = _G.lines.current = NULL; + + /* if debug information required */ + if (options.debug && currFunc) + { + debugFile->writeFunction (currFunc, lic); + } for (ic = lic; ic; ic = ic->next) { + _G.current_iCode = ic; - if (cln != ic->lineno) + if (ic->lineno && cln != ic->lineno) { - emit2 ("; %s %d", ic->filename, ic->lineno); + if (options.debug) + { + debugFile->writeCLine (ic); + } + if (!options.noCcodeInAsm) { + emit2 (";%s:%d: %s", ic->filename, ic->lineno, + printCLine(ic->filename, ic->lineno)); + } cln = ic->lineno; } + if (options.iCodeInAsm) { + emit2 (";ic:%d: %s", ic->key, printILine(ic)); + } /* if the result is marked as spilt and rematerializable or code for this has already been generated then @@ -5548,22 +7921,22 @@ genZ80Code (iCode * lic) switch (ic->op) { case '!': - emit2 ("; genNot"); + emitDebug ("; genNot"); genNot (ic); break; case '~': - emit2 ("; genCpl"); + emitDebug ("; genCpl"); genCpl (ic); break; case UNARYMINUS: - emit2 ("; genUminus"); + emitDebug ("; genUminus"); genUminus (ic); break; case IPUSH: - emit2 ("; genIpush"); + emitDebug ("; genIpush"); genIpush (ic); break; @@ -5578,83 +7951,83 @@ genZ80Code (iCode * lic) ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) { - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic->next, ic); } else { - emit2 ("; genIpop"); + emitDebug ("; genIpop"); genIpop (ic); } break; case CALL: - emit2 ("; genCall"); + emitDebug ("; genCall"); genCall (ic); break; case PCALL: - emit2 ("; genPcall"); + emitDebug ("; genPcall"); genPcall (ic); break; case FUNCTION: - emit2 ("; genFunction"); + emitDebug ("; genFunction"); genFunction (ic); break; case ENDFUNCTION: - emit2 ("; genEndFunction"); + emitDebug ("; genEndFunction"); genEndFunction (ic); break; case RETURN: - emit2 ("; genRet"); + emitDebug ("; genRet"); genRet (ic); break; case LABEL: - emit2 ("; genLabel"); + emitDebug ("; genLabel"); genLabel (ic); break; case GOTO: - emit2 ("; genGoto"); + emitDebug ("; genGoto"); genGoto (ic); break; case '+': - emit2 ("; genPlus"); + emitDebug ("; genPlus"); genPlus (ic); break; case '-': - emit2 ("; genMinus"); + emitDebug ("; genMinus"); genMinus (ic); break; case '*': - emit2 ("; genMult"); + emitDebug ("; genMult"); genMult (ic); break; case '/': - emit2 ("; genDiv"); + emitDebug ("; genDiv"); genDiv (ic); break; case '%': - emit2 ("; genMod"); + emitDebug ("; genMod"); genMod (ic); break; case '>': - emit2 ("; genCmpGt"); + emitDebug ("; genCmpGt"); genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '<': - emit2 ("; genCmpLt"); + emitDebug ("; genCmpLt"); genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); break; @@ -5669,66 +8042,67 @@ genZ80Code (iCode * lic) break; case EQ_OP: - emit2 ("; genCmpEq"); + emitDebug ("; genCmpEq"); genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); break; case AND_OP: - emit2 ("; genAndOp"); + emitDebug ("; genAndOp"); genAndOp (ic); break; case OR_OP: - emit2 ("; genOrOp"); + emitDebug ("; genOrOp"); genOrOp (ic); break; case '^': - emit2 ("; genXor"); + emitDebug ("; genXor"); genXor (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '|': - emit2 ("; genOr"); + emitDebug ("; genOr"); genOr (ic, ifxForOp (IC_RESULT (ic), ic)); break; case BITWISEAND: - emit2 ("; genAnd"); + emitDebug ("; genAnd"); genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); break; case INLINEASM: - emit2 ("; genInline"); + emitDebug ("; genInline"); genInline (ic); break; case RRC: - emit2 ("; genRRC"); + emitDebug ("; genRRC"); genRRC (ic); break; case RLC: - emit2 ("; genRLC"); + emitDebug ("; genRLC"); genRLC (ic); break; case GETHBIT: - emit2 ("; genHBIT"); - wassert (0); + emitDebug ("; genGetHBIT"); + genGetHbit (ic); + break; case LEFT_OP: - emit2 ("; genLeftShift"); + emitDebug ("; genLeftShift"); genLeftShift (ic); break; case RIGHT_OP: - emit2 ("; genRightShift"); + emitDebug ("; genRightShift"); genRightShift (ic); break; case GET_VALUE_AT_ADDRESS: - emit2 ("; genPointerGet"); + emitDebug ("; genPointerGet"); genPointerGet (ic); break; @@ -5736,50 +8110,66 @@ genZ80Code (iCode * lic) if (POINTER_SET (ic)) { - emit2 ("; genAssign (pointer)"); + emitDebug ("; genAssign (pointer)"); genPointerSet (ic); } else { - emit2 ("; genAssign"); + emitDebug ("; genAssign"); genAssign (ic); } break; case IFX: - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic, NULL); break; case ADDRESS_OF: - emit2 ("; genAddrOf"); + emitDebug ("; genAddrOf"); genAddrOf (ic); break; case JUMPTABLE: - emit2 ("; genJumpTab"); + emitDebug ("; genJumpTab"); genJumpTab (ic); break; case CAST: - emit2 ("; genCast"); + emitDebug ("; genCast"); genCast (ic); break; case RECEIVE: - emit2 ("; genReceive"); + emitDebug ("; genReceive"); genReceive (ic); break; case SEND: - emit2 ("; 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; + + case DUMMY_READ_VOLATILE: + emitDebug ("; genDummyRead"); + genDummyRead (ic); break; default: ic = ic; - /* piCode(ic,stdout); */ - } } @@ -5803,6 +8193,9 @@ genZ80Code (iCode * lic) } codeOutFile = fp; } + + freeTrace(&_G.lines.trace); + freeTrace(&_G.trace.aops); } /* @@ -5825,4 +8218,26 @@ _isPairUsed (iCode * ic, PAIR_ID pairId) return ret; } +static char * +fetchLitSpecial (asmop * aop, bool negate, bool xor) +{ + unsigned long v; + value *val = aop->aopu.aop_lit; + + wassert (aop->type == AOP_LIT); + wassert (!IS_FLOAT (val->type)); + + v = (unsigned long) floatFromVal (val); + + if (xor) + v ^= 0x8000; + if (negate) + v = 0-v; + v &= 0xFFFF; + + tsprintf (buffer, sizeof(buffer), "!immedword", v); + return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); +} + + */