9. With asm optimised strings 17030 192 2223
10 and below are with asm strings off.
-
+
+ 10 Mucho optimisations 13562 201 1FCC
+
Apparent advantage of turning on regparams:
1. Cost of push
Decent case is push of a constant
#include <string.h>
#include <ctype.h>
-#ifdef HAVE_SYS_ISA_DEFS_H
-#include <sys/isa_defs.h>
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
#endif
#include "z80.h"
int pushedBC;
int pushedDE;
} stack;
+
+ struct
+ {
+ int pushedBC;
+ int pushedDE;
+ } calleeSaves;
+
int frameId;
int receiveOffset;
bool flushStatics;
static const char *aopGet (asmop * aop, int offset, bool bit16);
+static const char *aopNames[] = {
+ "AOP_INVALID",
+ "AOP_LIT",
+ "AOP_REG",
+ "AOP_DIR",
+ "AOP_SFR",
+ "AOP_STK",
+ "AOP_IMMD",
+ "AOP_STR",
+ "AOP_CRY",
+ "AOP_IY",
+ "AOP_HL",
+ "AOP_ACC",
+ "AOP_HLREG",
+ "AOP_SIMPLELIT",
+ "AOP_EXSTK",
+ "AOP_PAIRPT"
+};
+
+static bool
+isLastUse (iCode *ic, operand *op)
+{
+ bitVect *uses = bitVectCopy (OP_USES (op));
+
+ while (!bitVectIsZero (uses))
+ {
+ if (bitVectFirstBit (uses) == ic->key)
+ {
+ if (bitVectnBitsOn (uses) == 1)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ bitVectUnSetBit (uses, bitVectFirstBit (uses));
+ }
+
+ return FALSE;
+}
+
static PAIR_ID
_getTempPairId(void)
{
return _pairs[_getTempPairId()].name;
}
+static bool
+isPairInUse (PAIR_ID id, iCode *ic)
+{
+ if (id == PAIR_DE)
+ {
+ return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+ }
+ else if (id == PAIR_BC)
+ {
+ return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
+ }
+ else
+ {
+ wassertl (0, "Only implemented for DE and BC");
+ return TRUE;
+ }
+}
+
+static bool
+isPairInUseNotInRet(PAIR_ID id, iCode *ic)
+{
+ bitVect *rInUse;
+
+ rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+
+ if (id == PAIR_DE)
+ {
+ return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
+ }
+ else
+ {
+ wassertl (0, "Only implemented for DE");
+ return TRUE;
+ }
+}
+
static PAIR_ID
getFreePairId (iCode *ic)
{
- if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
+ if (!isPairInUse (PAIR_BC, ic))
{
return PAIR_BC;
}
- else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
+ else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
{
return PAIR_DE;
}
{
char buffer[256];
- tvsprintf (buffer, szFormat, ap);
+ tvsprintf (buffer, sizeof(buffer), szFormat, ap);
_tidyUp (buffer);
_G.lines.current = (_G.lines.current ?
static void
_emitMove(const char *to, const char *from)
{
- if (strcasecmp(to, from) != 0)
+ if (STRCASECMP(to, from) != 0)
{
emit2("ld %s,%s", to, from);
}
}
}
+void
+aopDump(const char *plabel, asmop *aop)
+{
+ emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
+ switch (aop->type)
+ {
+ case AOP_STK:
+ emitDebug("; aop_stk %d", aop->aopu.aop_stk);
+ break;
+ default:
+ /* No information. */
+ break;
+ }
+}
+
static void
_moveA(const char *moveFrom)
{
/* if already has one */
if (sym->aop)
- return sym->aop;
+ {
+ return sym->aop;
+ }
/* Assign depending on the storage class */
if (sym->onStack || sym->iaccess)
/* if already has a asmop then continue */
if (op->aop)
- return;
+ {
+ return;
+ }
/* if the underlying symbol has a aop */
if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
}
/* else spill location */
+ if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
+ /* force a new aop if sizes differ */
+ sym->usl.spillLoc->aop = NULL;
+ }
sym->aop = op->aop = aop =
aopForSym (ic, sym->usl.spillLoc, result, requires_a);
+ wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
aop->size = getSize (sym->type);
return;
}
_pop (aop->aopu.aop_pairId);
}
+ if (getPairId (aop) == PAIR_HL)
+ {
+ spillPair (PAIR_HL);
+ }
+
dealloc:
/* all other cases just dealloc */
if (op)
char *
aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
{
- char *s = buffer;
-
/* depending on type */
switch (aop->type)
{
/* 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:
{
}
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));
}
/* 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));
}
emit2 ("ld %s,!hashedstr", pair, l);
}
+static PAIR_ID
+makeFreePairId (iCode *ic, bool *pisUsed)
+{
+ *pisUsed = FALSE;
+
+ if (ic != NULL)
+ {
+ if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
+ {
+ return PAIR_BC;
+ }
+ else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
+ {
+ return PAIR_DE;
+ }
+ else
+ {
+ *pisUsed = TRUE;
+ return PAIR_HL;
+ }
+ }
+ else
+ {
+ *pisUsed = TRUE;
+ return PAIR_HL;
+ }
+}
+
static void
-fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
+fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
{
/* if this is remateriazable */
if (isLitWord (aop)) {
}
else
{
- _push (PAIR_HL);
+ bool isUsed;
+ PAIR_ID id = makeFreePairId (ic, &isUsed);
+ if (isUsed)
+ _push (id);
/* Can't load into parts, so load into HL then exchange. */
- emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
- emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
- emit2 ("push hl");
+ emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
+ emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
+ emit2 ("push %s", _pairs[id].name);
emit2 ("pop iy");
- _pop (PAIR_HL);
+ if (isUsed)
+ _pop (id);
}
}
- else {
+ 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);
static void
fetchPair (PAIR_ID pairId, asmop * aop)
{
- fetchPairLong (pairId, aop, 0);
+ fetchPairLong (pairId, aop, NULL, 0);
}
static void
{
/* Doesnt include _G.stack.pushed */
int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
+
if (aop->aopu.aop_stk > 0)
{
abso += _G.stack.param_offset;
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 */
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;
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");
}
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:
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;
case AOP_PAIRPTR:
setupPair (aop->aopu.aop_pairId, aop, offset);
- sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
+ 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;
}
// PENDING
- tsprintf(buffer2, s);
+ tsprintf(buffer2, sizeof(buffer2), s);
s = buffer2;
/* will assign value to value */
/* if bit variable */
if (!aop->aopu.aop_dir)
{
- emit2 ("ld a,#0");
+ emit2 ("ld a,!zero");
emit2 ("rla");
}
else
emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
emit2 ("ld l,a");
+ spillPair (PAIR_HL);
}
else if ( getPairId ( AOP (result)) == PAIR_IY)
{
aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
- fetchPairLong (PAIR_DE, left, MSB24);
+ fetchPairLong (PAIR_DE, left, NULL, MSB24);
aopGet (right, MSB24, FALSE);
_pop (PAIR_AF);
}
if (size == 4)
{
- fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
+ fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
emit2 ("push hl");
spillPair (PAIR_HL);
_G.stack.pushed += 2;
- fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
+ fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
emit2 ("push hl");
spillPair (PAIR_HL);
_G.stack.pushed += 2;
{
sym_link *dtype = operandType (IC_LEFT (ic));
- bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
-
/* if caller saves & we have not saved then */
if (!ic->regsSaved)
{
else
{
spillCached ();
- if (i > 6)
+ if (i > 8)
{
- emit2 ("ld hl,#%d", i);
- emit2 ("add hl,sp");
- emit2 ("ld sp,hl");
+ emit2 ("ld iy,!immedword", i);
+ emit2 ("add iy,sp");
+ emit2 ("ld sp,iy");
}
else
{
while (i > 1)
{
- emit2 ("pop hl");
+ emit2 ("pop af");
i -= 2;
}
if (i)
- emit2 ("inc sp");
+ {
+ emit2 ("inc sp");
+ }
}
}
}
if (_G.stack.pushedDE)
{
- bool dInUse = bitVectBitValue(rInUse, D_IDX);
- bool eInUse = bitVectBitValue(rInUse, E_IDX);
+ bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
+ bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
- if (dInUse && eInUse)
+ if (dInRet && eInRet)
{
- _pop (PAIR_DE);
+ wassertl (0, "Shouldn't push DE if it's wiped out by the return");
}
- else if (dInUse)
+ else if (dInRet)
{
- _pop(PAIR_HL);
- emit2 ("ld d,h");
+ /* Only restore E */
+ emit2 ("ld a,d");
+ _pop (PAIR_DE);
+ emit2 ("ld d,a");
}
- else if (eInUse)
+ else if (eInRet)
{
- _pop(PAIR_HL);
- emit2 ("ld e,l");
+ /* Only restore D */
+ _pop (PAIR_AF);
+ emit2 ("ld d,a");
}
else
{
- wassertl (0, "Neither D or E were in use but it was pushed.");
+ _pop (PAIR_DE);
}
_G.stack.pushedDE = FALSE;
}
if (_G.stack.pushedBC)
{
- bool bInUse = bitVectBitValue(rInUse, B_IDX);
- bool cInUse = bitVectBitValue(rInUse, C_IDX);
+ bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
+ bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
- // If both B and C are used in the return value, then we won't get
- // here.
- if (bInUse && cInUse)
+ if (bInRet && cInRet)
{
- _pop (PAIR_BC);
+ wassertl (0, "Shouldn't push BC if it's wiped out by the return");
}
- else if (bInUse)
+ else if (bInRet)
{
- _pop(PAIR_HL);
- emit2 ("ld b,h");
+ /* Only restore C */
+ emit2 ("ld a,b");
+ _pop (PAIR_BC);
+ emit2 ("ld b,a");
}
- else if (cInUse)
+ else if (cInRet)
{
- _pop(PAIR_HL);
- emit2 ("ld c,l");
+ /* Only restore B */
+ _pop (PAIR_AF);
+ emit2 ("ld b,a");
}
else
{
- wassertl (0, "Neither B or C were in use but it was pushed.");
+ _pop (PAIR_BC);
}
_G.stack.pushedBC = FALSE;
}
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
sym_link *ftype;
-#if CALLEE_SAVES
bool bcInUse = FALSE;
bool deInUse = FALSE;
-#endif
setArea (IFFUNC_NONBANKED (sym->type));
/* Create the function header */
emit2 ("!functionheader", sym->name);
- /* PENDING: portability. */
- emit2 ("__%s_start:", sym->rname);
+ sprintf (buffer, "%s_start", sym->rname);
+ emit2 ("!labeldef", buffer);
emit2 ("!functionlabeldef", sym->rname);
if (options.profile)
_G.stack.param_offset = 0;
-#if CALLEE_SAVES
+ if (z80_opts.calleeSavesBC)
+ {
+ bcInUse = TRUE;
+ }
+
/* Detect which registers are used. */
- if (sym->regsUsed)
+ if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
{
int i;
for (i = 0; i < sym->regsUsed->size; i++)
_G.stack.param_offset += 2;
}
- _G.stack.pushedBC = bcInUse;
+ _G.calleeSaves.pushedBC = bcInUse;
if (deInUse)
{
_G.stack.param_offset += 2;
}
- _G.stack.pushedDE = deInUse;
-#endif
+ _G.calleeSaves.pushedDE = deInUse;
/* adjust the stack for the function */
_G.stack.last = sym->stack;
emit2 ("!leave");
}
-#if CALLEE_SAVES
- if (_G.stack.pushedDE)
+ if (_G.calleeSaves.pushedDE)
{
emit2 ("pop de");
- _G.stack.pushedDE = FALSE;
+ _G.calleeSaves.pushedDE = FALSE;
}
- if (_G.stack.pushedDE)
+ if (_G.calleeSaves.pushedBC)
{
emit2 ("pop bc");
- _G.stack.pushedDE = FALSE;
+ _G.calleeSaves.pushedBC = FALSE;
}
-#endif
if (options.profile)
{
/* Both baned and non-banked just ret */
emit2 ("ret");
- /* PENDING: portability. */
- emit2 ("__%s_end:", sym->rname);
+ sprintf (buffer, "%s_end", sym->rname);
+ emit2 ("!labeldef", buffer);
}
_G.flushStatics = 1;
_G.stack.pushed = 0;
if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
{
fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
- fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
+ fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
}
else
{
if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
{
fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
- emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
+ emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
spillCached();
commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
goto release;
// wassertl (val > 0, "Multiply must be positive");
wassertl (val != 1, "Can't multiply by 1");
- if (IS_Z80) {
+ if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
_push (PAIR_DE);
+ _G.stack.pushedDE = TRUE;
}
if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
spillCached();
- if (IS_Z80)
+ if (IS_Z80 && _G.stack.pushedDE)
{
_pop (PAIR_DE);
+ _G.stack.pushedDE = FALSE;
}
commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
// Save the flags
emit2 ("push af");
emit2 ("ld a,(de)");
- emit2 ("xor #0x80");
+ emit2 ("xor !immedbyte", 0x80);
emit2 ("ld e,a");
emit2 ("ld a,(hl)");
- emit2 ("xor #0x80");
+ emit2 ("xor !immedbyte", 0x80);
emit2 ("ld d,a");
emit2 ("pop af");
emit2 ("ld a,e");
// Save the flags
emit2 ("push af");
emit2 ("ld a,(hl)");
- emit2 ("xor #0x80");
+ emit2 ("xor !immedbyte", 0x80);
emit2 ("ld l,a");
emit2 ("ld a,%d(iy)", offset);
- emit2 ("xor #0x80");
+ emit2 ("xor !immedbyte", 0x80);
emit2 ("ld h,a");
emit2 ("pop af");
emit2 ("ld a,l");
}
if (AOP_TYPE (right) == AOP_LIT)
- lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ }
/* if the right side is a literal then anything goes */
if (AOP_TYPE (right) == AOP_LIT &&
else
{
tlbl = newiTempLabel (NULL);
- emitDebug(";1");
gencjneshort (left, right, tlbl);
if (IC_TRUE (ifx))
{
- emitDebug(";2");
emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
emitLabel (tlbl->key + 100);
}
{
/* PENDING: do this better */
symbol *lbl = newiTempLabel (NULL);
- emitDebug(";3");
emit2 ("!shortjp !tlabel", lbl->key + 100);
emitLabel (tlbl->key + 100);
emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
operand *left, *result;
left = IC_LEFT (ic);
result = IC_RESULT (ic);
+
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, FALSE);
else
{
emit2 ("rlc a");
- /* PENDING: For re-target. */
- emit2 ("and a,#1");
+ emit2 ("and a,!one");
outAcc (result);
}
movLeft2Result (left, offl, result, offr, 0);
movLeft2Result (left, offl + 1, result, offr + 1, 0);
}
- /* PENDING: for now just see if it'll work. */
- /*if (AOP(result)->type == AOP_REG) { */
- {
+
+ if (getPairId (AOP (result)) == PAIR_HL)
+ {
+ while (shCount--)
+ {
+ emit2 ("add hl,hl");
+ }
+ }
+ else
+ {
int size = 2;
int offset = 0;
symbol *tlbl, *tlbl1;
tlbl = newiTempLabel (NULL);
tlbl1 = newiTempLabel (NULL);
- /* Left is already in result - so now do the shift */
- if (shCount > 1)
+ if (AOP (result)->type == AOP_REG)
{
- emit2 ("ld a,!immedbyte+1", shCount);
- emit2 ("!shortjp !tlabel", tlbl1->key + 100);
- emitLabel (tlbl->key + 100);
+ while (shCount--)
+ {
+ for (offset = 0; offset < size; offset++)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+ }
+ }
}
-
- while (size--)
+ else
{
- l = aopGet (AOP (result), offset, FALSE);
-
- if (offset == 0)
- {
- emit2 ("sla %s", l);
- }
- else
- {
- emit2 ("rl %s", l);
- }
+ /* 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);
+ }
- offset++;
- }
- if (shCount > 1)
- {
- emitLabel (tlbl1->key + 100);
- emit2 ("dec a");
- emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+
+ offset++;
+ }
+ if (shCount > 1)
+ {
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
}
}
}
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)
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);
}
}
- 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);
/* 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
goto release;
}
- if ( getPairId( AOP (left)) == PAIR_IY)
+ if (getPairId (AOP (left)) == PAIR_IY)
{
/* 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++;
}
+
+ freeAsmop (left, NULL, ic);
goto release;
}
/* if this is remateriazable */
fetchPair (pair, AOP (left));
- freeAsmop (left, NULL, ic);
-
/* if bit then unpack */
if (IS_BITVAR (retype))
{
wassert (0);
}
- else if ( getPairId( AOP (result)) == PAIR_HL)
+ else if (getPairId (AOP (result)) == PAIR_HL)
{
wassertl (size == 2, "HL must be of size 2");
emit2 ("ld a,!*hl");
emit2 ("inc hl");
emit2 ("ld h,!*hl");
emit2 ("ld l,a");
+ spillPair (PAIR_HL);
+ }
+ else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ /* PENDING: make this better */
+ if (!IS_GB && AOP_TYPE (result) == AOP_REG)
+ {
+ aopPut (AOP (result), "!*hl", offset++);
+ }
+ else
+ {
+ emit2 ("ld a,!*pair", _pairs[pair].name);
+ aopPut (AOP (result), "a", offset++);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[pair].name);
+ _G.pairs[pair].offset++;
+ }
+ }
+ /* Fixup HL back down */
+ for (size = AOP_SIZE (result)-1; size; size--)
+ {
+ emit2 ("dec %s", _pairs[pair].name);
+ }
}
else
{
while (size--)
{
/* PENDING: make this better */
- if (!IS_GB && AOP (result)->type == AOP_REG)
+ if (!IS_GB &&
+ (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
{
aopPut (AOP (result), "!*hl", offset++);
}
}
}
+ freeAsmop (left, NULL, ic);
+
release:
freeAsmop (result, NULL, ic);
}
}
goto release;
}
+ else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
+ {
+ offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (AOP (right), offset, FALSE);
+ if (isRegOrLit (AOP (right)) && !IS_GB)
+ {
+ emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
+ }
+ else
+ {
+ _moveA (l);
+ emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[PAIR_HL].name);
+ _G.pairs[PAIR_HL].offset++;
+ }
+ offset++;
+ }
+
+ /* Fixup HL back down */
+ for (size = AOP_SIZE (right)-1; size; size--)
+ {
+ emit2 ("dec %s", _pairs[PAIR_HL].name);
+ }
+ goto release;
+ }
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
{
/* if it has an offset then we need to compute it */
if (sym->stack > 0)
- emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
+ emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
else
- emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+ emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
emit2 ("add hl,sp");
}
else
{
- emit2 ("ld hl,#%s", sym->rname);
+ emit2 ("ld hl,!hashedstr", sym->rname);
}
commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
}
if (AOP_TYPE (right) == AOP_LIT)
{
- lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
}
if (isPair (AOP (result)))
{
- fetchPair (getPairId (AOP (result)), AOP (right));
+ fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
}
else if ((size > 1) &&
(AOP_TYPE (result) != AOP_REG) &&
genCast (iCode * ic)
{
operand *result = IC_RESULT (ic);
- sym_link *ctype = operandType (IC_LEFT (ic));
+ sym_link *rtype = operandType (IC_RIGHT (ic));
operand *right = IC_RIGHT (ic);
int size, offset;
/* now depending on the sign of the destination */
size = AOP_SIZE (result) - AOP_SIZE (right);
/* Unsigned or not an integral type - right fill with zeros */
- if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
+ if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
{
while (size--)
aopPut (AOP (result), "!zero", offset++);
/* Yes, worthwhile. */
/* Commit whatever was in the buffer. */
_rleCommit(self);
- emit2(".db -%u,0x%02X", self->runLen, self->last);
+ emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
}
else
{
/* Commit whatever was in the buffer. */
_rleCommit(self);
- emit2 (".db -%u,0x%02X", self->runLen, self->last);
+ emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
self->runLen = 0;
}
self->runLen++;
freeAsmop (IC_LEFT(ic), NULL, ic);
}
+static void
+_swap (PAIR_ID one, PAIR_ID two)
+{
+ if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
+ {
+ emit2 ("ex de,hl");
+ }
+ else
+ {
+ emit2 ("ld a,%s", _pairs[one].l);
+ emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
+ emit2 ("ld %s,a", _pairs[two].l);
+ emit2 ("ld a,%s", _pairs[one].h);
+ emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
+ emit2 ("ld %s,a", _pairs[two].h);
+ }
+}
+
+/* The problem is that we may have all three pairs used and they may
+ be needed in a different order.
+
+ Note: Have ex de,hl
+
+ Combinations:
+ hl = hl => unity, fine
+ bc = bc
+ de = de
+
+ hl = hl hl = hl, swap de <=> bc
+ bc = de
+ de = bc
+
+ hl = bc Worst case
+ bc = de
+ de = hl
+
+ hl = bc de = de, swap bc <=> hl
+ bc = hl
+ de = de
+
+ hl = de Worst case
+ bc = hl
+ de = bc
+
+ hl = de bc = bc, swap hl <=> de
+ bc = bc
+ de = hl
+
+ Break it down into:
+ * Any pair = pair are done last
+ * Any pair = iTemp are done last
+ * Any swaps can be done any time
+
+ A worst case:
+ push p1
+ p1 = p2
+ p2 = p3
+ pop p3
+
+ So how do we detect the cases?
+ How about a 3x3 matrix?
+ source
+ dest x x x x
+ x x x x
+ x x x x (Fourth for iTemp/other)
+
+ First determin which mode to use by counting the number of unity and
+ iTemp assigns.
+ Three - any order
+ Two - Assign the pair first, then the rest
+ One - Swap the two, then the rest
+ Zero - Worst case.
+*/
+static void
+setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
+{
+ PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
+ PAIR_ID dest[3] = {
+ PAIR_BC, PAIR_HL, PAIR_DE
+ };
+ int i, j, nunity = 0;
+ memset (ids, PAIR_INVALID, sizeof (ids));
+
+ /* Sanity checks */
+ wassert (nparams == 3);
+
+ /* First save everything that needs to be saved. */
+ _saveRegsForCall (ic, 0);
+
+ /* Loading HL first means that DE is always fine. */
+ for (i = 0; i < nparams; i++)
+ {
+ aopOp (pparams[i], ic, FALSE, FALSE);
+ ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
+ }
+
+ /* Count the number of unity or iTemp assigns. */
+ for (i = 0; i < 3; i++)
+ {
+ if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
+ {
+ nunity++;
+ }
+ }
+
+ if (nunity == 3)
+ {
+ /* Any order, fall through. */
+ }
+ else if (nunity == 2)
+ {
+ /* One is assigned. Pull it out and assign. */
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < NUM_PAIRS; j++)
+ {
+ if (ids[dest[i]][j] == TRUE)
+ {
+ /* Found it. See if it's the right one. */
+ if (j == PAIR_INVALID || j == dest[i])
+ {
+ /* Keep looking. */
+ }
+ else
+ {
+ fetchPair(dest[i], AOP (pparams[i]));
+ goto done;
+ }
+ }
+ }
+ }
+ }
+ else if (nunity == 1)
+ {
+ /* Find the pairs to swap. */
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < NUM_PAIRS; j++)
+ {
+ if (ids[dest[i]][j] == TRUE)
+ {
+ if (j == PAIR_INVALID || j == dest[i])
+ {
+ /* Keep looking. */
+ }
+ else
+ {
+ _swap (j, dest[i]);
+ goto done;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ int next = getPairId (AOP (pparams[0]));
+ emit2 ("push %s", _pairs[next].name);
+
+ if (next == dest[1])
+ {
+ fetchPair (dest[1], AOP (pparams[1]));
+ fetchPair (dest[2], AOP (pparams[2]));
+ }
+ else
+ {
+ fetchPair (dest[2], AOP (pparams[2]));
+ fetchPair (dest[1], AOP (pparams[1]));
+ }
+ emit2 ("pop %s", _pairs[dest[0]].name);
+ }
+ done:
+ /* Finally pull out all of the iTemps */
+ for (i = 0; i < 3; i++)
+ {
+ if (ids[dest[i]][PAIR_INVALID] == 1)
+ {
+ fetchPair (dest[i], AOP (pparams[i]));
+ }
+ }
+}
+
+static void
+genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
+{
+ operand *from, *to;
+ symbol *label;
+ bool deInUse;
+
+ wassertl (nParams == 2, "Built-in strcpy must have two parameters");
+ to = pparams[0];
+ from = pparams[1];
+
+ deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+
+ setupForBuiltin3 (ic, nParams, pparams);
+
+ label = newiTempLabel(NULL);
+
+ emitLabel (label->key);
+ emit2 ("ld a,(hl)");
+ emit2 ("ldi");
+ emit2 ("or a");
+ emit2 ("!shortjp nz,!tlabel ; 1", label->key);
+
+ freeAsmop (from, NULL, ic->next);
+ freeAsmop (to, NULL, ic);
+}
+
+static void
+genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
+{
+ operand *from, *to, *count;
+ bool deInUse;
+
+ wassertl (nParams == 3, "Built-in memcpy must have two parameters");
+ to = pparams[2];
+ from = pparams[1];
+ count = pparams[0];
+
+ deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+
+ setupForBuiltin3 (ic, nParams, pparams);
+
+ emit2 ("ldir");
+
+ freeAsmop (count, NULL, ic->next->next);
+ freeAsmop (from, NULL, ic);
+
+ _restoreRegsAfterCall();
+
+ /* if we need assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
+ OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
+ IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+ aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+ movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
+ freeAsmop (IC_RESULT (ic), NULL, ic);
+ }
+
+ freeAsmop (to, NULL, ic->next);
+}
+
+/*-----------------------------------------------------------------*/
+/* genBuiltIn - calls the appropriate function to generating code */
+/* for a built in function */
+/*-----------------------------------------------------------------*/
+static void genBuiltIn (iCode *ic)
+{
+ operand *bi_parms[MAX_BUILTIN_ARGS];
+ int nbi_parms;
+ iCode *bi_iCode;
+ symbol *bif;
+
+ /* get all the arguments for a built in function */
+ bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
+
+ /* which function is it */
+ bif = OP_SYMBOL(IC_LEFT(bi_iCode));
+
+ if (strcmp(bif->name,"__builtin_strcpy")==0)
+ {
+ genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
+ }
+ else if (strcmp(bif->name,"__builtin_memcpy")==0)
+ {
+ genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
+ }
+ else
+ {
+ wassertl (0, "Unknown builtin function encountered");
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genZ80Code - generate code for Z80 based controllers */
/*-----------------------------------------------------------------*/
if (cln != ic->lineno)
{
- emit2 ("; %s %d", ic->filename, ic->lineno);
+ 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
break;
case SEND:
- emitDebug ("; addSet");
- addSet (&_G.sendSet, ic);
+ if (ic->builtinSEND)
+ {
+ emitDebug ("; genBuiltIn");
+ genBuiltIn(ic);
+ }
+ else
+ {
+ emitDebug ("; addSet");
+ addSet (&_G.sendSet, ic);
+ }
break;
case ARRAYINIT:
v = 0-v;
v &= 0xFFFF;
- tsprintf (buffer, "!immedword", v);
+ tsprintf (buffer, sizeof(buffer), "!immedword", v);
return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
}