X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=c8c6df5cf302e736d0d4445091db587bf5852b40;hb=0c679255e305cc36b7036a7d2be3da0213bc6c78;hp=10edebd57a5fe6b580d4612f1cd6cfd27360683c;hpb=52311272996ce8f4e0ff92b7e20f9054b63f1cfc;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 10edebd5..c8c6df5c 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,6 +27,59 @@ -------------------------------------------------------------------------*/ +/* + 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. + + 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 @@ -61,133 +96,154 @@ #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 */ -static char *spname; +/* Z80 calling convention description. + Parameters are passed right to left. As the stack grows downwards, + the parameters are arranged in left to right in memory. + Parameters may be passed in the HL and DE registers with one + parameter per pair. + 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. + 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 + are passed on the stack. + 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[] = {"e", "d", "l", "h"}; +static char *_fReceive[] = + { "c", "b", "e", "d" }; + static char **_fReturn; static char **_fTmp; -/* PENDING: messy */ -static char zero[20]; - -static char *accUse[] = -{"a"}; -static char *hlUse[] = -{"l", "h"}; -short rbank = -1; -short accInUse = 0; -short inLine = 0; -short debugLine = 0; -short nregssaved = 0; -extern int ptrRegReq; -extern int nRegs; extern FILE *codeOutFile; -set *sendSet = NULL; +/** Enum covering all the possible register pairs. + */ typedef enum { PAIR_INVALID, + PAIR_AF, PAIR_BC, PAIR_DE, PAIR_HL, PAIR_IY, PAIR_IX, NUM_PAIRS - } -PAIR_ID; + } PAIR_ID; static struct - { - const char *name; - const char *l; - const char *h; - } -_pairs[NUM_PAIRS] = { - { - "??", "?", "?" - } - , - { - "bc", "c", "b" - } - , - { - "de", "e", "d" - } - , - { - "hl", "l", "h" - } - , - { - "iy", "iy.l?", "iy.h?" - } - , - { - "ix", "ix.l?", "ix.h?" - } + const char *name; + const char *l; + const char *h; +} _pairs[NUM_PAIRS] = { + { "??1", "?2", "?3" }, + { "af", "f", "a" }, + { "bc", "c", "b" }, + { "de", "e", "d" }, + { "hl", "l", "h" }, + { "iy", "iy.l?", "iy.h?" }, + { "ix", "ix.l?", "ix.h?" } }; +// 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 ) -#define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x); -#define CLRC emitcode("xor","a,a"); +enum + { + LSB, + MSB16, + MSB24, + MSB32 + }; -lineNode *lineHead = NULL; -lineNode *lineCurr = NULL; +/** 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 *base; + int offset; + } pairs[NUM_PAIRS]; + struct + { + int last; + int pushed; + int param_offset; + int offset; + int pushedBC; + int pushedDE; + } stack; + int frameId; + int receiveOffset; + bool flushStatics; + bool in_home; + const char *lastFunctionName; + + set *sendSet; + + struct + { + /** TRUE if the registers have already been saved. */ + bool saved; + } saves; -static const unsigned char SLMask[] = -{0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00}; -static const unsigned char SRMask[] = -{0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00}; + struct + { + lineNode *head; + lineNode *current; + int isInline; + } lines; -#define LSB 0 -#define MSB16 1 -#define MSB24 2 -#define MSB32 3 +} _G; -/* Stack frame: - IX+4 param0 LH - IX+2 ret LH - IX+0 ix LH - IX-2 temp0 LH - */ +static const char *aopGet (asmop * aop, int offset, bool bit16); -static struct - { - struct - { - AOP_TYPE last_type; - const char *lit; - int offset; - } - pairs[NUM_PAIRS]; - struct - { - int last; - int pushed; - int param_offset; - int offset; - int pushed_bc; - int pushed_de; - } - stack; - int frameId; - bool flush_statics; - bool in_home; - } -_G; +static PAIR_ID +_getTempPairId(void) +{ + if (IS_GB) + { + return PAIR_DE; + } + else + { + return PAIR_HL; + } +} -static char *aopGet (asmop * aop, int offset, bool bit16); +static const char * +_getTempPairName(void) +{ + return _pairs[_getTempPairId()].name; +} static void _tidyUp (char *buf) @@ -200,45 +256,68 @@ _tidyUp (char *buf) } /* Change the first (and probably only) ' ' to a tab so everything lines up. - */ + */ while (*buf) { if (*buf == ' ') - { - *buf = '\t'; - return; - } + { + *buf = '\t'; + break; + } buf++; } } static void -emit2 (const char *szFormat,...) +_vemit2 (const char *szFormat, va_list ap) { char buffer[256]; + + tvsprintf (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; +} + +static void +emit2 (const char *szFormat,...) +{ va_list ap; va_start (ap, szFormat); - tvsprintf (buffer, szFormat, ap); + _vemit2 (szFormat, ap); - _tidyUp (buffer); - lineCurr = (lineCurr ? - connectLine (lineCurr, newLineNode (buffer)) : - (lineHead = newLineNode (buffer))); + va_end (ap); +} - lineCurr->isInline = inLine; - lineCurr->isDebug = debugLine; +static void +emitDebug (const char *szFormat,...) +{ + if (!DISABLE_DEBUG) + { + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); + } } /*-----------------------------------------------------------------*/ -/* emitcode - writes the code into a file : for now it is simple */ +/* emit2 - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ void -emitcode (const char *inst, const char *fmt,...) +_emit2 (const char *inst, const char *fmt,...) { va_list ap; - char lb[MAX_INLINEASM]; + char lb[INITIAL_INLINEASM]; char *lbp = lb; va_start (ap, fmt); @@ -255,33 +334,41 @@ emitcode (const char *inst, const char *fmt,...) lbp++; if (lbp && *lbp) - lineCurr = (lineCurr ? - connectLine (lineCurr, newLineNode (lb)) : - (lineHead = newLineNode (lb))); - lineCurr->isInline = inLine; - lineCurr->isDebug = debugLine; + { + _G.lines.current = (_G.lines.current ? + connectLine (_G.lines.current, newLineNode (lb)) : + (_G.lines.head = newLineNode (lb))); + } + _G.lines.current->isInline = _G.lines.isInline; va_end (ap); } -/* Z80: - { "adjustsp", - "\tld hl,#-%d\n" - "\tadd hl,sp\n" - "\tld sp,hl" - } - { "prelude", - "push bc" - "push de" - "push ix" - "ld ix,#0" - "add ix,sp" - { "leave" - emitcode("ld", "sp,ix"); - emitcode("pop", "ix"); - emitcode("pop", "de"); - } - } - */ +static void +_emitMove(const char *to, const char *from) +{ + if (strcasecmp(to, from) != 0) + { + emit2("ld %s,%s", to, from); + } + else + { + // Optimise it out. + // Could leave this to the peephole, but sometimes the peephole is inhibited. + } +} + +static void +_moveA(const char *moveFrom) +{ + // Let the peephole optimiser take care of redundent loads + _emitMove(ACC_NAME, moveFrom); +} + +static void +_clearCarry(void) +{ + emit2("xor a,a"); +} const char * getPairName (asmop * aop) @@ -316,7 +403,7 @@ getPairName (asmop * aop) break; } } - wassert (0); + wassertl (0, "Tried to get the pair name of something that isn't a pair"); return NULL; } @@ -384,9 +471,22 @@ isPtrPair (asmop * aop) void genPairPush (asmop * aop) { - emitcode ("push", "%s", getPairName (aop)); + emit2 ("push %s", getPairName (aop)); } +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; +} /*-----------------------------------------------------------------*/ /* newAsmop - creates a new asmOp */ @@ -423,7 +523,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* Assign depending on the storage class */ if (sym->onStack || sym->iaccess) { - emitcode ("", "; AOP_STK for %s", sym->rname); + emitDebug ("; AOP_STK for %s", sym->rname); sym->aop = aop = newAsmop (AOP_STK); aop->size = getSize (sym->type); aop->aopu.aop_stk = sym->stack; @@ -448,7 +548,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) sym->aop = aop = newAsmop (AOP_SFR); aop->aopu.aop_dir = sym->rname; aop->size = getSize (sym->type); - emitcode ("", "; AOP_SFR for %s", sym->rname); + emitDebug ("; AOP_SFR for %s", sym->rname); return aop; } } @@ -457,7 +557,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* in which case DPTR gets the address */ if (IS_GB) { - emitcode ("", "; AOP_HL for %s", sym->rname); + emitDebug ("; AOP_HL for %s", sym->rname); sym->aop = aop = newAsmop (AOP_HL); } else @@ -694,24 +794,27 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) if (sym->accuse) { - int i; if (sym->accuse == ACCUSE_A) { aop = op->aop = sym->aop = newAsmop (AOP_ACC); aop->size = getSize (sym->type); - for (i = 0; i < 2; i++) - aop->aopu.aop_str[i] = accUse[i]; + wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A"); + + aop->aopu.aop_str[0] = _pairs[PAIR_AF].h; } else if (sym->accuse == ACCUSE_HL) { wassert (!IS_GB); aop = op->aop = sym->aop = newAsmop (AOP_HLREG); aop->size = getSize (sym->type); - for (i = 0; i < 2; i++) - aop->aopu.aop_str[i] = hlUse[i]; + 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 - wassert (0); + else + { + wassertl (0, "Marked as being allocated into A or HL but is actually in neither"); + } return; } @@ -796,10 +899,6 @@ 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) { @@ -808,12 +907,19 @@ 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 (s, "!hashedstr + %d", aop->aopu.aop_immd, offset); + } + else if (offset == 0) + { + tsprintf (s, "%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 (s, "%s + %d", aop->aopu.aop_immd, offset); + } + return gc_strdup(s); + case AOP_LIT: { value *val = aop->aopu.aop_lit; @@ -824,14 +930,24 @@ 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); else tsprintf (buffer, "!constword", v); - rs = Safe_calloc (1, strlen (buffer) + 1); - return strcpy (rs, buffer); + + return gc_strdup(buffer); } else { @@ -876,12 +992,12 @@ adjustPair (const char *pair, int *pold, int new) while (*pold < new) { - emitcode ("inc", "%s", pair); + emit2 ("inc %s", pair); (*pold)++; } while (*pold > new) { - emitcode ("dec", "%s", pair); + emit2 ("dec %s", pair); (*pold)--; } } @@ -890,7 +1006,7 @@ static void spillPair (PAIR_ID pairId) { _G.pairs[pairId].last_type = AOP_INVALID; - _G.pairs[pairId].lit = NULL; + _G.pairs[pairId].base = NULL; } static void @@ -905,6 +1021,7 @@ requiresHL (asmop * aop) { switch (aop->type) { + case AOP_IY: case AOP_HL: case AOP_STK: return TRUE; @@ -913,34 +1030,14 @@ requiresHL (asmop * aop) } } -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)) { @@ -948,7 +1045,7 @@ 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) { @@ -963,74 +1060,59 @@ 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].offset = offset; - } - if (IS_GB && pairId == PAIR_DE && 0) - { - 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].base = gc_strdup (base); _G.pairs[pairId].offset = offset; } /* 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); + emit2 ("ld %s,!hashedstr", pair, l); } static void fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) { - /* if this is remateriazable */ - if (isLitWord (aop)) - { - fetchLitPair (pairId, aop, offset); - } - else - { /* we need to get it byte by byte */ - if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) - { - aopGet (aop, offset, FALSE); - switch (aop->size) - { - case 1: - emit2 ("ld l,!*hl"); - emit2 ("ld h,!immedbyte", 0); - break; - case 2: - emit2 ("!ldahli"); - emit2 ("ld h,!*hl"); - emit2 ("ld l,a"); - break; - default: - emit2 ("; WARNING: mlh woosed out. This code is invalid."); - } - } - else if (IS_Z80 && aop->type == AOP_IY) - { - /* Instead of fetching relative to IY, just grab directly - from the address IY refers to */ - char *l = aopGetLitWordLong (aop, offset, FALSE); - wassert (l); - emit2 ("ld %s,(%s)", _pairs[pairId].name, l); - } - else - { - emitcode ("ld", "%s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE)); - emitcode ("ld", "%s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE)); - } - /* PENDING: check? */ - if (pairId == PAIR_HL) - spillPair (PAIR_HL); + /* if this is remateriazable */ + if (isLitWord (aop)) { + fetchLitPair (pairId, aop, offset); + } + else { + /* we need to get it byte by byte */ + if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) { + aopGet (aop, offset, FALSE); + 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: + wassertl (0, "Attempted to fetch too much data into HL"); + break; + } + } + else if (IS_Z80 && aop->type == AOP_IY) { + /* Instead of fetching relative to IY, just grab directly + from the address IY refers to */ + char *l = aopGetLitWordLong (aop, offset, FALSE); + wassert (l); + emit2 ("ld %s,(%s)", _pairs[pairId].name, l); + + if (aop->size < 2) { + emit2("ld %s,!zero", _pairs[pairId].h); + } + } + 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); } } @@ -1097,17 +1179,19 @@ emitLabel (int key) /*-----------------------------------------------------------------*/ /* aopGet - for fetching value of the aop */ /*-----------------------------------------------------------------*/ -static char * +static const char * aopGet (asmop * aop, int offset, bool bit16) { char *s = buffer; - char *rs; /* 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) - return zero; + aop->type != AOP_LIT) + { + tsprintf (s, "!zero"); + return gc_strdup(s); + } /* depending on type */ switch (aop->type) @@ -1129,27 +1213,24 @@ aopGet (asmop * aop, int offset, bool bit16) tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd); break; default: - wassert (0); + wassertl (0, "Fetching from beyond the limits of an immediate value."); } - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); case AOP_DIR: wassert (IS_GB); - emitcode ("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); case AOP_SFR: wassert (IS_GB); - emitcode ("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); case AOP_REG: return aop->aopu.aop_reg[offset]->name; @@ -1158,15 +1239,15 @@ aopGet (asmop * aop, int offset, bool bit16) wassert (IS_GB); setupPair (PAIR_HL, aop, offset); tsprintf (s, "!*hl"); + return gc_strdup (s); case AOP_IY: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); tsprintf (s, "!*iyx", offset); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); case AOP_STK: if (IS_GB) @@ -1178,21 +1259,24 @@ aopGet (asmop * aop, int offset, bool bit16) { if (aop->aopu.aop_stk >= 0) offset += _G.stack.param_offset; - tsprintf (s, "!*ixx ; x", aop->aopu.aop_stk + offset); + tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset); } - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); case AOP_CRY: - wassert (0); + wassertl (0, "Tried to fetch from a bit variable"); case AOP_ACC: if (!offset) { return "a"; } - return "!zero"; + else + { + tsprintf(s, "!zero"); + return gc_strdup(s); + } case AOP_HLREG: wassert (offset < 2); @@ -1201,9 +1285,19 @@ 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 (s, "!immedbyte", (unsigned int) v & 0xff); + + return gc_strdup(s); + } case AOP_STR: aop->coff = offset; return aop->aopu.aop_str[offset]; + default: break; } @@ -1248,6 +1342,8 @@ canAssignToPtr (const char *s) static void aopPut (asmop * aop, const char *s, int offset) { + char buffer2[256]; + if (aop->size && offset > (aop->size - 1)) { werror (E_INTERNAL_ERROR, __FILE__, __LINE__, @@ -1255,6 +1351,10 @@ aopPut (asmop * aop, const char *s, int offset) exit (0); } + // PENDING + tsprintf(buffer2, s); + s = buffer2; + /* will assign value to value */ /* depending on where it is ofcourse */ switch (aop->type) @@ -1263,15 +1363,15 @@ aopPut (asmop * aop, const char *s, int offset) /* Direct. Hmmm. */ wassert (IS_GB); if (strcmp (s, "a")) - emitcode ("ld", "a,%s", s); - emitcode ("ld", "(%s+%d),a", aop->aopu.aop_dir, offset); + emit2 ("ld a,%s", s); + emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset); break; case AOP_SFR: wassert (IS_GB); if (strcmp (s, "a")) - emitcode ("ld", "a,%s", s); - emitcode ("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset); + emit2 ("ld a,%s", s); + emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset); break; case AOP_REG: @@ -1349,7 +1449,7 @@ aopPut (asmop * aop, const char *s, int offset) else { /* In bit space but not in C - cant happen */ - wassert (0); + wassertl (0, "Tried to write into a bit variable"); } break; @@ -1357,7 +1457,7 @@ aopPut (asmop * aop, const char *s, int offset) aop->coff = offset; if (strcmp (aop->aopu.aop_str[offset], s)) { - emitcode ("ld", "%s,%s", aop->aopu.aop_str[offset], s); + emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); } break; @@ -1367,13 +1467,12 @@ aopPut (asmop * aop, const char *s, int offset) break; if (offset > 0) { - - emitcode ("", "; Error aopPut AOP_ACC"); + wassertl (0, "Tried to access past the end of A"); } else { if (strcmp (aop->aopu.aop_str[offset], s)) - emitcode ("ld", "%s,%s", aop->aopu.aop_str[offset], s); + emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); } break; @@ -1422,7 +1521,7 @@ getDataSize (operand * op) if (size == 3) { /* pointer */ - wassert (0); + wassertl (0, "Somehow got a three byte data pointer"); } return size; } @@ -1434,7 +1533,7 @@ static void movLeft2Result (operand * left, int offl, operand * result, int offr, int sign) { - char *l; + const char *l; if (!sameRegs (AOP (left), AOP (result)) || (offl != offr)) { l = aopGet (AOP (left), offl, FALSE); @@ -1445,7 +1544,11 @@ movLeft2Result (operand * left, int offl, } else { - wassert (0); + if (getDataSize (left) == offl + 1) + { + emit2 ("ld a,%s", l); + aopPut (AOP (result), "a", offr); + } } } } @@ -1466,7 +1569,7 @@ outAcc (operand * result) /* unsigned or positive */ while (size--) { - aopPut (AOP (result), zero, offset++); + aopPut (AOP (result), "!zero", offset++); } } } @@ -1479,8 +1582,7 @@ outBitCLong (operand * result, bool swap_sense) /* if the result is bit */ if (AOP_TYPE (result) == AOP_CRY) { - emitcode ("", "; Note: outBitC form 1"); - aopPut (AOP (result), "blah", 0); + wassertl (0, "Tried to write carry to a bit"); } else { @@ -1502,23 +1604,23 @@ 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; if (size > 1) { - emitcode ("ld", "a,%s", aopGet (AOP (oper), offset++, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE)); size--; while (size--) - emitcode ("or", "a,%s", aopGet (AOP (oper), offset++, FALSE)); + emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE)); } else { if (AOP (oper)->type != AOP_ACC) { - CLRC; - emitcode ("or", "a,%s", aopGet (AOP (oper), 0, FALSE)); + _clearCarry(); + emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE)); } } } @@ -1538,16 +1640,16 @@ genNot (iCode * ic) /* if in bit space then a special case */ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) { - wassert (0); + wassertl (0, "Tried to negate a bit"); } /* if type float then do float */ if (IS_FLOAT (optype)) { - wassert (0); + wassertl (0, "Tried to negate a float"); } - toBoolean (IC_LEFT (ic)); + _toBoolean (IC_LEFT (ic)); /* Not of A: If A == 0, !A = 1 @@ -1580,15 +1682,15 @@ 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)); while (size--) { - char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); - MOVA (l); - emitcode ("cpl", ""); + const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); + _moveA (l); + emit2("cpl"); aopPut (AOP (IC_RESULT (ic)), "a", offset++); } @@ -1597,6 +1699,59 @@ 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, 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); +} + /*-----------------------------------------------------------------*/ /* genUminus - unary minus code generation */ /*-----------------------------------------------------------------*/ @@ -1615,7 +1770,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; } @@ -1625,17 +1780,28 @@ genUminus (iCode * ic) /* if float then do float stuff */ if (IS_FLOAT (optype)) { - wassert (0); + wassertl (0, "Tried to do a unary minus on a float"); 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; - CLRC; + _clearCarry(); while (size--) { - char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); + const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); emit2 ("ld a,!zero"); emit2 ("sbc a,%s", l); aopPut (AOP (IC_RESULT (ic)), "a", offset++); @@ -1657,21 +1823,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 - */ /*-----------------------------------------------------------------*/ @@ -1681,21 +1832,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); - emitcode ("pop", "de"); - _G.stack.pushed -= 2; + _pop (PAIR_DE); aopPut (AOP (oper), _fReturn[0], 2); aopPut (AOP (oper), _fReturn[1], 3); } @@ -1708,6 +1854,61 @@ assignResultValue (operand * oper) } } +static void +_saveRegsForCall(iCode *ic, int sendSetSize) +{ + /* Rules: + o Stack parameters are pushed before this function enters + o DE and BC may be used in this function. + o HL and DE may be used to return the result. + o HL and DE may be used to send variables. + o DE and BC may be used to store the result value. + o HL may be used in computing the sent value of DE + o The iPushes for other parameters occur before any addSets + + Logic: (to be run inside the first iPush or if none, before sending) + o Compute if DE and/or BC are in use over the call + o Compute if DE is used in the send set + o Compute if DE and/or BC are used to hold the result value + o If (DE is used, or in the send set) and is not used in the result, push. + o If BC is used and is not in the result, push + o + o If DE is used in the send set, fetch + o If HL is used in the send set, fetch + o Call + o ... + */ + if (_G.saves.saved == FALSE) { + bool deInUse, bcInUse; + bool deSending; + bool bcInRet = FALSE, deInRet = FALSE; + bitVect *rInUse; + + rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + + deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX); + bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX); + + deSending = (sendSetSize > 1); + + emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); + + if (bcInUse && bcInRet == FALSE) { + _push(PAIR_BC); + _G.stack.pushedBC = TRUE; + } + if (deInUse && deInRet == FALSE) { + _push(PAIR_DE); + _G.stack.pushedDE = TRUE; + } + + _G.saves.saved = TRUE; + } + else { + /* Already saved. */ + } +} + /*-----------------------------------------------------------------*/ /* genIpush - genrate code for pushing this gets a little complex */ /*-----------------------------------------------------------------*/ @@ -1715,51 +1916,43 @@ static void genIpush (iCode * ic) { int size, offset = 0; - char *l; + const char *l; /* if this is not a parm push : ie. it is spill push and spill push is always done on the local stack */ if (!ic->parmPush) { - /* 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)))) - { - emitcode ("push", 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++; - } - } + wassertl(0, "Encountered an unsupported spill push."); return; } - /* Hmmm... what about saving the currently used registers - at this point? */ + if (_G.saves.saved == FALSE) { + /* Caller saves, and this is the first iPush. */ + /* Scan ahead until we find the function that we are pushing parameters to. + Count the number of addSets on the way to figure out what registers + are used in the send set. + */ + int nAddSets = 0; + iCode *walk = ic->next; + + while (walk) { + if (walk->op == SEND) { + nAddSets++; + } + else if (walk->op == CALL || walk->op == PCALL) { + /* Found it. */ + break; + } + else { + /* Keep looking. */ + } + walk = walk->next; + } + _saveRegsForCall(walk, nAddSets); + } + else { + /* Already saved by another iPush. */ + } /* then do the push */ aopOp (IC_LEFT (ic), ic, FALSE, FALSE); @@ -1769,14 +1962,14 @@ genIpush (iCode * ic) if (isPair (AOP (IC_LEFT (ic)))) { _G.stack.pushed += 2; - emitcode ("push", "%s", getPairName (AOP (IC_LEFT (ic)))); + emit2 ("push %s", getPairName (AOP (IC_LEFT (ic)))); } else { if (size == 2) { fetchHL (AOP (IC_LEFT (ic))); - emitcode ("push", "hl"); + emit2 ("push hl"); spillPair (PAIR_HL); _G.stack.pushed += 2; goto release; @@ -1784,11 +1977,11 @@ genIpush (iCode * ic) if (size == 4) { fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2); - emitcode ("push", "hl"); + emit2 ("push hl"); spillPair (PAIR_HL); _G.stack.pushed += 2; fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0); - emitcode ("push", "hl"); + emit2 ("push hl"); spillPair (PAIR_HL); _G.stack.pushed += 2; goto release; @@ -1807,8 +2000,8 @@ genIpush (iCode * ic) l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE); emit2 ("ld a,%s", l); } - emitcode ("push", "af"); - emitcode ("inc", "sp"); + emit2 ("push af"); + emit2 ("inc sp"); _G.stack.pushed++; } } @@ -1834,14 +2027,14 @@ genIpop (iCode * ic) offset = (size - 1); if (isPair (AOP (IC_LEFT (ic)))) { - emitcode ("pop", getPairName (AOP (IC_LEFT (ic)))); + emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic)))); } else { while (size--) { - emitcode ("dec", "sp"); - emitcode ("pop", "hl"); + emit2 ("dec sp"); + emit2 ("pop hl"); spillPair (PAIR_HL); aopPut (AOP (IC_LEFT (ic)), "l", offset--); } @@ -1850,22 +2043,30 @@ genIpop (iCode * ic) freeAsmop (IC_LEFT (ic), NULL, ic); } -static int -_isPairUsed (iCode * ic, PAIR_ID pairId) +/* This is quite unfortunate */ +static void +setArea (int inHome) { - int ret = 0; - switch (pairId) - { - case PAIR_DE: - if (bitVectBitValue (ic->rUsed, D_IDX)) - ret++; - if (bitVectBitValue (ic->rUsed, E_IDX)) - ret++; - break; - default: - wassert (0); - } - return ret; + /* + static int lastArea = 0; + + if (_G.in_home != inHome) { + if (inHome) { + const char *sz = port->mem.code_name; + port->mem.code_name = "HOME"; + emit2("!area", CODE_NAME); + port->mem.code_name = sz; + } + else + emit2("!area", CODE_NAME); */ + _G.in_home = inHome; + // } +} + +static bool +isInHome (void) +{ + return _G.in_home; } static int @@ -1888,12 +2089,20 @@ _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")) ret++; } + else if (pairId == PAIR_BC) + { + 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")) + ret++; + } else { wassert (0); @@ -1905,117 +2114,81 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) return ret; } -/* This is quite unfortunate */ -static void -setArea (int inHome) -{ - static int lastArea = 0; - - /* - if (_G.in_home != inHome) { - if (inHome) { - const char *sz = port->mem.code_name; - port->mem.code_name = "HOME"; - emit2("!area", CODE_NAME); - port->mem.code_name = sz; - } - else - emit2("!area", CODE_NAME); */ - _G.in_home = inHome; - // } -} - -static bool -isInHome (void) -{ - return _G.in_home; -} - /** Emit the code for a call statement */ static void emitCall (iCode * ic, bool ispcall) { - int pushed_de = 0; sym_link *detype = getSpec (operandType (IC_LEFT (ic))); + bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + /* if caller saves & we have not saved then */ if (!ic->regsSaved) { /* PENDING */ } + _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0); + /* if send set is not empty then assign */ - if (sendSet) + if (_G.sendSet) { iCode *sic; int send = 0; - int n = elementsInSet (sendSet); - if (IS_Z80 && n == 2 && _isPairUsed (ic, PAIR_DE)) - { - /* Only push de if it is used and if it's not used - in the return value */ - /* Panic if partly used */ - if (_opUsesPair (IC_RESULT (ic), ic, PAIR_DE) == 1) - { - emit2 ("; Warning: de crossover"); - } - else if (!_opUsesPair (IC_RESULT (ic), ic, PAIR_DE)) - { - /* Store away de */ - _push (PAIR_DE); - pushed_de = 1; - } - } - /* PENDING: HACK */ - if (IS_Z80 && n == 2) - { - /* Want to load HL first, then DE as HL may = DE */ - sic = setFirstItem (sendSet); - sic = setNextItem (sendSet); - aopOp (IC_LEFT (sic), sic, FALSE, FALSE); - fetchPair (PAIR_HL, AOP (IC_LEFT (sic))); - send++; - freeAsmop (IC_LEFT (sic), NULL, sic); - sic = setFirstItem (sendSet); - aopOp (IC_LEFT (sic), sic, FALSE, FALSE); - fetchPair (PAIR_DE, AOP (IC_LEFT (sic))); - send++; - freeAsmop (IC_LEFT (sic), NULL, sic); - } - else - { - for (sic = setFirstItem (sendSet); sic; - sic = setNextItem (sendSet)) - { - int size; - aopOp (IC_LEFT (sic), sic, FALSE, FALSE); - size = AOP_SIZE (IC_LEFT (sic)); - wassert (size <= 2); - /* Always send in pairs */ - switch (send) - { - case 0: - if (IS_Z80 && n == 1) - fetchPair (PAIR_HL, AOP (IC_LEFT (sic))); - else - fetchPair (PAIR_DE, AOP (IC_LEFT (sic))); - break; - case 1: - fetchPair (PAIR_HL, AOP (IC_LEFT (sic))); - break; - default: - /* Send set too big */ - wassert (0); - } - send++; - freeAsmop (IC_LEFT (sic), NULL, sic); - } - } - sendSet = NULL; - if (pushed_de) - { - } + int nSend = elementsInSet(_G.sendSet); + bool swapped = FALSE; + + int _z80_sendOrder[] = { + PAIR_BC, PAIR_DE + }; + + if (nSend > 1) { + /* Check if the parameters are swapped. If so route through hl instead. */ + wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case."); + + sic = setFirstItem(_G.sendSet); + sic = setNextItem(_G.sendSet); + + if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) { + /* The second send value is loaded from one the one that holds the first + send, i.e. it is overwritten. */ + /* Cache the first in HL, and load the second from HL instead. */ + emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h); + emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l); + + swapped = TRUE; + } + } + + for (sic = setFirstItem (_G.sendSet); sic; + sic = setNextItem (_G.sendSet)) + { + int size; + aopOp (IC_LEFT (sic), sic, FALSE, FALSE); + + size = AOP_SIZE (IC_LEFT (sic)); + wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes"); + wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for"); + + // PENDING: Mild hack + if (swapped == TRUE && send == 1) { + if (size > 1) { + emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h); + } + else { + emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h); + } + emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l); + } + else { + fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic))); + } + + send++; + freeAsmop (IC_LEFT (sic), NULL, sic); + } + _G.sendSet = NULL; } if (ispcall) @@ -2028,15 +2201,14 @@ emitCall (iCode * ic, bool ispcall) if (isLitWord (AOP (IC_LEFT (ic)))) { - emitcode ("", "; Special case where the pCall is to a constant"); - emitcode ("call", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE)); + emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE)); } else { symbol *rlbl = newiTempLabel (NULL); spillPair (PAIR_HL); emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100)); - emitcode ("push", "hl"); + emit2 ("push hl"); _G.stack.pushed += 2; fetchHL (AOP (IC_LEFT (ic))); @@ -2065,6 +2237,9 @@ emitCall (iCode * ic, bool ispcall) } spillCached (); + /* Mark the regsiters as restored. */ + _G.saves.saved = FALSE; + /* if we need assign a result value */ if ((IS_ITEMP (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->nRegs || @@ -2072,9 +2247,7 @@ emitCall (iCode * ic, bool ispcall) IS_TRUE_SYMOP (IC_RESULT (ic))) { - accInUse++; aopOp (IC_RESULT (ic), ic, FALSE, FALSE); - accInUse--; assignResultValue (IC_RESULT (ic)); @@ -2085,6 +2258,7 @@ emitCall (iCode * ic, bool ispcall) if (ic->parmBytes) { int i = ic->parmBytes; + _G.stack.pushed -= i; if (IS_GB) { @@ -2095,25 +2269,77 @@ emitCall (iCode * ic, bool ispcall) spillCached (); if (i > 6) { - emitcode ("ld", "hl,#%d", i); - emitcode ("add", "hl,sp"); - emitcode ("ld", "sp,hl"); + emit2 ("ld hl,#%d", i); + emit2 ("add hl,sp"); + emit2 ("ld sp,hl"); } else { while (i > 1) { - emitcode ("pop", "hl"); + emit2 ("pop hl"); i -= 2; } if (i) - emitcode ("inc", "sp"); + emit2 ("inc sp"); } spillCached (); } } - if (pushed_de) - _pop (PAIR_DE); + + if (_G.stack.pushedDE) + { + bool dInUse = bitVectBitValue(rInUse, D_IDX); + bool eInUse = bitVectBitValue(rInUse, E_IDX); + + if (dInUse && eInUse) + { + _pop (PAIR_DE); + } + else if (dInUse) + { + _pop(PAIR_HL); + emit2 ("ld d,h"); + } + else if (eInUse) + { + _pop(PAIR_HL); + emit2 ("ld e,l"); + } + else + { + wassertl (0, "Neither D or E were in use but it was pushed."); + } + _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) + { + _pop (PAIR_BC); + } + else if (bInUse) + { + _pop(PAIR_HL); + emit2 ("ld b,h"); + } + else if (cInUse) + { + _pop(PAIR_HL); + emit2 ("ld c,l"); + } + else + { + wassertl (0, "Neither B or C were in use but it was pushed."); + } + _G.stack.pushedBC = FALSE; + } } /*-----------------------------------------------------------------*/ @@ -2122,7 +2348,6 @@ emitCall (iCode * ic, bool ispcall) static void genCall (iCode * ic) { - sym_link *detype = getSpec (operandType (IC_LEFT (ic))); emitCall (ic, FALSE); } @@ -2165,39 +2390,50 @@ genFunction (iCode * ic) symbol *sym = OP_SYMBOL (IC_LEFT (ic)); sym_link *fetype; - nregssaved = 0; +#if CALLEE_SAVES + bool bcInUse = FALSE; + bool deInUse = FALSE; +#endif + setArea (IS_NONBANKED (sym->etype)); - /* PENDING: hack */ - if (!IS_STATIC (sym->etype)) - { - addSetIfnotP (&publics, sym); - } + /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere + else. + */ + _G.receiveOffset = 0; - /* create the function header */ + /* 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); emit2 ("!functionlabeldef", sym->rname); + if (options.profile) + { + emit2 ("!profileenter"); + } + fetype = getSpec (operandType (IC_LEFT (ic))); /* if critical function then turn interrupts off */ if (SPEC_CRTCL (fetype)) emit2 ("!di"); - /* if this is an interrupt service routine then - save acc, b, dpl, dph */ + /* if this is an interrupt service routine then save all potentially used registers. */ if (IS_ISR (sym->etype)) { emit2 ("!pusha"); } + /* PENDING: callee-save etc */ - /* If BC or DE are used, then push */ - _G.stack.pushed_bc = 0; - _G.stack.pushed_de = 0; _G.stack.param_offset = 0; + +#if CALLEE_SAVES + /* Detect which registers are used. */ if (sym->regsUsed) { int i; @@ -2209,28 +2445,39 @@ genFunction (iCode * ic) { case C_IDX: case B_IDX: - _G.stack.pushed_bc = 1; + bcInUse = TRUE; break; case D_IDX: case E_IDX: - if (IS_Z80) - _G.stack.pushed_de = 1; + if (IS_Z80) { + deInUse = TRUE; + } + else { + /* Other systems use DE as a temporary. */ + } break; } } } - if (_G.stack.pushed_bc) - { - emit2 ("push bc"); - _G.stack.param_offset += 2; - } - if (_G.stack.pushed_de) - { - emit2 ("push de"); - _G.stack.param_offset += 2; - } } + if (bcInUse) + { + emit2 ("push bc"); + _G.stack.param_offset += 2; + } + + _G.stack.pushedBC = bcInUse; + + if (deInUse) + { + emit2 ("push de"); + _G.stack.param_offset += 2; + } + + _G.stack.pushedDE = deInUse; +#endif + /* adjust the stack for the function */ _G.stack.last = sym->stack; @@ -2251,7 +2498,7 @@ genEndFunction (iCode * ic) if (IS_ISR (sym->etype)) { - wassert (0); + wassertl (0, "Tried to close an interrupt support function"); } else { @@ -2260,35 +2507,42 @@ genEndFunction (iCode * ic) /* PENDING: calleeSave */ - /* if debug then send end of function */ - if (options.debug && currFunc) - { - debugLine = 1; - emitcode ("", "C$%s$%d$%d$%d ==.", - FileBaseName (ic->filename), currFunc->lastLine, - ic->level, ic->block); - if (IS_STATIC (currFunc->etype)) - emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name); - else - emitcode ("", "XG$%s$0$0 ==.", currFunc->name); - debugLine = 0; - } if (_G.stack.offset) - emit2 ("!leavex", _G.stack.offset); + { + emit2 ("!leavex", _G.stack.offset); + } else - emit2 ("!leave"); + { + emit2 ("!leave"); + } + +#if CALLEE_SAVES + if (_G.stack.pushedDE) + { + emit2 ("pop de"); + _G.stack.pushedDE = FALSE; + } + + if (_G.stack.pushedDE) + { + emit2 ("pop bc"); + _G.stack.pushedDE = FALSE; + } +#endif + + if (options.profile) + { + emit2 ("!profileexit"); + } + - if (_G.stack.pushed_de) - emit2 ("pop de"); - if (_G.stack.pushed_bc) - emit2 ("pop bc"); /* Both baned and non-banked just ret */ emit2 ("ret"); /* PENDING: portability. */ emit2 ("__%s_end:", sym->rname); } - _G.flush_statics = 1; + _G.flushStatics = 1; _G.stack.pushed = 0; _G.stack.offset = 0; } @@ -2299,7 +2553,7 @@ genEndFunction (iCode * ic) static void genRet (iCode * ic) { - char *l; + const char *l; /* Errk. This is a hack until I can figure out how to cause dehl to spill on a call */ int size, offset = 0; @@ -2318,11 +2572,11 @@ genRet (iCode * ic) { if (IS_GB) { - emitcode ("ld", "de,%s", l); + emit2 ("ld de,%s", l); } else { - emitcode ("ld", "hl,%s", l); + emit2 ("ld hl,%s", l); } } else @@ -2339,7 +2593,7 @@ genRet (iCode * ic) l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); if (strcmp (_fReturn[offset], l)) - emitcode ("ld", "%s,%s", _fReturn[offset++], l); + emit2 ("ld %s,%s", _fReturn[offset++], l); } } } @@ -2392,7 +2646,7 @@ genPlusIncr (iCode * ic) if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) return FALSE; - emitcode ("", "; genPlusIncr"); + emitDebug ("; genPlusIncr"); icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); @@ -2407,7 +2661,7 @@ genPlusIncr (iCode * ic) if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2) { fetchPair (resultId, AOP (IC_RIGHT (ic))); - emitcode ("add", "hl,%s", getPairName (AOP (IC_LEFT (ic)))); + emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); return TRUE; } if (icount > 5) @@ -2422,7 +2676,7 @@ genPlusIncr (iCode * ic) } while (icount--) { - emitcode ("inc", "%s", getPairName (AOP (IC_RESULT (ic)))); + emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic)))); } return TRUE; } @@ -2443,7 +2697,7 @@ genPlusIncr (iCode * ic) tlbl = newiTempLabel (NULL); while (size--) { - emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE)); + emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE)); if (size) { emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); @@ -2464,7 +2718,9 @@ genPlusIncr (iCode * ic) if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) { while (icount--) - emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + { + emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + } return TRUE; } @@ -2481,7 +2737,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 { @@ -2527,7 +2783,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 */ @@ -2535,7 +2791,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 @@ -2543,7 +2799,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)); @@ -2551,16 +2807,17 @@ 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 */ char buffer[100]; sprintf (buffer, "#(%s + %s)", left, right); - emitcode ("ld", "%s,%s", getPairName (AOP (IC_RESULT (ic))), buffer); + emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer); goto release; } } @@ -2570,7 +2827,7 @@ genPlus (iCode * ic) /* Fetch into HL then do the add */ spillPair (PAIR_HL); fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); - emitcode ("add", "hl,%s", getPairName (AOP (IC_RIGHT (ic)))); + emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic)))); goto release; } @@ -2634,18 +2891,22 @@ 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; + } } while (size--) { if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC) { - MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); + _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); if (offset == 0) emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE)); @@ -2655,7 +2916,7 @@ genPlus (iCode * ic) } else { - MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); + _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); if (offset == 0) emit2 ("add a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE)); @@ -2694,32 +2955,12 @@ 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); - emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE)); - emitcode ("jp", "np," LABEL_STR, tlbl->key + 100); - - emitcode ("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)))) { while (icount--) - emitcode ("dec", "%s", getPairName (AOP (IC_RESULT (ic)))); + emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic)))); return TRUE; } @@ -2729,10 +2970,27 @@ genMinusDec (iCode * ic) movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0); movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0); while (icount--) - emitcode ("dec", "%s", getPairName (AOP (IC_RESULT (ic)))); + 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) @@ -2743,7 +3001,7 @@ genMinusDec (iCode * ic) if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) { while (icount--) - emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE)); + emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE)); return TRUE; } @@ -2768,7 +3026,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; } @@ -2826,24 +3084,28 @@ genMinus (iCode * ic) 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; + } } /* if literal, add a,#-lit, else normal subb */ while (size--) { - MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); + _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE)); if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) { if (!offset) - emitcode ("sub", "a,%s", + emit2 ("sub a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE)); else - emitcode ("sbc", "a,%s", + emit2 ("sbc a,%s", aopGet (AOP (IC_RIGHT (ic)), offset, FALSE)); } else @@ -2860,7 +3122,9 @@ genMinus (iCode * ic) if (AOP_SIZE (IC_RESULT (ic)) == 3 && AOP_SIZE (IC_LEFT (ic)) == 3 && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)))) - wassert (0); + { + wassertl (0, "Tried to subtract on a long pointer"); + } release: freeAsmop (IC_LEFT (ic), NULL, ic); @@ -2875,7 +3139,7 @@ static void genMult (iCode * ic) { /* Shouldn't occur - all done through function calls */ - wassert (0); + wassertl (0, "Multiplication is handled through support function calls"); } /*-----------------------------------------------------------------*/ @@ -2885,7 +3149,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"); } /*-----------------------------------------------------------------*/ @@ -2955,7 +3219,7 @@ genIfxJump (iCode * ic, char *jval) /* Z80 can do a conditional long jump */ if (!strcmp (jval, "a")) { - emitcode ("or", "a,a"); + emit2 ("or a,a"); } else if (!strcmp (jval, "c")) { @@ -2965,7 +3229,7 @@ genIfxJump (iCode * ic, char *jval) } else { - emitcode ("bit", "%s,a", jval); + emit2 ("bit %s,a", jval); } emit2 ("jp %s,!tlabel", inst, jlbl->key + 100); @@ -2973,11 +3237,13 @@ 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 < */ @@ -2994,7 +3260,7 @@ genCmp (operand * left, operand * right, AOP_TYPE (right) == AOP_CRY) { /* Cant happen on the Z80 */ - wassert (0); + wassertl (0, "Tried to compare two bits"); } else { @@ -3007,56 +3273,58 @@ genCmp (operand * left, operand * right, if ((size == 1) && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR)) { - emitcode ("ld", "a,%s", aopGet (AOP (left), offset, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE)); if (sign) { emit2 ("xor a,!immedbyte", 0x80); emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80); } else - emitcode ("cp", "%s", aopGet (AOP (right), offset, FALSE)); - } + 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 #0x80"); + emit2 ("ld e,a"); + emit2 ("ld a,(hl)"); + emit2 ("xor #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 { - /* 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 (size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == 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); @@ -3066,19 +3334,19 @@ genCmp (operand * left, operand * right, if (!sign) { /* No sign so it's always false */ - CLRC; + _clearCarry(); } else { /* Just load in the top most bit */ - MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); + _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx) { genIfxJump (ifx, "7"); return; } else - emitcode ("rlc", "a"); + emit2 ("rlc a"); } goto release; } @@ -3096,9 +3364,9 @@ genCmp (operand * left, operand * right, } else { - emitcode ("ld", "a,%s", aopGet (AOP (left), size - 1, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE)); emit2 ("xor a,!immedbyte", 0x80); - emitcode ("ld", "%s,a", _fTmp[0]); + emit2 ("ld %s,a", _fTmp[0]); fDidXor = TRUE; } if (AOP_TYPE (right) == AOP_LIT) @@ -3110,34 +3378,28 @@ genCmp (operand * left, operand * right, } else { - emitcode ("ld", "a,%s", aopGet (AOP (right), size - 1, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE)); emit2 ("xor a,!immedbyte", 0x80); - emitcode ("ld", "%s,a", _fTmp[1]); + emit2 ("ld %s,a", _fTmp[1]); fDidXor = TRUE; } - if (!fDidXor) - CLRC; - } - else - { - CLRC; } while (size--) { /* Do a long subtract */ if (!sign || size) { - MOVA (aopGet (AOP (left), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); } if (sign && size == 0) { - emitcode ("ld", "a,%s", _fTmp[0]); - emitcode ("sbc", "a,%s", _fTmp[1]); + emit2 ("ld a,%s", _fTmp[0]); + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]); } else { /* Subtract through, propagating the carry */ - emitcode ("sbc", "a,%s ; 2", aopGet (AOP (right), offset++, FALSE)); + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE)); } } } @@ -3247,19 +3509,19 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { if (lit == 0) { - emitcode ("ld", "a,%s", aopGet (AOP (left), offset, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE)); if (size > 1) { size--; offset++; while (size--) { - emitcode ("or", "a,%s", aopGet (AOP (left), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE)); } } else { - emitcode ("or", "a,a"); + emit2 ("or a,a"); } emit2 ("jp nz,!tlabel", lbl->key + 100); } @@ -3267,11 +3529,11 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { while (size--) { - emitcode ("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) - emitcode ("or", "a,a"); + emit2 ("or a,a"); else - emitcode ("cp", "a,%s", aopGet (AOP (right), offset, FALSE)); + emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE)); emit2 ("jp nz,!tlabel", lbl->key + 100); offset++; } @@ -3285,14 +3547,14 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { while (size--) { - MOVA (aopGet (AOP (left), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) && ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)) /* PENDING */ emit2 ("jp nz,!tlabel", lbl->key + 100); else { - emitcode ("cp", "%s ; 4", aopGet (AOP (right), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (right), offset, FALSE)); emit2 ("jp nz,!tlabel", lbl->key + 100); } offset++; @@ -3304,8 +3566,8 @@ gencjneshort (operand * left, operand * right, symbol * lbl) /* PENDING: is this required? */ while (size--) { - MOVA (aopGet (AOP (right), offset, FALSE)); - emitcode ("cp", "%s ; 5", aopGet (AOP (left), offset, FALSE)); + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (left), offset, FALSE)); emit2 ("!shortjp nz,!tlabel", lbl->key + 100); offset++; } @@ -3326,7 +3588,7 @@ gencjne (operand * left, operand * right, symbol * lbl) emit2 ("ld a,!one"); emit2 ("!shortjp !tlabel", tlbl->key + 100); emitLabel (lbl->key + 100); - emitcode ("xor", "a,a"); + emit2 ("xor a,a"); emitLabel (tlbl->key + 100); } @@ -3342,6 +3604,8 @@ genCmpEq (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); + emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic))); + /* Swap operands if it makes the operation easier. ie if: 1. Left is a literal. */ @@ -3359,7 +3623,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 { @@ -3389,7 +3653,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 a bit to either a literal or another bit"); } else { @@ -3460,14 +3724,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); } @@ -3497,14 +3761,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); } @@ -3574,15 +3838,6 @@ genAnd (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); -#ifdef DEBUG_TYPE - emitcode ("", "; Type res[%d] = l[%d]&r[%d]", - AOP_TYPE (result), - AOP_TYPE (left), AOP_TYPE (right)); - emitcode ("", "; 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)) @@ -3615,7 +3870,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; } @@ -3625,80 +3880,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--; - MOVA (aopGet (AOP (left), posbit >> 3, FALSE)); - // bit = left & 2^n - if (size) - { - wassert (0); - emitcode ("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); - emitcode ("setb", "c"); - } - while (sizel--) - { - if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L) - { - MOVA (aopGet (AOP (left), offset, FALSE)); - // byte == 2^n ? - if ((posbit = isLiteralBit (bytelit)) != 0) - { - wassert (0); - emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100); - } - else - { - if (bytelit != 0x0FFL) - emitcode ("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) - { - emitcode ("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; } @@ -3715,11 +3936,11 @@ genAnd (iCode * ic, iCode * ifx) else { if (bytelit == 0) - aopPut (AOP (result), zero, offset); + aopPut (AOP (result), "!zero", offset); else { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("and", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE)); aopPut (AOP (left), "a", offset); } @@ -3730,12 +3951,12 @@ 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 { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("and", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE)); aopPut (AOP (left), "a", offset); } @@ -3747,7 +3968,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 { @@ -3766,18 +3987,18 @@ genAnd (iCode * ic, iCode * ifx) } else if (bytelit == 0) { - aopPut (AOP (result), zero, offset); + aopPut (AOP (result), "!zero", offset); continue; } } // faster than result <- left, anl result,right // and better if result is SFR if (AOP_TYPE (left) == AOP_ACC) - emitcode ("and", "a,%s", aopGet (AOP (right), offset, FALSE)); + emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE)); else { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("and", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE)); } aopPut (AOP (result), "a", offset); @@ -3801,20 +4022,12 @@ 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 - emitcode ("", "; Type res[%d] = l[%d]&r[%d]", - AOP_TYPE (result), - AOP_TYPE (left), AOP_TYPE (right)); - emitcode ("", "; 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)) @@ -3847,15 +4060,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; } @@ -3870,8 +4107,8 @@ genOr (iCode * ic, iCode * ifx) continue; else { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("or", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); } @@ -3879,11 +4116,11 @@ genOr (iCode * ic, iCode * ifx) else { if (AOP_TYPE (left) == AOP_ACC) - emitcode ("or", "a,%s", aopGet (AOP (right), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE)); else { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("or", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); } @@ -3895,7 +4132,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++) @@ -3915,11 +4152,11 @@ genOr (iCode * ic, iCode * ifx) // faster than result <- left, anl result,right // and better if result is SFR if (AOP_TYPE (left) == AOP_ACC) - emitcode ("or", "a,%s", aopGet (AOP (right), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE)); else { - MOVA (aopGet (AOP (left), offset, FALSE)); - emitcode ("or", "a,%s", + _moveA (aopGet (AOP (left), offset, FALSE)); + emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE)); } aopPut (AOP (result), "a", offset); @@ -3981,15 +4218,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; } @@ -4004,20 +4265,22 @@ genXor (iCode * ic, iCode * ifx) continue; else { - MOVA (aopGet (AOP (right), offset, FALSE)); - emitcode ("xor", "a,%s", + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("xor a,%s", aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); + aopPut (AOP (result), "a", offset); } } else { if (AOP_TYPE (left) == AOP_ACC) - emitcode ("xor", "a,%s", aopGet (AOP (right), offset, FALSE)); + { + emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + } else { - MOVA (aopGet (AOP (right), offset, FALSE)); - emitcode ("xor", "a,%s", + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("xor a,%s", aopGet (AOP (left), offset, FALSE)); aopPut (AOP (result), "a", 0); } @@ -4029,7 +4292,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++) @@ -4048,14 +4311,15 @@ genXor (iCode * ic, iCode * ifx) } // faster than result <- left, anl result,right // and better if result is SFR - if (AOP_TYPE (left) == AOP_ACC) - emitcode ("xor", "a,%s", aopGet (AOP (right), offset, FALSE)); + if (AOP_TYPE (left) == AOP_ACC) + { + emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + } else { - MOVA (aopGet (AOP (right), offset, FALSE)); - emitcode ("xor", "a,%s", + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("xor a,%s", aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); } aopPut (AOP (result), "a", offset); } @@ -4073,11 +4337,11 @@ release: static void genInline (iCode * ic) { - char buffer[MAX_INLINEASM]; - char *bp = buffer; - char *bp1 = buffer; + char *buffer, *bp, *bp1; - inLine += (!options.asmpeep); + _G.lines.isInline += (!options.asmpeep); + + buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1); strcpy (buffer, IC_INLINE (ic)); /* emit each line as a code */ @@ -4086,7 +4350,7 @@ genInline (iCode * ic) if (*bp == '\n') { *bp++ = '\0'; - emitcode (bp1, ""); + emit2 (bp1); bp1 = bp; } else @@ -4096,7 +4360,7 @@ genInline (iCode * ic) bp++; *bp = '\0'; bp++; - emitcode (bp1, ""); + emit2 (bp1); bp1 = bp; } else @@ -4104,9 +4368,9 @@ genInline (iCode * ic) } } if (bp1 != bp) - emitcode (bp1, ""); - /* emitcode("",buffer); */ - inLine -= (!options.asmpeep); + emit2 (bp1); + _G.lines.isInline -= (!options.asmpeep); + } /*-----------------------------------------------------------------*/ @@ -4127,53 +4391,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"); + /* PENDING: For re-target. */ + emit2 ("and a,#1"); + 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; - 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); - emitcode ("or", "a,a"); - offset = size; - while (size--) - { - l = aopGet (AOP (result), --offset, FALSE); - emitcode ("rr", "%s", l); - } - if (shCount > 1) - { - emitLabel (tlbl1->key + 100); - emitcode ("dec", "a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - } + emitLabel (tlbl1->key + 100); + emit2 ("dec a"); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); } } @@ -4201,7 +4509,7 @@ shiftL2Left2Result (operand * left, int offl, int size = 2; int offset = 0; symbol *tlbl, *tlbl1; - char *l; + const char *l; tlbl = newiTempLabel (NULL); tlbl1 = newiTempLabel (NULL); @@ -4214,16 +4522,25 @@ shiftL2Left2Result (operand * left, int offl, emitLabel (tlbl->key + 100); } - emitcode ("or", "a,a"); while (size--) { - l = aopGet (AOP (result), offset++, FALSE); - emitcode ("rl", "%s", l); + 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); - emitcode ("dec", "a"); + emit2 ("dec a"); emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); } } @@ -4242,34 +4559,34 @@ AccRol (int shCount) case 0: break; case 1: - emitcode ("rl", "a"); + emit2 ("sla a"); break; case 2: - emitcode ("rl", "a"); - emitcode ("rl", "a"); + emit2 ("sla a"); + emit2 ("rl a"); break; case 3: - emitcode ("rl", "a"); - emitcode ("rl", "a"); - emitcode ("rl", "a"); + emit2 ("sla a"); + emit2 ("rl a"); + emit2 ("rl a"); break; case 4: - emitcode ("rl", "a"); - emitcode ("rl", "a"); - emitcode ("rl", "a"); - emitcode ("rl", "a"); + emit2 ("sla a"); + emit2 ("rl a"); + emit2 ("rl a"); + emit2 ("rl a"); break; case 5: - emitcode ("rr", "a"); - emitcode ("rr", "a"); - emitcode ("rr", "a"); + emit2 ("srl a"); + emit2 ("rr a"); + emit2 ("rr a"); break; case 6: - emitcode ("rr", "a"); - emitcode ("rr", "a"); + emit2 ("srl a"); + emit2 ("rr a"); break; case 7: - emitcode ("rr", "a"); + emit2 ("srl a"); break; } } @@ -4280,16 +4597,21 @@ AccRol (int shCount) static void AccLsh (int shCount) { + static const unsigned char SLMask[] = + { + 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00 + }; + if (shCount != 0) { if (shCount == 1) { - emitcode ("add", "a,a"); + emit2 ("add a,a"); } else if (shCount == 2) { - emitcode ("add", "a,a"); - emitcode ("add", "a,a"); + emit2 ("add a,a"); + emit2 ("add a,a"); } else { @@ -4308,9 +4630,9 @@ static void shiftL1Left2Result (operand * left, int offl, operand * result, int offr, int shCount) { - char *l; + const char *l; l = aopGet (AOP (left), offl, FALSE); - MOVA (l); + _moveA (l); /* shift left accumulator */ AccLsh (shCount); aopPut (AOP (result), "a", offr); @@ -4336,18 +4658,18 @@ genlshTwo (operand * result, operand * left, int shCount) if (shCount) { movLeft2Result (left, LSB, result, MSB16, 0); - aopPut (AOP (result), zero, 0); - shiftL1Left2Result (left, MSB16, result, MSB16, shCount); + aopPut (AOP (result), "!zero", 0); + shiftL1Left2Result (left, LSB, result, MSB16, shCount); } else { movLeft2Result (left, LSB, result, MSB16, 0); - aopPut (AOP (result), zero, 0); + aopPut (AOP (result), "!zero", 0); } } else { - aopPut (AOP (result), zero, LSB); + aopPut (AOP (result), "!zero", LSB); } } /* 1 <= shCount <= 7 */ @@ -4392,20 +4714,19 @@ genLeftShiftLiteral (operand * left, size = getSize (operandType (result)); -#if VIEW_SIZE - emitcode ("; shift left ", "result %d, left %d", size, - AOP_SIZE (left)); -#endif - /* I suppose that the left size >= result size */ if (shCount == 0) { wassert (0); } - else if (shCount >= (size * 8)) - while (size--) - aopPut (AOP (result), zero, size); + else if (shCount >= (size * 8)) + { + while (size--) + { + aopPut (AOP (result), "!zero", size); + } + } else { switch (size) @@ -4417,7 +4738,7 @@ genLeftShiftLiteral (operand * left, genlshTwo (result, left, shCount); break; case 4: - wassert (0); + wassertl (0, "Shifting of longs is currently unsupported"); break; default: wassert (0); @@ -4434,7 +4755,7 @@ static void genLeftShift (iCode * ic) { int size, offset; - char *l; + const char *l; symbol *tlbl, *tlbl1; operand *left, *right, *result; @@ -4456,15 +4777,15 @@ genLeftShift (iCode * ic) count in B : Note: we take only the lower order byte since shifting more that 32 bits make no sense anyway, ( the largest size of an object can be only 32 bits ) */ - emitcode ("ld", "a,%s", aopGet (AOP (right), 0, FALSE)); - emitcode ("inc", "a"); + 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); /* now move the left to the result if they are not the same */ -#if 1 + if (!sameRegs (AOP (left), AOP (result))) { @@ -4477,17 +4798,6 @@ 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); @@ -4497,14 +4807,23 @@ genLeftShift (iCode * ic) emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); l = aopGet (AOP (result), offset, FALSE); - emitcode ("or", "a,a"); + while (size--) { - l = aopGet (AOP (result), offset++, FALSE); - emitcode ("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); - emitcode ("dec", "a"); + emit2 ("dec a"); emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); freeAsmop (left, NULL, ic); @@ -4515,29 +4834,32 @@ 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); - char *l; + const char *l; wassert (size == 1); 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--) - emitcode ("srl", "%s", l); + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } } else { - MOVA (l); + _moveA (l); while (shCount--) { - emitcode ("srl", "a"); + emit2 ("%s a", is_signed ? "sra" : "srl"); } aopPut (AOP (result), "a", 0); } @@ -4549,6 +4871,11 @@ genrshOne (operand * result, operand * left, int shCount) static void AccRsh (int shCount) { + static const unsigned char SRMask[] = + { + 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00 + }; + if (shCount != 0) { /* rotate right accumulator */ @@ -4566,10 +4893,13 @@ shiftR1Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign) { - MOVA (aopGet (AOP (left), offl, FALSE)); + _moveA (aopGet (AOP (left), offl, FALSE)); if (sign) { - wassert (0); + while (shCount--) + { + emit2 ("%s a", sign ? "sra" : "srl"); + } } else { @@ -4598,7 +4928,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 @@ -4614,7 +4956,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; @@ -4626,9 +4969,6 @@ genRightShiftLiteral (operand * left, size = getSize (operandType (result)); - emitcode ("; shift right ", "result %d, left %d", size, - AOP_SIZE (left)); - /* I suppose that the left size >= result size */ if (shCount == 0) { @@ -4637,23 +4977,22 @@ genRightShiftLiteral (operand * left, else if (shCount >= (size * 8)) while (size--) - aopPut (AOP (result), zero, size); + aopPut (AOP (result), "!zero", 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); @@ -4669,7 +5008,7 @@ genRightShift (iCode * ic) operand *right, *left, *result; sym_link *retype; int size, offset, first = 1; - char *l; + const char *l; bool is_signed; symbol *tlbl, *tlbl1; @@ -4697,7 +5036,7 @@ 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; } @@ -4720,8 +5059,8 @@ genRightShift (iCode * ic) } } - emitcode ("ld", "a,%s", aopGet (AOP (right), 0, FALSE)); - emitcode ("inc", "a"); + emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); + emit2 ("inc a"); freeAsmop (right, NULL, ic); tlbl = newiTempLabel (NULL); @@ -4736,17 +5075,16 @@ genRightShift (iCode * ic) l = aopGet (AOP (result), offset--, FALSE); if (first) { - if (is_signed) - emitcode ("sra", "%s", l); - else - emitcode ("srl", "%s", l); + emit2 ("%s %s", is_signed ? "sra" : "srl", l); first = 0; } else - emitcode ("rr", "%s", l); + { + emit2 ("rr %s", l); + } } emitLabel (tlbl1->key + 100); - emitcode ("dec", "a"); + emit2 ("dec a"); emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); freeAsmop (left, NULL, ic); @@ -4877,7 +5215,7 @@ genGenPointerSet (operand * right, if (isPair (AOP (result)) && (AOP_SIZE (right) == 1)) { /* Just do it */ - char *l = aopGet (AOP (right), 0, FALSE); + const char *l = aopGet (AOP (right), 0, FALSE); const char *pair = getPairName (AOP (result)); if (canAssignToPtr (l) && isPtr (pair)) { @@ -4885,7 +5223,7 @@ genGenPointerSet (operand * right, } else { - MOVA (l); + _moveA (l); emit2 ("ld !*pair,a", pair); } goto release; @@ -4912,19 +5250,19 @@ genGenPointerSet (operand * right, while (size--) { - char *l = aopGet (AOP (right), offset, FALSE); + const char *l = aopGet (AOP (right), offset, FALSE); if (isRegOrLit (AOP (right)) && !IS_GB) { emit2 ("ld !*pair,%s", _pairs[pairId].name, l); } else { - MOVA (l); + _moveA (l); emit2 ("ld !*pair,a", _pairs[pairId].name); } if (size) { - emitcode ("inc", _pairs[pairId].name); + emit2 ("inc %s", _pairs[pairId].name); _G.pairs[pairId].offset++; } offset++; @@ -4967,7 +5305,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 */ @@ -5015,8 +5353,8 @@ genAddrOf (iCode * ic) { emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset); } - emitcode ("ld", "d,h"); - emitcode ("ld", "e,l"); + emit2 ("ld d,h"); + emit2 ("ld e,l"); } else { @@ -5032,14 +5370,14 @@ genAddrOf (iCode * ic) { /* if it has an offset then we need to compute it */ if (sym->stack > 0) - emitcode ("ld", "hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset); + emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset); else - emitcode ("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset); - emitcode ("add", "hl,sp"); + emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset); + emit2 ("add hl,sp"); } else { - emitcode ("ld", "hl,#%s", sym->rname); + emit2 ("ld hl,#%s", sym->rname); } aopPut (AOP (IC_RESULT (ic)), "l", 0); aopPut (AOP (IC_RESULT (ic)), "h", 1); @@ -5060,14 +5398,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))) { - emitcode ("", "; (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); @@ -5075,14 +5411,14 @@ genAssign (iCode * ic) /* if they are the same registers */ if (sameRegs (AOP (right), AOP (result))) { - emitcode ("", "; (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 */ @@ -5112,7 +5448,7 @@ genAssign (iCode * ic) { if (!fXored && size > 1) { - emitcode ("xor", "a,a"); + emit2 ("xor a,a"); fXored = TRUE; } if (fXored) @@ -5121,7 +5457,7 @@ genAssign (iCode * ic) } else { - aopPut (AOP (result), zero, offset); + aopPut (AOP (result), "!zero", offset); } } else @@ -5134,11 +5470,33 @@ genAssign (iCode * ic) else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB) { /* Special case. Load into a and d, then load out. */ - MOVA (aopGet (AOP (right), 0, FALSE)); - emitcode ("ld", "e,%s", aopGet (AOP (right), 1, FALSE)); + _moveA (aopGet (AOP (right), 0, FALSE)); + emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE)); 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--) @@ -5146,7 +5504,7 @@ genAssign (iCode * ic) /* PENDING: do this check better */ if (requiresHL (AOP (right)) && requiresHL (AOP (result))) { - MOVA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); } else @@ -5169,24 +5527,24 @@ static void genJumpTab (iCode * ic) { symbol *jtab; - char *l; + const char *l; aopOp (IC_JTCOND (ic), ic, FALSE, FALSE); /* get the condition into accumulator */ l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE); if (!IS_GB) - emitcode ("push", "de"); - emitcode ("ld", "e,%s", l); + emit2 ("push de"); + emit2 ("ld e,%s", l); emit2 ("ld d,!zero"); jtab = newiTempLabel (NULL); spillCached (); emit2 ("ld hl,!immed!tlabel", jtab->key + 100); - emitcode ("add", "hl,de"); - emitcode ("add", "hl,de"); - emitcode ("add", "hl,de"); + emit2 ("add hl,de"); + emit2 ("add hl,de"); + emit2 ("add hl,de"); freeAsmop (IC_JTCOND (ic), NULL, ic); if (!IS_GB) - emitcode ("pop", "de"); + emit2 ("pop de"); emit2 ("jp !*hl"); emitLabel (jtab->key + 100); /* now generate the jump labels */ @@ -5216,7 +5574,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 */ @@ -5240,16 +5598,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); @@ -5268,17 +5617,16 @@ genCast (iCode * ic) if (SPEC_USIGN (ctype) || !IS_SPEC (ctype)) { while (size--) - aopPut (AOP (result), zero, offset++); + aopPut (AOP (result), "!zero", offset++); } else { /* we need to extend the sign :{ */ - char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, + const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE); - MOVA (l); - emitcode ("", "; genCast: sign extend untested."); - emitcode ("rla", ""); - emitcode ("sbc", "a,a"); + _moveA (l); + emit2 ("rla "); + emit2 ("sbc a,a"); while (size--) aopPut (AOP (result), "a", offset++); } @@ -5302,15 +5650,261 @@ genReceive (iCode * ic) } else { - accInUse++; - aopOp (IC_RESULT (ic), ic, FALSE, FALSE); - accInUse--; - assignResultValue (IC_RESULT (ic)); + // PENDING: HACK + int size; + int i; + + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + size = AOP_SIZE(IC_RESULT(ic)); + + for (i = 0; i < size; i++) { + aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i); + } } freeAsmop (IC_RESULT (ic), 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, int 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 -%u,0x%02X", 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 -%u,0x%02X", 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); + + if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) + { + /* Emit the support function call and the destination address. */ + emit2("call __initrleblock"); + emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0)); + } + else + { + wassertl (0, "Unexpected operand to genArrayInit.\n"); + } + + type = operandType(IC_LEFT(ic)); + + if (type && type->next) + { + elementSize = getSize(type->next); + } + else + { + wassertl (0, "Can't determine 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; + + if (ix != 0) + { + 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"); + + freeAsmop (IC_LEFT(ic), NULL, ic); +} + /*-----------------------------------------------------------------*/ /* genZ80Code - generate code for Z80 based controllers */ /*-----------------------------------------------------------------*/ @@ -5331,39 +5925,15 @@ genZ80Code (iCode * lic) _fReturn = _z80_return; _fTmp = _z80_return; } - tsprintf (zero, "!zero"); - - lineHead = lineCurr = NULL; - - /* if debug information required */ - if (options.debug && currFunc) - { - cdbSymbol (currFunc, cdbFile, FALSE, TRUE); - debugLine = 1; - if (IS_STATIC (currFunc->etype)) - emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name); - else - emitcode ("", "G$%s$0$0 ==.", currFunc->name); - debugLine = 0; - } - /* stack pointer name */ - spname = "sp"; + _G.lines.head = _G.lines.current = NULL; for (ic = lic; ic; ic = ic->next) { if (cln != ic->lineno) { - if (options.debug) - { - debugLine = 1; - emitcode ("", "C$%s$%d$%d$%d ==.", - FileBaseName (ic->filename), ic->lineno, - ic->level, ic->block); - debugLine = 0; - } - emitcode (";", "%s %d", ic->filename, ic->lineno); + emit2 ("; %s %d", ic->filename, ic->lineno); cln = ic->lineno; } /* if the result is marked as @@ -5377,22 +5947,22 @@ genZ80Code (iCode * lic) switch (ic->op) { case '!': - emitcode ("", "; genNot"); + emitDebug ("; genNot"); genNot (ic); break; case '~': - emitcode ("", "; genCpl"); + emitDebug ("; genCpl"); genCpl (ic); break; case UNARYMINUS: - emitcode ("", "; genUminus"); + emitDebug ("; genUminus"); genUminus (ic); break; case IPUSH: - emitcode ("", "; genIpush"); + emitDebug ("; genIpush"); genIpush (ic); break; @@ -5407,83 +5977,83 @@ genZ80Code (iCode * lic) ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) { - emitcode ("", "; genIfx"); + emitDebug ("; genIfx"); genIfx (ic->next, ic); } else { - emitcode ("", "; genIpop"); + emitDebug ("; genIpop"); genIpop (ic); } break; case CALL: - emitcode ("", "; genCall"); + emitDebug ("; genCall"); genCall (ic); break; case PCALL: - emitcode ("", "; genPcall"); + emitDebug ("; genPcall"); genPcall (ic); break; case FUNCTION: - emitcode ("", "; genFunction"); + emitDebug ("; genFunction"); genFunction (ic); break; case ENDFUNCTION: - emitcode ("", "; genEndFunction"); + emitDebug ("; genEndFunction"); genEndFunction (ic); break; case RETURN: - emitcode ("", "; genRet"); + emitDebug ("; genRet"); genRet (ic); break; case LABEL: - emitcode ("", "; genLabel"); + emitDebug ("; genLabel"); genLabel (ic); break; case GOTO: - emitcode ("", "; genGoto"); + emitDebug ("; genGoto"); genGoto (ic); break; case '+': - emitcode ("", "; genPlus"); + emitDebug ("; genPlus"); genPlus (ic); break; case '-': - emitcode ("", "; genMinus"); + emitDebug ("; genMinus"); genMinus (ic); break; case '*': - emitcode ("", "; genMult"); + emitDebug ("; genMult"); genMult (ic); break; case '/': - emitcode ("", "; genDiv"); + emitDebug ("; genDiv"); genDiv (ic); break; case '%': - emitcode ("", "; genMod"); + emitDebug ("; genMod"); genMod (ic); break; case '>': - emitcode ("", "; genCmpGt"); + emitDebug ("; genCmpGt"); genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '<': - emitcode ("", "; genCmpLt"); + emitDebug ("; genCmpLt"); genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); break; @@ -5498,66 +6068,67 @@ genZ80Code (iCode * lic) break; case EQ_OP: - emitcode ("", "; genCmpEq"); + emitDebug ("; genCmpEq"); genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); break; case AND_OP: - emitcode ("", "; genAndOp"); + emitDebug ("; genAndOp"); genAndOp (ic); break; case OR_OP: - emitcode ("", "; genOrOp"); + emitDebug ("; genOrOp"); genOrOp (ic); break; case '^': - emitcode ("", "; genXor"); + emitDebug ("; genXor"); genXor (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '|': - emitcode ("", "; genOr"); + emitDebug ("; genOr"); genOr (ic, ifxForOp (IC_RESULT (ic), ic)); break; case BITWISEAND: - emitcode ("", "; genAnd"); + emitDebug ("; genAnd"); genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); break; case INLINEASM: - emitcode ("", "; genInline"); + emitDebug ("; genInline"); genInline (ic); break; case RRC: - emitcode ("", "; genRRC"); + emitDebug ("; genRRC"); genRRC (ic); break; case RLC: - emitcode ("", "; genRLC"); + emitDebug ("; genRLC"); genRLC (ic); break; case GETHBIT: - emitcode ("", "; genHBIT"); - wassert (0); + emitDebug ("; genGetHBIT"); + genGetHbit (ic); + break; case LEFT_OP: - emitcode ("", "; genLeftShift"); + emitDebug ("; genLeftShift"); genLeftShift (ic); break; case RIGHT_OP: - emitcode ("", "; genRightShift"); + emitDebug ("; genRightShift"); genRightShift (ic); break; case GET_VALUE_AT_ADDRESS: - emitcode ("", "; genPointerGet"); + emitDebug ("; genPointerGet"); genPointerGet (ic); break; @@ -5565,50 +6136,52 @@ genZ80Code (iCode * lic) if (POINTER_SET (ic)) { - emitcode ("", "; genAssign (pointer)"); + emitDebug ("; genAssign (pointer)"); genPointerSet (ic); } else { - emitcode ("", "; genAssign"); + emitDebug ("; genAssign"); genAssign (ic); } break; case IFX: - emitcode ("", "; genIfx"); + emitDebug ("; genIfx"); genIfx (ic, NULL); break; case ADDRESS_OF: - emitcode ("", "; genAddrOf"); + emitDebug ("; genAddrOf"); genAddrOf (ic); break; case JUMPTABLE: - emitcode ("", "; genJumpTab"); + emitDebug ("; genJumpTab"); genJumpTab (ic); break; case CAST: - emitcode ("", "; genCast"); + emitDebug ("; genCast"); genCast (ic); break; case RECEIVE: - emitcode ("", "; genReceive"); + emitDebug ("; genReceive"); genReceive (ic); break; case SEND: - emitcode ("", "; addSet"); - addSet (&sendSet, ic); + emitDebug ("; addSet"); + addSet (&_G.sendSet, ic); break; + case ARRAYINIT: + genArrayInit(ic); + break; + default: ic = ic; - /* piCode(ic,stdout); */ - } } @@ -5616,7 +6189,7 @@ genZ80Code (iCode * lic) /* now we are ready to call the peep hole optimizer */ if (!options.nopeep) - peepHole (&lineHead); + peepHole (&_G.lines.head); /* This is unfortunate */ /* now do the actual printing */ @@ -5624,12 +6197,56 @@ genZ80Code (iCode * lic) FILE *fp = codeOutFile; if (isInHome () && codeOutFile == code->oFile) codeOutFile = home->oFile; - printLine (lineHead, codeOutFile); - if (_G.flush_statics) + printLine (_G.lines.head, codeOutFile); + if (_G.flushStatics) { flushStatics (); - _G.flush_statics = 0; + _G.flushStatics = 0; } codeOutFile = fp; } } + +/* + Attic +static int +_isPairUsed (iCode * ic, PAIR_ID pairId) +{ + int ret = 0; + switch (pairId) + { + case PAIR_DE: + if (bitVectBitValue (ic->rMask, D_IDX)) + ret++; + if (bitVectBitValue (ic->rMask, E_IDX)) + ret++; + break; + default: + wassert (0); + } + 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, "!immedword", v); + return gc_strdup (buffer); +} + + +*/