X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=6f033efe1c4b090a37c011b3f64911f5eec8f23e;hb=00f3243b4043482746e524b2527f6dcd1a202b9e;hp=ffef364818ec9c0c860d9fd2d5943f6694de1c8e;hpb=2ee35049f829fc523bab32504f31cfdef6745757;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index ffef3648..6f033efe 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 @@ -81,6 +116,11 @@ IX is used as an index register to the top of the local variable area. ix-0 is the top most local variable. */ + +enum { + DISABLE_DEBUG = 0 +}; + static char *_z80_return[] = {"l", "h", "e", "d"}; static char *_gbz80_return[] = @@ -201,12 +241,9 @@ _tidyUp (char *buf) } static void -emit2 (const char *szFormat,...) +_vemit2 (const char *szFormat, va_list ap) { char buffer[256]; - va_list ap; - - va_start (ap, szFormat); tvsprintf (buffer, szFormat, ap); @@ -218,6 +255,33 @@ emit2 (const char *szFormat,...) _G.lines.current->isInline = _G.lines.isInline; } +static void +emit2 (const char *szFormat,...) +{ + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); +} + +static void +emitDebug (const char *szFormat,...) +{ + if (!DISABLE_DEBUG) + { + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); + } +} + /*-----------------------------------------------------------------*/ /* emit2 - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ @@ -418,7 +482,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* Assign depending on the storage class */ if (sym->onStack || sym->iaccess) { - emit2 ("; 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; @@ -443,7 +507,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); - emit2 ("; AOP_SFR for %s", sym->rname); + emitDebug ("; AOP_SFR for %s", sym->rname); return aop; } } @@ -452,7 +516,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* in which case DPTR gets the address */ if (IS_GB) { - emit2 ("; AOP_HL for %s", sym->rname); + emitDebug ("; AOP_HL for %s", sym->rname); sym->aop = aop = newAsmop (AOP_HL); } else @@ -794,10 +858,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) { @@ -809,9 +869,9 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset); else tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + + return gc_strdup(s); + case AOP_LIT: { value *val = aop->aopu.aop_lit; @@ -822,14 +882,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 { @@ -938,7 +1008,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) { const char *l; const char *pair = _pairs[pairId].name; - l = aopGetLitWordLong (left, 0, FALSE); + l = aopGetLitWordLong (left, offset, FALSE); wassert (l && pair); if (isPtr (pair)) @@ -980,10 +1050,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) _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 @@ -1008,7 +1075,7 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) emit2 ("ld l,a"); break; default: - emit2 ("; WARNING: mlh woosed out. This code is invalid."); + emitDebug ("; WARNING: mlh woosed out. This code is invalid."); } } else if (IS_Z80 && aop->type == AOP_IY) { @@ -1136,14 +1203,14 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_DIR: wassert (IS_GB); - emit2 ("ld a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); return gc_strdup(s); case AOP_SFR: wassert (IS_GB); - emit2 ("ldh a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); return gc_strdup(s); @@ -1175,7 +1242,7 @@ 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); } return gc_strdup(s); @@ -1375,7 +1442,7 @@ aopPut (asmop * aop, const char *s, int offset) if (offset > 0) { - emit2 ("; Error aopPut AOP_ACC"); + emitDebug ("; Error aopPut AOP_ACC"); } else { @@ -1486,7 +1553,7 @@ outBitCLong (operand * result, bool swap_sense) /* if the result is bit */ if (AOP_TYPE (result) == AOP_CRY) { - emit2 ("; Note: outBitC form 1"); + emitDebug ("; Note: outBitC form 1"); aopPut (AOP (result), "blah", 0); } else @@ -1509,7 +1576,7 @@ outBitC (operand * result) /* toBoolean - emit code for orl a,operator(sizeop) */ /*-----------------------------------------------------------------*/ void -toBoolean (operand * oper) +_toBoolean (operand * oper) { int size = AOP_SIZE (oper); int offset = 0; @@ -1554,7 +1621,7 @@ genNot (iCode * ic) wassert (0); } - toBoolean (IC_LEFT (ic)); + _toBoolean (IC_LEFT (ic)); /* Not of A: If A == 0, !A = 1 @@ -1764,7 +1831,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize) deSending = (sendSetSize > 1); - emit2 ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); + emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); if (bcInUse && bcInRet == FALSE) { _push(PAIR_BC); @@ -1796,42 +1863,6 @@ genIpush (iCode * ic) if (!ic->parmPush) { wassertl(0, "Encountered an unsupported spill push."); -#if 0 - /* and the item is spilt then do nothing */ - if (OP_SYMBOL (IC_LEFT (ic))->isspilt) - return; - - aopOp (IC_LEFT (ic), ic, FALSE, FALSE); - size = AOP_SIZE (IC_LEFT (ic)); - /* push it on the stack */ - if (isPair (AOP (IC_LEFT (ic)))) - { - emit2 ("push %s", getPairName (AOP (IC_LEFT (ic)))); - _G.stack.pushed += 2; - } - else - { - offset = size; - while (size--) - { - /* Simple for now - load into A and PUSH AF */ - if (AOP (IC_LEFT (ic))->type == AOP_IY) - { - char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE); - wassert (l); - emit2 ("ld a,(%s)", l); - } - else - { - l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE); - emit2 ("ld a,%s", l); - } - emit2 ("push af"); - emit2 ("inc sp"); - _G.stack.pushed++; - } - } -#endif return; } @@ -1998,7 +2029,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) { if (pairId == PAIR_DE) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "e")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "d")) @@ -2006,7 +2037,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) } else if (pairId == PAIR_BC) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "c")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "b")) @@ -2110,7 +2141,7 @@ emitCall (iCode * ic, bool ispcall) if (isLitWord (AOP (IC_LEFT (ic)))) { - emit2 ("; Special case where the pCall is to a constant"); + emitDebug ("; Special case where the pCall is to a constant"); emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE)); } else @@ -2291,15 +2322,6 @@ resultRemat (iCode * ic) extern set *publics; -/* Steps: - o Check genFunction - o Check emitCall and clean up - o Check genReturn - o Check return puller - - PENDING: Remove this. -*/ - /*-----------------------------------------------------------------*/ /* genFunction - generated code for function entry */ /*-----------------------------------------------------------------*/ @@ -2338,6 +2360,11 @@ genFunction (iCode * ic) 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 */ @@ -2452,6 +2479,12 @@ genEndFunction (iCode * ic) } #endif + if (options.profile) + { + emit2 ("!profileexit"); + } + + /* Both baned and non-banked just ret */ emit2 ("ret"); @@ -2562,7 +2595,7 @@ genPlusIncr (iCode * ic) if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) return FALSE; - emit2 ("; genPlusIncr"); + emitDebug ("; genPlusIncr"); icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); @@ -2634,7 +2667,9 @@ genPlusIncr (iCode * ic) if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) { while (icount--) - emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + { + emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + } return TRUE; } @@ -2713,7 +2748,7 @@ genPlus (iCode * ic) if (genPlusIncr (ic) == TRUE) goto release; - emit2 ("; genPlusIncr failed"); + emitDebug ("; Can't optimise plus by inc, falling back to the normal way"); size = getDataSize (IC_RESULT (ic)); @@ -2721,10 +2756,11 @@ genPlus (iCode * ic) if (isPair (AOP (IC_RESULT (ic)))) { char *left, *right; - left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE); right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE); - if (left && right) + + if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT && + left && right) { /* It's a pair */ /* PENDING: fix */ @@ -2806,7 +2842,7 @@ genPlus (iCode * ic) } else if (size == 4) { - emit2 ("; WARNING: This add is probably broken.\n"); + wassertl (0, "Hit bad case for add"); } } } @@ -2864,26 +2900,6 @@ genMinusDec (iCode * ic) size = getDataSize (IC_RESULT (ic)); -#if 0 - /* if increment 16 bits in register */ - if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && - (size > 1) && - (icount == 1)) - { - symbol *tlbl = newiTempLabel (NULL); - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE)); - emit2 ("jp np," LABEL_STR, tlbl->key + 100); - - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE)); - if (size == 4) - { - wassert (0); - } - emitLabel (tlbl->key + 100); - return TRUE; - } -#endif - /* if decrement 16 bits in register */ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && isPair (AOP (IC_RESULT (ic)))) @@ -2903,6 +2919,22 @@ genMinusDec (iCode * ic) return TRUE; } + /* if increment 16 bits in register */ + if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && + (size == 2)) + { + fetchPair (PAIR_HL, AOP (IC_RESULT (ic))); + + while (icount--) { + emit2 ("dec hl"); + } + aopPut (AOP (IC_RESULT (ic)), "l", LSB); + aopPut (AOP (IC_RESULT (ic)), "h", MSB16); + + 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) @@ -2998,7 +3030,7 @@ genMinus (iCode * ic) } else if (size == 4) { - emit2 ("; WARNING: This sub is probably broken.\n"); + emitDebug ("; WARNING: This sub is probably broken.\n"); } } } @@ -3307,7 +3339,7 @@ genCmp (operand * left, operand * right, else { /* Subtract through, propagating the carry */ - emit2 ("sbc a,%s ; 2", aopGet (AOP (right), offset++, FALSE)); + emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE)); } } } @@ -3437,7 +3469,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { while (size--) { - emit2 ("ld a,%s ; 2", aopGet (AOP (left), offset, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE)); if ((AOP_TYPE (right) == AOP_LIT) && lit == 0) emit2 ("or a,a"); else @@ -3462,7 +3494,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) emit2 ("jp nz,!tlabel", lbl->key + 100); else { - emit2 ("cp %s ; 4", aopGet (AOP (right), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (right), offset, FALSE)); emit2 ("jp nz,!tlabel", lbl->key + 100); } offset++; @@ -3475,7 +3507,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) while (size--) { _moveA (aopGet (AOP (right), offset, FALSE)); - emit2 ("cp %s ; 5", aopGet (AOP (left), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (left), offset, FALSE)); emit2 ("!shortjp nz,!tlabel", lbl->key + 100); offset++; } @@ -3512,7 +3544,7 @@ genCmpEq (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); - emit2("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic))); + emitDebug ("; genCmpEq: left %u, right %u, result %u\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. @@ -3637,9 +3669,9 @@ genAndOp (iCode * ic) 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); } @@ -3674,9 +3706,9 @@ genOrOp (iCode * ic) 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); } @@ -3747,10 +3779,10 @@ genAnd (iCode * ic, iCode * ifx) aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); #ifdef DEBUG_TYPE - emit2 ("; Type res[%d] = l[%d]&r[%d]", + emitDebug ("; Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", + emitDebug ("; Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); #endif @@ -3979,10 +4011,10 @@ genOr (iCode * ic, iCode * ifx) aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); #if 1 - emit2 ("; Type res[%d] = l[%d]&r[%d]", + emitDebug ("; Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", + emitDebug ("; Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); #endif @@ -4302,53 +4334,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 <= 2) { - wassert (0); + while (shCount--) + { + emitRsh2 (AOP (result), size, is_signed); + } } else { - /* if (AOP(result)->type == AOP_REG) { */ - int size = 2; - int offset = 0; - symbol *tlbl, *tlbl1; - const char *l; - - tlbl = newiTempLabel (NULL); - tlbl1 = newiTempLabel (NULL); + emit2 ("ld a,!immedbyte+1", shCount); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); + emitLabel (tlbl->key + 100); - /* Left is already in result - so now do the shift */ - if (shCount > 1) - { - emit2 ("ld a,!immedbyte+1", shCount); - emit2 ("!shortjp !tlabel", tlbl1->key + 100); - emitLabel (tlbl->key + 100); - } + emitRsh2 (AOP (result), size, is_signed); - emit2 ("or a,a"); - offset = size; - while (size--) - { - l = aopGet (AOP (result), --offset, FALSE); - emit2 ("rr %s", l); - } - if (shCount > 1) - { - emitLabel (tlbl1->key + 100); - emit2 ("dec a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - } + emitLabel (tlbl1->key + 100); + emit2 ("dec a"); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); } } @@ -4392,8 +4468,11 @@ shiftL2Left2Result (operand * left, int offl, emit2 ("or a,a"); while (size--) { - l = aopGet (AOP (result), offset++, FALSE); + l = aopGet (AOP (result), offset, FALSE); + emit2 ("rl %s", l); + + offset++; } if (shCount > 1) { @@ -4573,7 +4652,7 @@ genLeftShiftLiteral (operand * left, size = getSize (operandType (result)); #if VIEW_SIZE - emit2 ("; shift left result %d, left %d", size, + emitDebug ("; shift left result %d, left %d", size, AOP_SIZE (left)); #endif @@ -4681,7 +4760,9 @@ genLeftShift (iCode * ic) emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); l = aopGet (AOP (result), offset, FALSE); + emit2 ("or a,a"); + while (size--) { l = aopGet (AOP (result), offset++, FALSE); @@ -4699,7 +4780,7 @@ genLeftShift (iCode * ic) /* genrshOne - left shift two bytes by known amount != 0 */ /*-----------------------------------------------------------------*/ static void -genrshOne (operand * result, operand * left, int shCount) +genrshOne (operand * result, operand * left, int shCount, int is_signed) { /* Errk */ int size = AOP_SIZE (result); @@ -4709,19 +4790,24 @@ genrshOne (operand * result, operand * left, int shCount) wassert (shCount < 8); l = aopGet (AOP (left), 0, FALSE); + + emit2 ("or a,a"); + if (AOP (result)->type == AOP_REG) { aopPut (AOP (result), l, 0); l = aopGet (AOP (result), 0, FALSE); while (shCount--) - emit2 ("srl %s", l); + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } } else { _moveA (l); while (shCount--) { - emit2 ("srl a"); + emit2 ("%s a", is_signed ? "sra" : "srl"); } aopPut (AOP (result), "a", 0); } @@ -4803,7 +4889,8 @@ static void genRightShiftLiteral (operand * left, operand * right, operand * result, - iCode * ic) + iCode * ic, + int sign) { int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit); int size; @@ -4815,7 +4902,7 @@ genRightShiftLiteral (operand * left, size = getSize (operandType (result)); - emit2 ("; shift right result %d, left %d", size, + emitDebug ("; shift right result %d, left %d", size, AOP_SIZE (left)); /* I suppose that the left size >= result size */ @@ -4832,17 +4919,17 @@ genRightShiftLiteral (operand * left, switch (size) { case 1: - genrshOne (result, left, shCount); + genrshOne (result, left, shCount, sign); break; case 2: /* PENDING: sign support */ - genrshTwo (result, left, shCount, FALSE); + genrshTwo (result, left, shCount, sign); break; case 4: - wassert (0); + wassertl (0, "Asked to shift right a long which should be a function call"); break; default: - wassert (0); + wassertl (0, "Entered default case in right shift delegate"); } } freeAsmop (left, NULL, ic); @@ -4886,7 +4973,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; } @@ -4925,14 +5012,13 @@ genRightShift (iCode * ic) l = aopGet (AOP (result), offset--, FALSE); if (first) { - if (is_signed) - emit2 ("sra %s", l); - else - emit2 ("srl %s", l); + emit2 ("%s %s", is_signed ? "sra" : "srl", l); first = 0; } else - emit2 ("rr %s", l); + { + emit2 ("rr %s", l); + } } emitLabel (tlbl1->key + 100); emit2 ("dec a"); @@ -5156,7 +5242,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 */ @@ -5253,7 +5339,7 @@ genAssign (iCode * ic) /* Dont bother assigning if they are the same */ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) { - emit2 ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); + emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); return; } #endif @@ -5264,7 +5350,7 @@ genAssign (iCode * ic) /* if they are the same registers */ if (sameRegs (AOP (right), AOP (result))) { - emit2 ("; (registers are the same)"); + emitDebug ("; (registers are the same)"); goto release; } @@ -5465,7 +5551,7 @@ genCast (iCode * ic) const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE); _moveA (l); - emit2 ("; genCast: sign extend untested."); + emitDebug ("; genCast: sign extend untested."); emit2 ("rla "); emit2 ("sbc a,a"); while (size--) @@ -5506,6 +5592,246 @@ genReceive (iCode * ic) 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 */ /*-----------------------------------------------------------------*/ @@ -5548,22 +5874,22 @@ genZ80Code (iCode * lic) switch (ic->op) { case '!': - emit2 ("; genNot"); + emitDebug ("; genNot"); genNot (ic); break; case '~': - emit2 ("; genCpl"); + emitDebug ("; genCpl"); genCpl (ic); break; case UNARYMINUS: - emit2 ("; genUminus"); + emitDebug ("; genUminus"); genUminus (ic); break; case IPUSH: - emit2 ("; genIpush"); + emitDebug ("; genIpush"); genIpush (ic); break; @@ -5578,83 +5904,83 @@ genZ80Code (iCode * lic) ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) { - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic->next, ic); } else { - emit2 ("; genIpop"); + emitDebug ("; genIpop"); genIpop (ic); } break; case CALL: - emit2 ("; genCall"); + emitDebug ("; genCall"); genCall (ic); break; case PCALL: - emit2 ("; genPcall"); + emitDebug ("; genPcall"); genPcall (ic); break; case FUNCTION: - emit2 ("; genFunction"); + emitDebug ("; genFunction"); genFunction (ic); break; case ENDFUNCTION: - emit2 ("; genEndFunction"); + emitDebug ("; genEndFunction"); genEndFunction (ic); break; case RETURN: - emit2 ("; genRet"); + emitDebug ("; genRet"); genRet (ic); break; case LABEL: - emit2 ("; genLabel"); + emitDebug ("; genLabel"); genLabel (ic); break; case GOTO: - emit2 ("; genGoto"); + emitDebug ("; genGoto"); genGoto (ic); break; case '+': - emit2 ("; genPlus"); + emitDebug ("; genPlus"); genPlus (ic); break; case '-': - emit2 ("; genMinus"); + emitDebug ("; genMinus"); genMinus (ic); break; case '*': - emit2 ("; genMult"); + emitDebug ("; genMult"); genMult (ic); break; case '/': - emit2 ("; genDiv"); + emitDebug ("; genDiv"); genDiv (ic); break; case '%': - emit2 ("; genMod"); + emitDebug ("; genMod"); genMod (ic); break; case '>': - emit2 ("; genCmpGt"); + emitDebug ("; genCmpGt"); genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '<': - emit2 ("; genCmpLt"); + emitDebug ("; genCmpLt"); genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); break; @@ -5669,66 +5995,67 @@ genZ80Code (iCode * lic) break; case EQ_OP: - emit2 ("; genCmpEq"); + emitDebug ("; genCmpEq"); genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); break; case AND_OP: - emit2 ("; genAndOp"); + emitDebug ("; genAndOp"); genAndOp (ic); break; case OR_OP: - emit2 ("; genOrOp"); + emitDebug ("; genOrOp"); genOrOp (ic); break; case '^': - emit2 ("; genXor"); + emitDebug ("; genXor"); genXor (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '|': - emit2 ("; genOr"); + emitDebug ("; genOr"); genOr (ic, ifxForOp (IC_RESULT (ic), ic)); break; case BITWISEAND: - emit2 ("; genAnd"); + emitDebug ("; genAnd"); genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); break; case INLINEASM: - emit2 ("; genInline"); + emitDebug ("; genInline"); genInline (ic); break; case RRC: - emit2 ("; genRRC"); + emitDebug ("; genRRC"); genRRC (ic); break; case RLC: - emit2 ("; genRLC"); + emitDebug ("; genRLC"); genRLC (ic); break; case GETHBIT: - emit2 ("; genHBIT"); - wassert (0); + emitDebug ("; genGetHBIT"); + genGetHbit (ic); + break; case LEFT_OP: - emit2 ("; genLeftShift"); + emitDebug ("; genLeftShift"); genLeftShift (ic); break; case RIGHT_OP: - emit2 ("; genRightShift"); + emitDebug ("; genRightShift"); genRightShift (ic); break; case GET_VALUE_AT_ADDRESS: - emit2 ("; genPointerGet"); + emitDebug ("; genPointerGet"); genPointerGet (ic); break; @@ -5736,46 +6063,50 @@ genZ80Code (iCode * lic) if (POINTER_SET (ic)) { - emit2 ("; genAssign (pointer)"); + emitDebug ("; genAssign (pointer)"); genPointerSet (ic); } else { - emit2 ("; genAssign"); + emitDebug ("; genAssign"); genAssign (ic); } break; case IFX: - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic, NULL); break; case ADDRESS_OF: - emit2 ("; genAddrOf"); + emitDebug ("; genAddrOf"); genAddrOf (ic); break; case JUMPTABLE: - emit2 ("; genJumpTab"); + emitDebug ("; genJumpTab"); genJumpTab (ic); break; case CAST: - emit2 ("; genCast"); + emitDebug ("; genCast"); genCast (ic); break; case RECEIVE: - emit2 ("; genReceive"); + emitDebug ("; genReceive"); genReceive (ic); break; case SEND: - emit2 ("; addSet"); + emitDebug ("; addSet"); addSet (&_G.sendSet, ic); break; + case ARRAYINIT: + genArrayInit(ic); + break; + default: ic = ic; /* piCode(ic,stdout); */