X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=e9b3302b73642afb8922c51d0a4763b158635b14;hb=30357bade4ba51536bdf52d60db2a3c96251a1ff;hp=09e50849dd2fa59b94174340d7cbbbb9e57708ba;hpb=a6a4dace7d80a15bb86a12e4dc0a05a9beae9290;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 09e50849..e9b3302b 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -93,10 +93,6 @@ #define STRCASECMP strcasecmp #endif -#ifdef HAVE_SYS_ISA_DEFS_H -#include -#endif - #include "z80.h" #include "SDCCglobl.h" #include "SDCCpeeph.h" @@ -218,12 +214,15 @@ static struct int pushedDE; } calleeSaves; + bool omitFramePtr; int frameId; int receiveOffset; bool flushStatics; bool in_home; const char *lastFunctionName; - + iCode *current_iCode; + bool preserveCarry; + set *sendSet; struct @@ -237,6 +236,7 @@ static struct lineNode *head; lineNode *current; int isInline; + int isDebug; allocTrace trace; } lines; @@ -264,7 +264,8 @@ static const char *aopNames[] = { "AOP_HLREG", "AOP_SIMPLELIT", "AOP_EXSTK", - "AOP_PAIRPT" + "AOP_PAIRPT", + "AOP_DUMMY" }; static bool @@ -400,9 +401,9 @@ _newLineNode (char *line) static void _vemit2 (const char *szFormat, va_list ap) { - char buffer[256]; + char buffer[INITIAL_INLINEASM]; - tvsprintf (buffer, szFormat, ap); + tvsprintf (buffer, sizeof(buffer), szFormat, ap); _tidyUp (buffer); _G.lines.current = (_G.lines.current ? @@ -410,6 +411,8 @@ _vemit2 (const char *szFormat, va_list ap) (_G.lines.head = _newLineNode (buffer))); _G.lines.current->isInline = _G.lines.isInline; + _G.lines.current->isDebug = _G.lines.isDebug; + _G.lines.current->ic = _G.current_iCode; } static void @@ -430,11 +433,11 @@ emitDebug (const char *szFormat,...) if (!DISABLE_DEBUG) { va_list ap; - + va_start (ap, szFormat); - + _vemit2 (szFormat, ap); - + va_end (ap); } } @@ -469,6 +472,7 @@ _emit2 (const char *inst, const char *fmt,...) (_G.lines.head = _newLineNode (lb))); } _G.lines.current->isInline = _G.lines.isInline; + _G.lines.current->ic = _G.current_iCode; va_end (ap); } @@ -489,12 +493,26 @@ _emitMove(const char *to, const char *from) void aopDump(const char *plabel, asmop *aop) { + int i; + char regbuf[9]; + char *rbp = regbuf; + emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size); switch (aop->type) { + case AOP_EXSTK: case AOP_STK: emitDebug("; aop_stk %d", aop->aopu.aop_stk); break; + case AOP_REG: + for (i=aop->size-1;i>=0;i--) + *rbp++ = *(aop->aopu.aop_reg[i]->name); + *rbp = '\0'; + emitDebug("; reg = %s", regbuf); + break; + case AOP_PAIRPTR: + emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name); + default: /* No information. */ break; @@ -589,6 +607,22 @@ isPair (asmop * aop) return (getPairId (aop) != PAIR_INVALID); } +/** Returns TRUE if the registers used in aop cannot be split into high + and low halves */ +bool +isUnsplitable (asmop * aop) +{ + switch (getPairId (aop)) + { + case PAIR_IX: + case PAIR_IY: + return TRUE; + default: + return FALSE; + } + return FALSE; +} + bool isPtrPair (asmop * aop) { @@ -611,6 +645,30 @@ spillPair (PAIR_ID pairId) _G.pairs[pairId].base = NULL; } +/* Given a register name, spill the pair (if any) the register is part of */ +static void +spillPairReg (const char *regname) +{ + if (strlen(regname)==1) + { + switch (*regname) + { + case 'h': + case 'l': + spillPair(PAIR_HL); + break; + case 'd': + case 'e': + spillPair(PAIR_DE); + break; + case 'b': + case 'c': + spillPair(PAIR_BC); + break; + } + } +} + /** Push a register pair onto the stack */ void genPairPush (asmop * aop) @@ -633,6 +691,39 @@ _pop (PAIR_ID pairId) spillPair (pairId); } +void +genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair) +{ + switch (dstPair) + { + case PAIR_IX: + case PAIR_IY: + case PAIR_AF: + _push(srcPair); + _pop(dstPair); + break; + case PAIR_BC: + case PAIR_DE: + case PAIR_HL: + if (srcPair == PAIR_IX || srcPair == PAIR_IY) + { + _push(srcPair); + _pop(dstPair); + } + else + { + emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l); + emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h); + } + default: + wassertl (0, "Tried to move a nonphysical pair"); + } + _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type; + _G.pairs[dstPair].base = _G.pairs[srcPair].base; + _G.pairs[dstPair].offset = _G.pairs[srcPair].offset; +} + + /*-----------------------------------------------------------------*/ /* newAsmop - creates a new asmOp */ /*-----------------------------------------------------------------*/ @@ -674,7 +765,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) Normally everything is AOP_STK, but for offsets of < -128 or > 127 on the Z80 an extended stack pointer is used. */ - if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type)))) + if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type)))) { emitDebug ("; AOP_EXSTK for %s", sym->rname); sym->aop = aop = newAsmop (AOP_EXSTK); @@ -995,14 +1086,21 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } - /* else spill location */ - if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) { - /* force a new aop if sizes differ */ - sym->usl.spillLoc->aop = NULL; - } - sym->aop = op->aop = aop = - aopForSym (ic, sym->usl.spillLoc, result, requires_a); - wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location"); + if (sym->usl.spillLoc) + { + if (getSize(sym->type) != getSize(sym->usl.spillLoc->type)) + { + /* force a new aop if sizes differ */ + sym->usl.spillLoc->aop = NULL; + } + sym->aop = op->aop = aop = + aopForSym (ic, sym->usl.spillLoc, result, requires_a); + aop->size = getSize (sym->type); + return; + } + + /* else must be a dummy iTemp */ + sym->aop = op->aop = aop = newAsmop (AOP_DUMMY); aop->size = getSize (sym->type); return; } @@ -1079,8 +1177,6 @@ isLitWord (asmop * aop) char * aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { - char *s = buffer; - /* depending on type */ switch (aop->type) { @@ -1090,17 +1186,20 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) /* PENDING: for re-target */ if (with_hash) { - tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset); + tsprintf (buffer, sizeof(buffer), + "!hashedstr + %d", aop->aopu.aop_immd, offset); } else if (offset == 0) { - tsprintf (s, "%s", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), + "%s", aop->aopu.aop_immd); } else { - tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); + tsprintf (buffer, sizeof(buffer), + "%s + %d", aop->aopu.aop_immd, offset); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_LIT: { @@ -1125,9 +1224,9 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) } if (with_hash) - tsprintf (buffer, "!immedword", v); + tsprintf (buffer, sizeof(buffer), "!immedword", v); else - tsprintf (buffer, "!constword", v); + tsprintf (buffer, sizeof(buffer), "!constword", v); return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } @@ -1143,15 +1242,15 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) /* it is type float */ fl.f = (float) floatFromVal (val); -#ifdef _BIG_ENDIAN +#ifdef WORDS_BIGENDIAN i = fl.c[3-offset] | (fl.c[3-offset-1]<<8); #else i = fl.c[offset] | (fl.c[offset+1]<<8); #endif if (with_hash) - tsprintf (buffer, "!immedword", i); + tsprintf (buffer, sizeof(buffer), "!immedword", i); else - tsprintf (buffer, "!constword", i); + tsprintf (buffer, sizeof(buffer), "!constword", i); return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } @@ -1350,6 +1449,11 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset) _pop (id); } } + else if (isUnsplitable(aop)) + { + emit2("push %s", _pairs[getPairId(aop)].name); + emit2("pop %s", _pairs[pairId].name); + } else { emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE)); @@ -1378,6 +1482,12 @@ setupPairFromSP (PAIR_ID id, int offset) { wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL"); + if (_G.preserveCarry) + { + _push (PAIR_AF); + offset += 2; + } + if (offset < INT8MIN || offset > INT8MAX) { emit2 ("ld hl,!immedword", offset); @@ -1385,7 +1495,13 @@ setupPairFromSP (PAIR_ID id, int offset) } else { - emit2 ("!ldahlsp", offset); + emit2 ("!ldahlsp", offset); + } + + if (_G.preserveCarry) + { + _pop (PAIR_AF); + offset -= 2; } } @@ -1421,11 +1537,15 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset) else { /* PENDING: Do this better. */ + if (_G.preserveCarry) + _push (PAIR_AF); sprintf (buffer, "%d", offset + _G.stack.pushed); emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer); emit2 ("add %s,sp", _pairs[pairId].name); _G.pairs[pairId].last_type = aop->type; _G.pairs[pairId].offset = offset; + if (_G.preserveCarry) + _pop (PAIR_AF); } } break; @@ -1454,6 +1574,8 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset) } case AOP_PAIRPTR: + if (pairId != aop->aopu.aop_pairId) + genMovePairPair(aop->aopu.aop_pairId, pairId); adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset); break; @@ -1476,55 +1598,59 @@ emitLabel (int key) static const char * aopGet (asmop * aop, int offset, bool bit16) { - char *s = buffer; + // char *s = buffer; /* offset is greater than size then zero */ /* PENDING: this seems a bit screwed in some pointer cases. */ if (offset > (aop->size - 1) && aop->type != AOP_LIT) { - tsprintf (s, "!zero"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } /* depending on type */ switch (aop->type) { + case AOP_DUMMY: + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + case AOP_IMMD: /* PENDING: re-target */ if (bit16) - tsprintf (s, "!immedwords", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd); else switch (offset) { case 2: - tsprintf (s, "!bankimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd); break; case 1: - tsprintf (s, "!msbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd); break; case 0: - tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd); break; default: wassertl (0, "Fetching from beyond the limits of an immediate value."); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_DIR: wassert (IS_GB); emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + SNPRINTF (buffer, sizeof(buffer), "a"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_SFR: wassert (IS_GB); emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + SNPRINTF (buffer, sizeof(buffer), "a"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_REG: return aop->aopu.aop_reg[offset]->name; @@ -1532,38 +1658,39 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_HL: wassert (IS_GB); setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); - return traceAlloc(&_G.trace.aops, Safe_strdup (s)); + return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); case AOP_IY: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); - tsprintf (s, "!*iyx", offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_EXSTK: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); - tsprintf (s, "!*iyx", offset, offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_STK: if (IS_GB) { setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); } else { if (aop->aopu.aop_stk >= 0) offset += _G.stack.param_offset; - tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset); + tsprintf (buffer, sizeof(buffer), + "!*ixx", aop->aopu.aop_stk + offset); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_CRY: wassertl (0, "Tried to fetch from a bit variable"); @@ -1575,8 +1702,8 @@ aopGet (asmop * aop, int offset, bool bit16) } else { - tsprintf(s, "!zero"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + tsprintf(buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } case AOP_HLREG: @@ -1591,9 +1718,10 @@ aopGet (asmop * aop, int offset, bool bit16) unsigned long v = aop->aopu.aop_simplelit; v >>= (offset * 8); - tsprintf (s, "!immedbyte", (unsigned int) v & 0xff); + tsprintf (buffer, sizeof(buffer), + "!immedbyte", (unsigned int) v & 0xff); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } case AOP_STR: aop->coff = offset; @@ -1601,9 +1729,17 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_PAIRPTR: setupPair (aop->aopu.aop_pairId, aop, offset); - sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name); + if (aop->aopu.aop_pairId==PAIR_IX) + SNPRINTF (buffer, sizeof(buffer), + "!*ixx", 0); + else if (aop->aopu.aop_pairId==PAIR_IY) + SNPRINTF (buffer, sizeof(buffer), + "!*iyx", 0); + else + SNPRINTF (buffer, sizeof(buffer), + "(%s)", _pairs[aop->aopu.aop_pairId].name); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); default: break; @@ -1659,13 +1795,17 @@ aopPut (asmop * aop, const char *s, int offset) } // PENDING - tsprintf(buffer2, s); + tsprintf(buffer2, sizeof(buffer2), s); s = buffer2; /* will assign value to value */ /* depending on where it is ofcourse */ switch (aop->type) { + case AOP_DUMMY: + _moveA (s); /* in case s is volatile */ + break; + case AOP_DIR: /* Direct. Hmmm. */ wassert (IS_GB); @@ -1687,6 +1827,7 @@ aopPut (asmop * aop, const char *s, int offset) else emit2 ("ld %s,%s", aop->aopu.aop_reg[offset]->name, s); + spillPairReg(aop->aopu.aop_reg[offset]->name); break; case AOP_IY: @@ -1786,6 +1927,7 @@ aopPut (asmop * aop, const char *s, int offset) { emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); } + spillPairReg(aop->aopu.aop_str[offset]); break; case AOP_ACC: @@ -1799,18 +1941,27 @@ aopPut (asmop * aop, const char *s, int offset) else { if (strcmp (aop->aopu.aop_str[offset], s)) - emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + { + emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); + } } break; case AOP_HLREG: wassert (offset < 2); emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); break; case AOP_PAIRPTR: setupPair (aop->aopu.aop_pairId, aop, offset); - emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); + if (aop->aopu.aop_pairId==PAIR_IX) + emit2 ("ld !*ixx,%s", 0, s); + else if (aop->aopu.aop_pairId==PAIR_IY) + emit2 ("ld !*ixy,%s", 0, s); + else + emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); break; default: @@ -2012,43 +2163,6 @@ _toBoolean (operand * oper) } } -/*-----------------------------------------------------------------*/ -/* genNotFloat - generates not for float operations */ -/*-----------------------------------------------------------------*/ -static void -genNotFloat (operand * op, operand * res) -{ - int size, offset; - symbol *tlbl; - - emitDebug ("; genNotFloat"); - - /* we will put 127 in the first byte of - the result */ - aopPut (AOP (res), "!immedbyte", 0x7F); - size = AOP_SIZE (op) - 1; - offset = 1; - - _moveA (aopGet (op->aop, offset++, FALSE)); - - while (size--) - { - emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE)); - } - - tlbl = newiTempLabel (NULL); - aopPut (res->aop, "!one", 1); - emit2 ("!shortjp z !tlabel", tlbl->key + 100); - aopPut (res->aop, "!zero", 1); - - emitLabel(tlbl->key + 100); - - size = res->aop->size - 2; - offset = 2; - /* put zeros in the rest */ - while (size--) - aopPut (res->aop, "!zero", offset++); -} /*-----------------------------------------------------------------*/ /* genNot - generate code for ! operation */ @@ -2056,7 +2170,6 @@ genNotFloat (operand * op, operand * res) static void genNot (iCode * ic) { - sym_link *optype = operandType (IC_LEFT (ic)); /* assign asmOps to operand & result */ aopOp (IC_LEFT (ic), ic, FALSE, TRUE); @@ -2068,13 +2181,6 @@ genNot (iCode * ic) wassertl (0, "Tried to negate a bit"); } - /* if type float then do float */ - if (IS_FLOAT (optype)) - { - genNotFloat (IC_LEFT (ic), IC_RESULT (ic)); - goto release; - } - _toBoolean (IC_LEFT (ic)); /* Not of A: @@ -2084,7 +2190,6 @@ genNot (iCode * ic) emit2 ("sub a,!one"); outBitC (IC_RESULT (ic)); - release: /* release the aops */ freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -2356,7 +2461,8 @@ _saveRegsForCall(iCode *ic, int sendSetSize) bool bcInRet = FALSE, deInRet = FALSE; bitVect *rInUse; - rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), + z80_rUmaskForOp (IC_RESULT(ic))); deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX); bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX); @@ -2591,6 +2697,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) static void emitCall (iCode * ic, bool ispcall) { + bool bInRet, cInRet, dInRet, eInRet; sym_link *dtype = operandType (IC_LEFT (ic)); /* if caller saves & we have not saved then */ @@ -2759,12 +2866,24 @@ emitCall (iCode * ic, bool ispcall) } spillCached (); + if (IC_RESULT (ic)) + { + bitVect *result = z80_rUmaskForOp (IC_RESULT (ic)); + bInRet = bitVectBitValue(result, B_IDX); + cInRet = bitVectBitValue(result, C_IDX); + dInRet = bitVectBitValue(result, D_IDX); + eInRet = bitVectBitValue(result, E_IDX); + } + else + { + bInRet = FALSE; + cInRet = FALSE; + dInRet = FALSE; + eInRet = FALSE; + } if (_G.stack.pushedDE) { - bool dInRet = bitVectBitValue(ic->rUsed, D_IDX); - bool eInRet = bitVectBitValue(ic->rUsed, E_IDX); - if (dInRet && eInRet) { wassertl (0, "Shouldn't push DE if it's wiped out by the return"); @@ -2791,9 +2910,6 @@ emitCall (iCode * ic, bool ispcall) if (_G.stack.pushedBC) { - bool bInRet = bitVectBitValue(ic->rUsed, B_IDX); - bool cInRet = bitVectBitValue(ic->rUsed, C_IDX); - if (bInRet && cInRet) { wassertl (0, "Shouldn't push BC if it's wiped out by the return"); @@ -2864,6 +2980,8 @@ extern set *publics; static void genFunction (iCode * ic) { + bool stackParm; + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); sym_link *ftype; @@ -2958,8 +3076,29 @@ genFunction (iCode * ic) /* adjust the stack for the function */ _G.stack.last = sym->stack; - - if (sym->stack && IS_GB && sym->stack > -INT8MIN) + + stackParm = FALSE; + for (sym = setFirstItem (istack->syms); sym; + sym = setNextItem (istack->syms)) + { + if (sym->_isparm && !IS_REGPARM (sym->etype)) + { + stackParm = TRUE; + break; + } + } + sym = OP_SYMBOL (IC_LEFT (ic)); + + _G.omitFramePtr = options.ommitFramePtr; + if (IS_Z80 && !stackParm && !sym->stack) + { + /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */ + /* the above !sym->stack condition can be removed. -- EEP */ + if (sym->stack) + emit2 ("!ldaspsp", -sym->stack); + _G.omitFramePtr = TRUE; + } + else if (sym->stack && IS_GB && sym->stack > -INT8MIN) emit2 ("!enterxl", sym->stack); else if (sym->stack) emit2 ("!enterx", sym->stack); @@ -2987,7 +3126,12 @@ genEndFunction (iCode * ic) /* PENDING: calleeSave */ - if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX) + if (IS_Z80 && _G.omitFramePtr) + { + if (_G.stack.offset) + emit2 ("!ldaspsp", _G.stack.offset); + } + else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX) { emit2 ("!leavexl", _G.stack.offset); } @@ -3018,7 +3162,22 @@ genEndFunction (iCode * ic) } - /* Both baned and non-banked just ret */ + if (options.debug && currFunc) + { + _G.lines.isDebug = 1; + sprintf (buffer, "C$%s$%d$%d$%d", + FileBaseName (ic->filename), currFunc->lastLine, + ic->level, ic->block); + emit2 ("!labeldef", buffer); + if (IS_STATIC (currFunc->etype)) + sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name); + else + sprintf (buffer, "XG$%s$0$0", currFunc->name); + emit2 ("!labeldef", buffer); + _G.lines.isDebug = 0; + } + + /* Both banked and non-banked just ret */ emit2 ("ret"); sprintf (buffer, "%s_end", sym->rname); @@ -3050,6 +3209,9 @@ genRet (iCode * ic) aopOp (IC_LEFT (ic), ic, FALSE, FALSE); size = AOP_SIZE (IC_LEFT (ic)); + aopDump("IC_LEFT", AOP(IC_LEFT(ic))); + + #if 0 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0)))) { if (IS_GB) @@ -3061,6 +3223,11 @@ genRet (iCode * ic) emit2 ("ld hl,%s", l); } } + #endif + if (size==2) + { + fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic))); + } else { if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic)))) @@ -3075,7 +3242,8 @@ genRet (iCode * ic) l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); if (strcmp (_fReturn[offset], l)) - emit2 ("ld %s,%s", _fReturn[offset++], l); + emit2 ("ld %s,%s", _fReturn[offset], l); + offset++; } } } @@ -3324,11 +3492,16 @@ setupToPreserveCarry (asmop *result, asmop *left, asmop *right) if (couldDestroyCarry (right) && couldDestroyCarry (result)) { shiftIntoPair (0, right); - shiftIntoPair (1, result); + /* check result again, in case right == result */ + if (couldDestroyCarry (result)) + shiftIntoPair (1, result); } else if (couldDestroyCarry (right)) { - shiftIntoPair (0, right); + if (getPairId (result) == PAIR_HL) + _G.preserveCarry = TRUE; + else + shiftIntoPair (0, right); } else if (couldDestroyCarry (result)) { @@ -3530,7 +3703,7 @@ genPlus (iCode * ic) goto release; } } - + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); while (size--) @@ -3559,6 +3732,7 @@ genPlus (iCode * ic) } release: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -3762,6 +3936,7 @@ genMinus (iCode * ic) } release: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -5168,7 +5343,7 @@ genXor (iCode * ic, iCode * ifx) _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); } } } @@ -5469,6 +5644,7 @@ AccRol (int shCount) { shCount &= 0x0007; // shCount : 0..7 +#if 0 switch (shCount) { case 0: @@ -5504,6 +5680,43 @@ AccRol (int shCount) emit2 ("srl a"); break; } +#else + switch (shCount) + { + case 0: + break; + case 1: + emit2 ("rlca"); + break; + case 2: + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 3: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 4: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 5: + emit2 ("rrca"); + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 6: + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 7: + emit2 ("rrca"); + break; + } +#endif } /*-----------------------------------------------------------------*/ @@ -5890,9 +6103,19 @@ genRightShiftLiteral (operand * left, wassert (0); } - else if (shCount >= (size * 8)) + else if (shCount >= (size * 8)) { + const char *s; + if (!SPEC_USIGN(getSpec(operandType(left)))) { + _moveA(aopGet (AOP (left), 0, FALSE)); + emit2 ("rlc a"); + emit2 ("sbc a,a"); + s=ACC_NAME; + } else { + s="!zero"; + } while (size--) - aopPut (AOP (result), "!zero", size); + aopPut (AOP (result), s, size); + } else { switch (size) @@ -5955,13 +6178,16 @@ genRightShift (iCode * ic) return; } + emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); + emit2 ("inc a"); + freeAsmop (right, NULL, ic); + aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); /* now move the left to the result if they are not the same */ - if (!sameRegs (AOP (left), AOP (result)) && - AOP_SIZE (result) > 1) + if (!sameRegs (AOP (left), AOP (result))) { size = AOP_SIZE (result); @@ -5974,10 +6200,6 @@ genRightShift (iCode * ic) } } - emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); - emit2 ("inc a"); - freeAsmop (right, NULL, ic); - tlbl = newiTempLabel (NULL); tlbl1 = newiTempLabel (NULL); size = AOP_SIZE (result); @@ -6006,6 +6228,82 @@ genRightShift (iCode * ic) freeAsmop (result, NULL, ic); } + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, int pair) +{ + int offset = 0; /* result byte offset */ + int rsize; /* result size */ + int rlen = 0; /* remaining bitfield length */ + sym_link *etype; /* bitfield type information */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + + emitDebug ("; genUnpackBits"); + + etype = getSpec (operandType (result)); + rsize = getSize (operandType (result)); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + AccRsh (bstr); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen)); + aopPut (AOP (result), "a", offset++); + goto finish; + } + + /* TODO: what if pair == PAIR_DE ? */ + if (getPairId (AOP (result)) == PAIR_HL) + { + wassertl (rsize == 2, "HL must be of size 2"); + emit2 ("ld a,!*hl"); + emit2 ("inc hl"); + emit2 ("ld h,!*hl"); + emit2 ("ld l,a"); + emit2 ("ld a,h"); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen)); + emit2 ("ld h,a"); + spillPair (PAIR_HL); + return; + } + + /* Bit field did not fit in a byte. Copy all + but the partial byte at the end. */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + aopPut (AOP (result), "a", offset++); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* Handle the partial byte at the end */ + if (rlen) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen)); + aopPut (AOP (result), "a", offset++); + } + +finish: + if (offset < rsize) + { + rsize -= offset; + while (rsize--) + aopPut (AOP (result), "!zero", offset++); + } +} + /*-----------------------------------------------------------------*/ /* genGenPointerGet - get value from generic pointer space */ /*-----------------------------------------------------------------*/ @@ -6025,12 +6323,13 @@ genGenPointerGet (operand * left, size = AOP_SIZE (result); - if (isPair (AOP (left)) && size == 1) + if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype)) { /* Just do it */ if (isPtrPair (AOP (left))) { - tsprintf (buffer, "!*pair", getPairName (AOP (left))); + tsprintf (buffer, sizeof(buffer), + "!*pair", getPairName (AOP (left))); aopPut (AOP (result), buffer, 0); } else @@ -6042,14 +6341,14 @@ genGenPointerGet (operand * left, goto release; } - if (getPairId (AOP (left)) == PAIR_IY) + if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype)) { /* Just do it */ offset = 0; while (size--) { char at[20]; - tsprintf (at, "!*iyx", offset); + tsprintf (at, sizeof(at), "!*iyx", offset); aopPut (AOP (result), at, offset); offset++; } @@ -6065,7 +6364,10 @@ genGenPointerGet (operand * left, /* if bit then unpack */ if (IS_BITVAR (retype)) { - wassert (0); + genUnpackBits (result, pair); + freeAsmop (left, NULL, ic); + goto release; + //wassert (0); } else if (getPairId (AOP (result)) == PAIR_HL) { @@ -6165,6 +6467,149 @@ isRegOrLit (asmop * aop) return FALSE; } + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, + operand * right, + int pair, + iCode *ic) +{ + int offset = 0; /* source byte offset */ + int rlen = 0; /* remaining bitfield length */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + int litval; /* source literal value (if AOP_LIT) */ + unsigned char mask; /* bitmask within current byte */ + int extraPair; /* a tempory register */ + bool needPopExtra=0; /* need to restore original value of temp reg */ + + emitDebug ("; genPackBits",""); + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + mask = ((unsigned char) (0xFF << (blen + bstr)) | + (unsigned char) (0xFF >> (8 - bstr))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with a bitfield length <8 and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval <<= bstr; + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + emit2 ("ld !*pair,a", _pairs[pair].name); + return; + } + else + { + /* Case with a bitfield length <8 and arbitrary source + */ + _moveA (aopGet (AOP (right), 0, FALSE)); + /* shift and mask source value */ + AccLsh (bstr); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = PAIR_BC; + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (needPopExtra) + _pop (extraPair); + return; + } + } + + /* Bit length is greater than 7 bits. In this case, copy */ + /* all except the partial byte at the end */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) ); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* If there was a partial byte at the end */ + if (rlen) + { + mask = (((unsigned char) -1 << rlen) & 0xff); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with partial byte and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval >>= (blen-rlen); + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + } + else + { + /* Case with partial byte and arbitrary source + */ + _moveA (aopGet (AOP (right), offset++, FALSE)); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = getPairId (AOP (right)); + if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID)) + extraPair = PAIR_BC; + + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + if (needPopExtra) + _pop (extraPair); + + } + emit2 ("ld !*pair,a", _pairs[pair].name); + } +} + + /*-----------------------------------------------------------------*/ /* genGenPointerSet - stores the value into a pointer location */ /*-----------------------------------------------------------------*/ @@ -6174,7 +6619,9 @@ genGenPointerSet (operand * right, { int size, offset; sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (result)); PAIR_ID pairId = PAIR_HL; + bool isBitvar; aopOp (result, ic, FALSE, FALSE); aopOp (right, ic, FALSE, FALSE); @@ -6184,8 +6631,11 @@ genGenPointerSet (operand * right, size = AOP_SIZE (right); + isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype); + emitDebug("; isBitvar = %d", isBitvar); + /* Handle the exceptions first */ - if (isPair (AOP (result)) && size == 1) + if (isPair (AOP (result)) && size == 1 && !isBitvar) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -6202,7 +6652,7 @@ genGenPointerSet (operand * right, goto release; } - if ( getPairId( AOP (result)) == PAIR_IY) + if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -6223,7 +6673,8 @@ genGenPointerSet (operand * right, } goto release; } - else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)) + else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result) + && !isBitvar) { offset = 0; @@ -6265,9 +6716,11 @@ genGenPointerSet (operand * right, freeAsmop (result, NULL, ic); /* if bit then unpack */ - if (IS_BITVAR (retype)) + if (isBitvar) { - wassert (0); + genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic); + goto release; + //wassert (0); } else { @@ -6645,7 +7098,7 @@ genCast (iCode * ic) /* now depending on the sign of the destination */ size = AOP_SIZE (result) - AOP_SIZE (right); /* Unsigned or not an integral type - right fill with zeros */ - if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY) + if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY) { while (size--) aopPut (AOP (result), "!zero", offset++); @@ -6696,6 +7149,31 @@ genReceive (iCode * ic) freeAsmop (IC_RESULT (ic), NULL, ic); } +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + operand *right; + int size, offset; + + right = IC_RIGHT (ic); + aopOp (right, ic, FALSE, FALSE); + + /* general case */ + size = AOP_SIZE (right); + offset = 0; + + while (size--) + { + _moveA (aopGet (AOP (right), offset, FALSE)); + offset++; + } + + freeAsmop (right, NULL, ic); +} + enum { /** Maximum number of bytes to emit per line. */ @@ -7232,15 +7710,45 @@ genZ80Code (iCode * lic) } _G.lines.head = _G.lines.current = NULL; + + /* if debug information required */ + if (options.debug && currFunc) + { + debugFile->writeFunction(currFunc); + _G.lines.isDebug = 1; + if (IS_STATIC (currFunc->etype)) + sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name); + else + sprintf (buffer, "G$%s$0$0", currFunc->name); + emit2 ("!labeldef", buffer); + _G.lines.isDebug = 0; + } for (ic = lic; ic; ic = ic->next) { + _G.current_iCode = ic; - if (cln != ic->lineno) + if (ic->lineno && cln != ic->lineno) { - emit2 ("; %s %d", ic->filename, ic->lineno); + if (options.debug) + { + _G.lines.isDebug = 1; + sprintf (buffer, "C$%s$%d$%d$%d", + FileBaseName (ic->filename), ic->lineno, + ic->level, ic->block); + emit2 ("%s !equ .", buffer); + emit2 ("!global", buffer); + _G.lines.isDebug = 0; + } + if (!options.noCcodeInAsm) { + emit2 (";%s:%d: %s", ic->filename, ic->lineno, + printCLine(ic->filename, ic->lineno)); + } cln = ic->lineno; } + if (options.iCodeInAsm) { + emit2 (";ic:%d: %s", ic->key, printILine(ic)); + } /* if the result is marked as spilt and rematerializable or code for this has already been generated then @@ -7493,7 +8001,12 @@ genZ80Code (iCode * lic) emitDebug ("; genArrayInit"); genArrayInit(ic); break; - + + case DUMMY_READ_VOLATILE: + emitDebug ("; genDummyRead"); + genDummyRead (ic); + break; + default: ic = ic; } @@ -7561,7 +8074,7 @@ fetchLitSpecial (asmop * aop, bool negate, bool xor) v = 0-v; v &= 0xFFFF; - tsprintf (buffer, "!immedword", v); + tsprintf (buffer, sizeof(buffer), "!immedword", v); return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); }