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>
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
#ifdef HAVE_SYS_ISA_DEFS_H
#include <sys/isa_defs.h>
#endif
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;
}
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)
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;
/* 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;
spillCached ();
if (i > 8)
{
- emit2 ("ld iy,#%d", i);
+ emit2 ("ld iy,!immedword", i);
emit2 ("add iy,sp");
emit2 ("ld sp,iy");
}
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");
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);
+ }
}
}
}
goto release;
}
- if ( getPairId( AOP (left)) == PAIR_IY)
+ if (getPairId (AOP (left)) == PAIR_IY)
{
/* Just do it */
offset = 0;
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++;
genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
{
operand *from, *to, *count;
- symbol *label;
bool deInUse;
- iCode *pcall;
wassertl (nParams == 3, "Built-in memcpy must have two parameters");
to = pparams[2];