gen.c - Z80 specific code generator.
Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
- ticks dhry size
+ ticks dhry size
Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
Improved WORD push 22784 144 19AE
With label1 on 22694 144 197E
5/3/00 17741 185 17B6
With reg params for mul and div 16234 202 162D
- Michael Hope <michaelh@earthling.net> 2000
+ 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
+
+ Michael Hope <michaelh@juju.net.nz> 2000
Based on the mcs51 generator -
Sandeep Dutta . sandeep.dutta@usa.net (1998)
and - Jean-Louis VERN.jlvern@writeme.com (1999)
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 = 1
+};
+
static char *_z80_return[] =
{"l", "h", "e", "d"};
static char *_gbz80_return[] =
}
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);
_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 */
/*-----------------------------------------------------------------*/
/* 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;
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;
}
}
/* 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
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) {
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);
{
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);
if (offset > 0)
{
- emit2 ("; Error aopPut AOP_ACC");
+ emitDebug ("; Error aopPut AOP_ACC");
}
else
{
/* 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
/* toBoolean - emit code for orl a,operator(sizeop) */
/*-----------------------------------------------------------------*/
void
-toBoolean (operand * oper)
+_toBoolean (operand * oper)
{
int size = AOP_SIZE (oper);
int offset = 0;
wassert (0);
}
- toBoolean (IC_LEFT (ic));
+ _toBoolean (IC_LEFT (ic));
/* Not of A:
If A == 0, !A = 1
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);
{
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"))
}
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"))
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
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 */
/*-----------------------------------------------------------------*/
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 */
}
#endif
+ if (options.profile)
+ {
+ emit2 ("!profileexit");
+ }
+
+
/* Both baned and non-banked just ret */
emit2 ("ret");
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);
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;
}
if (genPlusIncr (ic) == TRUE)
goto release;
- emit2 ("; genPlusIncr failed");
+ emitDebug ("; genPlusIncr failed");
size = getDataSize (IC_RESULT (ic));
}
else if (size == 4)
{
- emit2 ("; WARNING: This add is probably broken.\n");
+ emitDebug ("; WARNING: This add is probably broken.\n");
}
}
}
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))))
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)
}
else if (size == 4)
{
- emit2 ("; WARNING: This sub is probably broken.\n");
+ emitDebug ("; WARNING: This sub is probably broken.\n");
}
}
}
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));
}
}
}
{
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
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++;
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++;
}
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.
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);
}
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);
}
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
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
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 */
/*-----------------------------------------------------------------*/
int shCount, int is_signed)
{
int size = 2;
- int offset = 0;
symbol *tlbl, *tlbl1;
- const char *l;
movLeft2Result (left, offl, result, offr, 0);
movLeft2Result (left, offl + 1, result, offr + 1, 0);
tlbl = newiTempLabel (NULL);
tlbl1 = newiTempLabel (NULL);
-
+
/* Left is already in result - so now do the shift */
- if (shCount > 1)
+ if (shCount <= 2)
{
- emit2 ("ld a,!immedbyte+1", shCount);
- emit2 ("!shortjp !tlabel", tlbl1->key + 100);
- emitLabel (tlbl->key + 100);
- }
-
- offset = 0;
- while (size--)
- {
- l = aopGet (AOP (result), size, FALSE);
- if (offset == 0)
- {
- emit2 ("%s %s", is_signed ? "sra" : "srl", l);
- }
- else
+ while (shCount--)
{
- emit2 ("rr %s", l);
+ emitRsh2 (AOP (result), size, is_signed);
}
- offset++;
}
- if (shCount > 1)
+ else
{
+ emit2 ("ld a,!immedbyte+1", shCount);
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+
+ emitRsh2 (AOP (result), size, is_signed);
+
emitLabel (tlbl1->key + 100);
emit2 ("dec a");
emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
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
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 */
/* 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 */
/* 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
/* if they are the same registers */
if (sameRegs (AOP (right), AOP (result)))
{
- emit2 ("; (registers are the same)");
+ emitDebug ("; (registers are the same)");
goto release;
}
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--)
if (cln != ic->lineno)
{
- emit2 ("; %s %d", ic->filename, ic->lineno);
+ emitDebug ("; %s %d", ic->filename, ic->lineno);
cln = ic->lineno;
}
/* if the result is marked as
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;
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;
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 ("; genGetHBIT");
+ 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;
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;
enum
{
D_ALLOC = 0,
- D_ALLOC2 = 0
+ D_ALLOC2 = 0,
+ D_ACCUSE2 = 0,
+ D_ACCUSE2_VERBOSE = 0
};
#if 1
return 1;
}
-/*-----------------------------------------------------------------*/
-/* liveRangesWith - applies function to a given set of live range */
-/*-----------------------------------------------------------------*/
+/** liveRangesWith - applies function to a given set of live range
+ */
set *
liveRangesWith (bitVect * lrs, int (func) (symbol *, eBBlock *, iCode *),
eBBlock * ebp, iCode * ic)
}
-/*-----------------------------------------------------------------*/
-/* leastUsedLR - given a set determines which is the least used */
-/*-----------------------------------------------------------------*/
+/** leastUsedLR - given a set determines which is the least used
+ */
symbol *
leastUsedLR (set * sset)
{
return sym;
}
-/*-----------------------------------------------------------------*/
-/* noOverLap - will iterate through the list looking for over lap */
-/*-----------------------------------------------------------------*/
+/** noOverLap - will iterate through the list looking for over lap
+ */
static int
noOverLap (set * itmpStack, symbol * fsym)
{
{
iCode *dic, *sic;
- D (D_ALLOC, ("packRegsForAssing: running on ic %p\n", ic));
+ D (D_ALLOC, ("packRegsForAssign: running on ic %p\n", ic));
if (
/* !IS_TRUE_SYMOP(IC_RESULT(ic)) || */
OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_HL;
}
-bool
+static bool
opPreservesA (iCode * ic, iCode * uic)
{
- /* if it is a conditional branch then we definitely can */
if (uic->op == IFX)
- return FALSE;
+ {
+ return TRUE;
+
+ if (getSize (operandType (IC_COND (uic))) == 1 &&
+ IS_OP_LITERAL (IC_COND (uic)))
+ {
+ return TRUE;
+ }
+
+ D (D_ACCUSE2, (" + Dropping as operation is an IFX\n"));
+ return FALSE;
+ }
if (uic->op == JUMPTABLE)
- return FALSE;
+ {
+ D (D_ACCUSE2, (" + Dropping as operation is a Jumptable\n"));
+ return FALSE;
+ }
+
+ /* A pointer assign preserves A if A is the left value. */
+ if (uic->op == '=' && POINTER_SET (uic))
+ {
+ return TRUE;
+ }
/* if the usage has only one operand then we can */
/* PENDING: check */
if (IC_LEFT (uic) == NULL ||
IC_RIGHT (uic) == NULL)
- return FALSE;
+ {
+ D (D_ACCUSE2, (" + Dropping as operation has only one operand\n"));
+ return FALSE;
+ }
/* PENDING: check this rule */
if (getSize (operandType (IC_RESULT (uic))) > 1)
{
+ D (D_ACCUSE2, (" + Dropping as operation has size is too big\n"));
return FALSE;
}
1
)
{
+ D (D_ACCUSE2, (" + Dropping as 'its a bad op'\n"));
return FALSE;
}
/* PENDING */
if (!IC_LEFT (uic) || !IC_RESULT (ic))
- return FALSE;
+ {
+ D (D_ACCUSE2, (" + Dropping for some reason #1\n"));
+ return FALSE;
+ }
/** This is confusing :) Guess for now */
if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
(IS_ITEMP (IC_RIGHT (uic)) ||
(IS_TRUE_SYMOP (IC_RIGHT (uic)))))
- return TRUE;
+ {
+ return TRUE;
+ }
if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
(IS_ITEMP (IC_LEFT (uic)) ||
(IS_TRUE_SYMOP (IC_LEFT (uic)))))
- return TRUE;
+ {
+ return TRUE;
+ }
+
+ D (D_ACCUSE2, (" + Dropping as hit default case\n"));
return FALSE;
}
-static void
-joinPushes (iCode * ic)
+static bool
+opIgnoresA (iCode * ic, iCode * uic)
{
-#if 0
- if (ic->op == IPUSH &&
- isOperandLiteral (IC_LEFT (ic)) &&
- getSize (operandType (IC_LEFT (ic))) == 1 &&
- ic->next->op == IPUSH &&
- isOperandLiteral (IC_LEFT (ic->next)) &&
- getSize (operandType (IC_LEFT (ic->next))) == 1)
- {
- /* This is a bit tricky as michaelh doesnt know what he's doing.
- */
- /* First upgrade the size of (first) to int */
- SPEC_NOUN (operandType (IC_LEFT (ic))) = V_INT;
-
- floatFromVal (AOP /* need some sleep ... */ );
- /* Now get and join the values */
- value *val = aop->aopu.aop_lit;
- /* if it is a float then it gets tricky */
- /* otherwise it is fairly simple */
- if (!IS_FLOAT (val->type))
- {
- unsigned long v = floatFromVal (val);
-
- floatFrom ( /* need some sleep ... */ );
- printf ("Size %u\n", getSize (operandType (IC_LEFT (ic))));
- ic->next = ic->next->next;
- }
+ /* A increment of an iTemp by a constant is OK. */
+ if ( uic->op == '+' &&
+ IS_ITEMP (IC_LEFT (uic)) &&
+ IS_ITEMP (IC_RESULT (uic)) &&
+ IS_OP_LITERAL (IC_RIGHT (uic)))
+ {
+ unsigned int icount = (unsigned int) floatFromVal (IC_RIGHT (uic)->operand.valOperand);
+
+ /* Being an ITEMP means that we're already a symbol. */
+ if (icount == 1 &&
+ IC_RESULT (uic)->operand.symOperand->key == IC_LEFT (uic)->operand.symOperand->key
+ )
+ {
+ return TRUE;
+ }
}
-#endif
+
+ return FALSE;
}
+
+/* Some optimisation cases:
+
+ 1. Part of memcpy
+; genPointerGet
+ ld l,-4(ix)
+ ld h,-3(ix)
+ ld c,(hl)
+; genPlus
+ inc -4(ix)
+ jp nz,00108$
+ inc -3(ix)
+00108$:
+; genAssign (pointer)
+ ld a,c
+ ld (de),a
+
+ want to optimise down to:
+ ld hl,-4(ix) ...
+ ld a,(hl)
+ inc -4(ix).w ...
+ ld (de),a
+
+ So genPointer get is OK
+ genPlus where the right is constant, left is iTemp, and result is same as left
+ genAssign (pointer) is OK
+
+ 2. Part of _strcpy
+; genPointerGet
+ ld a,(de)
+ ld c,a
+; genIfx
+ xor a,a
+ or a,c
+ jp z,00103$
+; _strcpy.c 40
+; genAssign (pointer)
+; AOP_STK for _strcpy_to_1_1
+ ld l,-2(ix)
+ ld h,-1(ix)
+ ld (hl),c
+
+ want to optimise down to:
+ ld a,(de)
+ or a,a
+ jp z,00103$
+ ld (bc),a
+
+ So genIfx where IC_COND has size of 1 and is a constant.
+*/
+
/** Pack registers for acc use.
When the result of this operation is small and short lived it may
be able to be stored in the accumulator.
- Note that the 'A preserving' list is currently emperical :)e
+ Note that the 'A preserving' list is currently emperical :)
*/
static void
packRegsForAccUse2 (iCode * ic)
ic->op != EQ_OP &&
ic->op != CAST &&
1)
- return;
+ {
+ D (D_ACCUSE2, (" + Dropping as not a 'good' source command\n"));
+ return;
+ }
/* if + or - then it has to be one byte result.
MLH: Ok.
*/
if ((ic->op == '+' || ic->op == '-')
&& getSize (operandType (IC_RESULT (ic))) > 1)
- return;
+ {
+ D (D_ACCUSE2, (" + Dropping as it's a big + or -\n"));
+ return;
+ }
/* if shift operation make sure right side is not a literal.
MLH: depends.
/* has only one definition */
if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
{
+ D (D_ACCUSE2, (" + Dropping as it has more than one definition\n"));
return;
}
if (!(uic = hTabItemWithKey (iCodehTab,
bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
{
+ D (D_ACCUSE2, (" + Dropping as usage does not follow first\n"));
return;
}
next = hTabItemWithKey (iCodehTab, setBit);
if (scan->next == next)
{
+ D (D_ACCUSE2_VERBOSE, (" ! Is next in line\n"));
+
bitVectUnSetBit (uses, setBit);
/* Still contigous. */
if (!opPreservesA (ic, next))
{
+ D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A\n"));
return;
}
+ D (D_ACCUSE2_VERBOSE, (" ! Preserves A, so continue scanning\n"));
scan = next;
}
+ else if (scan->next == NULL && bitVectnBitsOn (uses) == 1 && next != NULL)
+ {
+ if (next->prev == NULL)
+ {
+ if (!opPreservesA (ic, next))
+ {
+ D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A #2\n"));
+ return;
+ }
+ bitVectUnSetBit (uses, setBit);
+ scan = next;
+ }
+ else
+ {
+ D (D_ACCUSE2, (" + Dropping as last in list and next doesn't start a block\n"));
+ return;
+ }
+ }
+ else if (scan->next == NULL)
+ {
+ D (D_ACCUSE2, (" + Dropping as hit the end of the list\n"));
+ D (D_ACCUSE2, (" + Next in htab: %p\n", next));
+ return;
+ }
else
{
- return;
+ if (opIgnoresA (ic, scan->next))
+ {
+ /* Safe for now. */
+ scan = scan->next;
+ D (D_ACCUSE2_VERBOSE, (" ! Op ignores A, so continue scanning\n"));
+ }
+ else
+ {
+ D (D_ACCUSE2, (" + Dropping as parts are not consecuitive and intermediate might use A\n"));
+ return;
+ }
}
}
while (!bitVectIsZero (uses));
+
OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A;
return;
}
packRegsForAccUse2 (ic);
}
#endif
- joinPushes (ic);
}
}