summaryrefslogtreecommitdiff
path: root/src/mcs51
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/mcs51
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/mcs51')
-rw-r--r--src/mcs51/Makefile7
-rw-r--r--src/mcs51/Makefile.in7
-rw-r--r--src/mcs51/gen.c12371
-rw-r--r--src/mcs51/gen.h88
-rw-r--r--src/mcs51/main.c934
-rw-r--r--src/mcs51/main.h45
-rw-r--r--src/mcs51/mcs51.vcxproj165
-rw-r--r--src/mcs51/mcs51.vcxproj.filters55
-rw-r--r--src/mcs51/peep.c773
-rw-r--r--src/mcs51/peep.h25
-rw-r--r--src/mcs51/peeph.def5092
-rw-r--r--src/mcs51/ralloc.c3466
-rw-r--r--src/mcs51/ralloc.h81
-rw-r--r--src/mcs51/rtrack.c1200
-rw-r--r--src/mcs51/rtrack.h28
15 files changed, 24337 insertions, 0 deletions
diff --git a/src/mcs51/Makefile b/src/mcs51/Makefile
new file mode 100644
index 0000000..cb704c7
--- /dev/null
+++ b/src/mcs51/Makefile
@@ -0,0 +1,7 @@
+
+srcdir = .
+top_builddir = ../..
+top_srcdir = ../..
+
+# Make all in this directory
+include $(srcdir)/../port.mk
diff --git a/src/mcs51/Makefile.in b/src/mcs51/Makefile.in
new file mode 100644
index 0000000..dfb8a52
--- /dev/null
+++ b/src/mcs51/Makefile.in
@@ -0,0 +1,7 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Make all in this directory
+include $(srcdir)/../port.mk
diff --git a/src/mcs51/gen.c b/src/mcs51/gen.c
new file mode 100644
index 0000000..b3ebf12
--- /dev/null
+++ b/src/mcs51/gen.c
@@ -0,0 +1,12371 @@
+/*-------------------------------------------------------------------------
+ gen.c - source file for code generation for 8051
+
+ Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
+ Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com
+ Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-------------------------------------------------------------------*/
+/*
+ Notes:
+ 000123 mlh Moved aopLiteral to SDCCglue.c to help the split
+ Made everything static
+*/
+
+#define D(x) do if (options.verboseAsm) {x;} while(0)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "common.h"
+#include "ralloc.h"
+#include "rtrack.h"
+#include "gen.h"
+#include "dbuf_string.h"
+
+char *aopLiteralGptr (const char *name, value * val);
+extern int allocInfo;
+
+/* this is the down and dirty file with all kinds of
+ kludgy & hacky stuff. This is what it is all about
+ CODE GENERATION for a specific MCU . some of the
+ routines may be reusable, will have to see */
+
+static char *zero = "#0x00";
+static char *one = "#0x01";
+static char *spname;
+
+char *fReturn8051[] = { "dpl", "dph", "b", "a", "r4", "r5", "r6", "r7" };
+
+unsigned fReturnSizeMCS51 = 4; /* shared with ralloc.c */
+char **fReturn = fReturn8051;
+static char *accUse[] = { "a", "b" };
+
+static short rbank = -1;
+
+#define REG_WITH_INDEX mcs51_regWithIdx
+
+#define AOP(op) op->aop
+#define AOP_TYPE(op) AOP(op)->type
+#define AOP_SIZE(op) AOP(op)->size
+#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
+ AOP_TYPE(x) == AOP_R0))
+
+#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \
+ AOP_TYPE(x) == AOP_DPTR || \
+ AOP(x)->paged))
+
+#define AOP_INPREG(x) (x && (x->type == AOP_REG && \
+ (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
+ x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
+
+#define IS_AOP_IMMEDIATE(x) (AOP(x) && (AOP_TYPE(x) == AOP_LIT || \
+ AOP_TYPE(x) == AOP_IMMD || \
+ AOP_TYPE(x) == AOP_STR))
+
+#define SP_BP(sp, bp) (options.omitFramePtr ? sp : bp)
+#define SYM_BP(sym) (SPEC_OCLS (sym->etype)->paged ? SP_BP("_spx", "_bpx") : SP_BP("sp", "_bp"))
+
+#define EQ(a, b) (strcmp (a, b) == 0)
+
+#define R0INB _G.bu.bs.r0InB
+#define R1INB _G.bu.bs.r1InB
+#define OPINB _G.bu.bs.OpInB
+#define BITSINB _G.bu.bs.bitsInB
+#define BINUSE _G.bu.BInUse
+
+static struct
+{
+ short r0Pushed;
+ short r1Pushed;
+ union
+ {
+ struct
+ {
+ short r0InB: 2; //2 so we can see it overflow
+ short r1InB: 2; //2 so we can see it overflow
+ short OpInB: 2; //2 so we can see it overflow
+ short bitsInB: 2; //2 so we can see it overflow
+ } bs;
+ short BInUse;
+ } bu;
+ short accInUse;
+ struct
+ {
+ int pushed;
+ int pushedregs;
+ int offset;
+ int param_offset;
+ int xpushed;
+ int xpushedregs;
+ int xoffset;
+ } stack;
+ set *sendSet;
+ symbol *currentFunc;
+}
+_G;
+
+static char *rb1regs[] =
+{
+ "b1_0", "b1_1", "b1_2", "b1_3", "b1_4", "b1_5", "b1_6", "b1_7",
+ "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7"
+};
+
+extern struct dbuf_s *codeOutBuf;
+
+#define RESULTONSTACK(x) \
+ (IC_RESULT (x) && IC_RESULT (x)->aop && \
+ IC_RESULT (x)->aop->type == AOP_STK )
+
+#define MOVA(x) mova (x) /* use function to avoid multiple eval */
+#define MOVB(x) movb (x)
+
+#define CLRC emitcode ("clr","c")
+#define SETC emitcode ("setb","c")
+
+static unsigned char SLMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
+ 0xE0, 0xC0, 0x80, 0x00
+ };
+
+static unsigned char SRMask[] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
+ 0x07, 0x03, 0x01, 0x00
+ };
+
+#define MAX_REGISTER_BANKS 4
+
+#define LSB 0
+#define MSB16 1
+#define MSB24 2
+#define MSB32 3
+
+/*-----------------------------------------------------------------*/
+/* mcs51_emitDebuggerSymbol - associate the current code location */
+/* with a debugger symbol */
+/*-----------------------------------------------------------------*/
+void
+mcs51_emitDebuggerSymbol (const char *debugSym)
+{
+ genLine.lineElement.isDebug = 1;
+ emitcode ("", "%s ==.", debugSym);
+ genLine.lineElement.isDebug = 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* mova - moves specified value into accumulator */
+/*-----------------------------------------------------------------*/
+static void
+mova (const char *x)
+{
+ /* do some early peephole optimization */
+ if (!strncmp (x, "a", 2) || !strncmp (x, "acc", 4))
+ return;
+
+ /* if it is a literal mov try to get it cheaper */
+ if (*x == '#' && rtrackMoveALit (x))
+ return;
+
+ /* another early peephole optimization */
+ if (EQ (x, "#0x00"))
+ {
+ emitcode ("clr", "a");
+ return;
+ }
+
+ emitcode ("mov", "a,%s", x);
+}
+
+/*-----------------------------------------------------------------*/
+/* movb - moves specified value into register b */
+/*-----------------------------------------------------------------*/
+static void
+movb (const char *x)
+{
+ /* do some early peephole optimization */
+ if (!strncmp (x, "b", 2))
+ return;
+
+ /* if it is a literal mov try to get it cheaper */
+ if (*x == '#')
+ {
+ emitcode ("mov", "b,%s", rtrackGetLit (x));
+ return;
+ }
+
+ emitcode ("mov", "b,%s", x);
+}
+
+/*-----------------------------------------------------------------*/
+/* emitpush - push something on internal stack */
+/*-----------------------------------------------------------------*/
+static void
+emitpush (const char *arg)
+{
+ char buf[] = "ar?";
+
+ _G.stack.pushed++;
+ if (!arg)
+ {
+ emitcode ("inc", "sp");
+ return;
+ }
+ else if (EQ (arg, "a"))
+ {
+ arg = "acc";
+ }
+ else if ((*arg == '@') || (*arg == '#'))
+ {
+ MOVA (arg);
+ arg = "acc";
+ }
+ else if (EQ (arg, "r0") || EQ (arg, "r1") || EQ (arg, "r2") || EQ (arg, "r3") ||
+ EQ (arg, "r4") || EQ (arg, "r5") || EQ (arg, "r6") || EQ (arg, "r7"))
+ {
+ buf[2] = arg[1];
+ arg = buf;
+ }
+ emitcode ("push", arg);
+}
+
+/*-----------------------------------------------------------------*/
+/* emitpop - pop something from internal stack */
+/*-----------------------------------------------------------------*/
+static void
+emitpop (const char *arg)
+{
+ if (!arg)
+ emitcode ("dec", "sp");
+ else
+ emitcode ("pop", arg);
+ _G.stack.pushed--;
+ wassertl (_G.stack.pushed >= 0, "stack underflow");
+}
+
+/*-----------------------------------------------------------------*/
+/* pushB - saves register B if necessary */
+/*-----------------------------------------------------------------*/
+static bool
+pushB (void)
+{
+ bool pushedB = FALSE;
+
+ if (BINUSE)
+ {
+ emitpush ("b");
+// printf("B was in use !\n");
+ pushedB = TRUE;
+ }
+ else
+ {
+ OPINB++;
+ }
+ return pushedB;
+}
+
+/*-----------------------------------------------------------------*/
+/* popB - restores value of register B if necessary */
+/*-----------------------------------------------------------------*/
+static void
+popB (bool pushedB)
+{
+ if (pushedB)
+ {
+ emitpop ("b");
+ }
+ else
+ {
+ OPINB--;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* pushReg - saves register */
+/*-----------------------------------------------------------------*/
+static bool
+pushReg (int index, bool bits_pushed)
+{
+ const reg_info *reg = REG_WITH_INDEX (index);
+ if (reg->type == REG_BIT)
+ {
+ if (!bits_pushed)
+ emitpush (reg->base);
+ return TRUE;
+ }
+ else
+ emitpush (reg->dname);
+ return bits_pushed;
+}
+
+/*-----------------------------------------------------------------*/
+/* popReg - restores register */
+/*-----------------------------------------------------------------*/
+static bool
+popReg (int index, bool bits_popped)
+{
+ const reg_info *reg = REG_WITH_INDEX (index);
+ if (reg->type == REG_BIT)
+ {
+ if (!bits_popped)
+ emitpop (reg->base);
+ return TRUE;
+ }
+ else
+ emitpop (reg->dname);
+ return bits_popped;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* showR0R1status - helper for debugging getFreePtr failures */
+/*-----------------------------------------------------------------*/
+static void
+showR0R1status(iCode * ic)
+{
+ bool r0iu, r1iu;
+ bool r0ou, r1ou;
+
+ r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
+ r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
+ printf ("ic->rUsed = [");
+ if (r0iu)
+ if (r1iu)
+ printf("r0,r1");
+ else
+ printf("r0");
+ else
+ if (r1iu)
+ printf("r1");
+ printf("] ");
+
+ r0ou = bitVectBitValue (ic->rMask, R0_IDX);
+ r1ou = bitVectBitValue (ic->rMask, R1_IDX);
+ printf ("ic->rMask = [");
+ if (r0ou)
+ if (r1ou)
+ printf("r0,r1");
+ else
+ printf("r0");
+ else
+ if (r1ou)
+ printf("r1");
+ printf("]\n");
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getFreePtr (iCode * ic, asmop * aop, bool result)
+{
+ bool r0iu, r1iu;
+ bool r0ou, r1ou;
+
+ /* the logic: if r0 & r1 used in the instruction
+ then we are in trouble otherwise */
+
+ /* first check if r0 & r1 are used by this
+ instruction, in which case we are in trouble */
+ r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
+ r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
+ if (r0iu && r1iu)
+ {
+ goto endOfWorld;
+ }
+
+ r0ou = bitVectBitValue (ic->rMask, R0_IDX);
+ r1ou = bitVectBitValue (ic->rMask, R1_IDX);
+
+ /* if no usage of r0 then return it */
+ if (!r0iu && !r0ou)
+ {
+ ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
+ aop->type = AOP_R0;
+
+ return aop->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
+ }
+
+ /* if no usage of r1 then return it */
+ if (!r1iu && !r1ou)
+ {
+ ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
+ aop->type = AOP_R1;
+
+ return aop->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
+ }
+
+ /* now we know they both have usage */
+ /* if r0 not used in this instruction */
+ if (!r0iu)
+ {
+ /* push it if not already pushed */
+ if ((ic->op == IPUSH) || (ic->op == PCALL))
+ {
+ MOVB (REG_WITH_INDEX (R0_IDX)->dname);
+ R0INB++;
+ }
+ else if (!_G.r0Pushed)
+ {
+ emitpush (REG_WITH_INDEX (R0_IDX)->dname);
+ _G.r0Pushed++;
+ }
+
+ ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
+ aop->type = AOP_R0;
+
+ return aop->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
+ }
+
+ /* if r1 not used then */
+
+ if (!r1iu)
+ {
+ /* push it if not already pushed */
+ if ((ic->op == IPUSH) || (ic->op == PCALL))
+ {
+ MOVB (REG_WITH_INDEX (R1_IDX)->dname);
+ R1INB++;
+ }
+ else if (!_G.r1Pushed)
+ {
+ emitpush (REG_WITH_INDEX (R1_IDX)->dname);
+ _G.r1Pushed++;
+ }
+
+ ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
+ aop->type = AOP_R1;
+ return REG_WITH_INDEX (R1_IDX);
+ }
+
+endOfWorld:
+ /* I said end of world, but not quite end of world yet */
+ /* if this is a result then we can push it on the stack */
+ if (result)
+ {
+ aop->type = AOP_STK;
+ return NULL;
+ }
+ /* in the case that result AND left AND right needs a pointer reg
+ we can safely use the result's */
+ if (bitVectBitValue (mcs51_rUmaskForOp (IC_RESULT (ic)), R0_IDX) &&
+ (!OP_SYMBOL (IC_RESULT (ic)) || OP_SYMBOL (IC_RESULT (ic))->regs[getSize (operandType (IC_RESULT (ic))) - 1]->rIdx == R0_IDX))
+ {
+ aop->type = AOP_R0;
+ return REG_WITH_INDEX (R0_IDX);
+ }
+ if (bitVectBitValue (mcs51_rUmaskForOp (IC_RESULT (ic)), R1_IDX) &&
+ (!OP_SYMBOL (IC_RESULT (ic)) || OP_SYMBOL (IC_RESULT (ic))->regs[getSize (operandType (IC_RESULT (ic))) - 1]->rIdx == R1_IDX))
+ {
+ aop->type = AOP_R1;
+ return REG_WITH_INDEX (R1_IDX);
+ }
+
+ /* now this is REALLY the end of the world */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "getFreePtr should never reach here");
+ exit (EXIT_FAILURE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* getTempRegs - initialize an array of pointers to GPR registers */
+/* that are not in use. Returns 1 if the requested */
+/* number of registers were available, 0 otherwise. */
+/*-----------------------------------------------------------------*/
+int
+getTempRegs (reg_info ** tempRegs, int size, iCode * ic)
+{
+ bitVect *freeRegs;
+ int i;
+ int offset;
+
+ if (!ic)
+ ic = genLine.lineElement.ic;
+ if (!ic)
+ return 0;
+ if (!_G.currentFunc)
+ return 0;
+
+ freeRegs = newBitVect (8);
+ bitVectSetBit (freeRegs, R2_IDX);
+ bitVectSetBit (freeRegs, R3_IDX);
+ bitVectSetBit (freeRegs, R4_IDX);
+ bitVectSetBit (freeRegs, R5_IDX);
+ bitVectSetBit (freeRegs, R6_IDX);
+ bitVectSetBit (freeRegs, R7_IDX);
+
+ if (IFFUNC_CALLEESAVES (_G.currentFunc->type))
+ {
+ bitVect *newfreeRegs;
+ newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
+ freeBitVect (freeRegs);
+ freeRegs = newfreeRegs;
+ }
+ freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
+
+ offset = 0;
+ for (i = 0; i < freeRegs->size; i++)
+ {
+ if (bitVectBitValue (freeRegs, i))
+ tempRegs[offset++] = REG_WITH_INDEX (i);
+ if (offset >= size)
+ {
+ freeBitVect (freeRegs);
+ return 1;
+ }
+ }
+
+ freeBitVect (freeRegs);
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* newAsmop - creates a new asmOp */
+/*-----------------------------------------------------------------*/
+static asmop *
+newAsmop (short type)
+{
+ asmop *aop;
+
+ aop = Safe_calloc (1, sizeof (asmop));
+ aop->type = type;
+ aop->allocated = 1;
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* pointerCode - returns the code for a pointer type */
+/*-----------------------------------------------------------------*/
+static int
+pointerCode (sym_link * etype)
+{
+ return PTR_TYPE (SPEC_OCLS (etype));
+}
+
+/*-----------------------------------------------------------------*/
+/* leftRightUseAcc - returns size of accumulator use by operands */
+/*-----------------------------------------------------------------*/
+static int
+leftRightUseAcc (iCode * ic)
+{
+ operand *op;
+ int size;
+ int accuseSize = 0;
+ int accuse = 0;
+
+ if (!ic)
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "null iCode pointer");
+ return 0;
+ }
+
+ if (ic->op == IFX)
+ {
+ op = IC_COND (ic);
+ if (IS_OP_ACCUSE (op))
+ {
+ accuse = 1;
+ size = getSize (OP_SYMBOL (op)->type);
+ if (size > accuseSize)
+ accuseSize = size;
+ }
+ }
+ else if (ic->op == JUMPTABLE)
+ {
+ op = IC_JTCOND (ic);
+ if (IS_OP_ACCUSE (op))
+ {
+ accuse = 1;
+ size = getSize (OP_SYMBOL (op)->type);
+ if (size > accuseSize)
+ accuseSize = size;
+ }
+ }
+ else
+ {
+ op = IC_LEFT (ic);
+ if (IS_OP_ACCUSE (op))
+ {
+ accuse = 1;
+ size = getSize (OP_SYMBOL (op)->type);
+ if (size > accuseSize)
+ accuseSize = size;
+ }
+ op = IC_RIGHT (ic);
+ if (IS_OP_ACCUSE (op))
+ {
+ accuse = 1;
+ size = getSize (OP_SYMBOL (op)->type);
+ if (size > accuseSize)
+ accuseSize = size;
+ }
+ }
+
+ if (accuseSize)
+ return accuseSize;
+ else
+ return accuse;
+}
+
+/*-----------------------------------------------------------------*/
+/* stackoffset - stack offset for symbol */
+/*-----------------------------------------------------------------*/
+static int
+stackoffset (symbol * sym)
+{
+ int offset = sym->stack;
+ if (options.omitFramePtr)
+ {
+ if (SPEC_OCLS (sym->etype)->paged)
+ offset -= _G.stack.xoffset + _G.stack.xpushed;
+ else
+ offset -= _G.stack.offset + _G.stack.pushed;
+ }
+ if (sym->stack < 0)
+ offset -= _G.stack.param_offset;
+ return offset;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopPtrForSym - pointer for symbol */
+/*-----------------------------------------------------------------*/
+static void
+aopPtrForSym (symbol * sym, bool accuse, int offset, asmop * aop, iCode * ic)
+{
+ char *base;
+ struct dbuf_s tmpBuf;
+ dbuf_init (&tmpBuf, 1024);
+ if (sym->onStack)
+ {
+ dbuf_printf (&tmpBuf, "%s", SYM_BP (sym));
+ }
+ else
+ {
+ dbuf_printf (&tmpBuf, "#%s", sym->rname);
+ }
+ base = dbuf_detach_c_str (&tmpBuf);
+
+ offset += stackoffset (sym);
+
+ if (abs (offset) >= 248)
+ werrorfl (ic->filename, ic->lineno, W_LIT_OVERFLOW);
+
+ if ((abs (offset) < 3) || (accuse && (abs (offset) < 4)))
+ {
+ emitcode ("mov", "%s,%s", aop->aopu.aop_ptr->name, base);
+ while (offset < 0)
+ {
+ emitcode ("dec", aop->aopu.aop_ptr->name);
+ offset++;
+ }
+ while (offset > 0)
+ {
+ emitcode ("inc", aop->aopu.aop_ptr->name);
+ offset--;
+ }
+ }
+ else
+ {
+ if (accuse)
+ {
+ emitcode ("xch", "a,%s", aop->aopu.aop_ptr->name);
+ emitcode ("mov", "a,%s", base);
+ emitcode ("add", "a,#0x%02x", offset & 0xff);
+ emitcode ("xch", "a,%s", aop->aopu.aop_ptr->name);
+ }
+ else
+ {
+ emitcode ("mov", "a,%s", base);
+ emitcode ("add", "a,#0x%02x", offset & 0xff);
+ emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
+ }
+ }
+ aop->paged = SPEC_OCLS (sym->etype)->paged;
+ dbuf_free (base);
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForSym - for a true symbol */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForSym (iCode * ic, symbol * sym, bool result)
+{
+ asmop *aop;
+ memmap *space;
+ bool accuse = leftRightUseAcc (ic) || _G.accInUse;
+
+ wassertl (ic != NULL, "Got a null iCode");
+ wassertl (sym != NULL, "Got a null symbol");
+
+ space = SPEC_OCLS (sym->etype);
+
+ /* if already has one */
+ if (sym->aop)
+ {
+ sym->aop->allocated++;
+ return sym->aop;
+ }
+
+ /* assign depending on the storage class */
+ /* if it is on the stack or indirectly addressable */
+ /* space we need to assign either r0 or r1 to it */
+ if (sym->onStack || sym->iaccess)
+ {
+ sym->aop = aop = newAsmop (0);
+ aop->aopu.aop_ptr = getFreePtr (ic, aop, result);
+ aop->size = getSize (sym->type);
+
+ /* now assign the address of the variable to
+ the pointer register */
+ if (aop->type != AOP_STK)
+ {
+ aopPtrForSym (sym, accuse, 0, aop, ic);
+ }
+ else
+ {
+ aop->aopu.aop_sym = sym;
+ }
+ return aop;
+ }
+
+ /* if in bit space */
+ if (IN_BITSPACE (space))
+ {
+ sym->aop = aop = newAsmop (AOP_CRY);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ return aop;
+ }
+ /* if it is in direct space */
+ if (IN_DIRSPACE (space))
+ {
+ //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
+ //printTypeChainRaw(sym->type, NULL);
+ //printf("space = %s\n", space ? space->sname : "NULL");
+ sym->aop = aop = newAsmop (AOP_DIR);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ return aop;
+ }
+
+ /* special case for a function */
+ if (IS_FUNC (sym->type))
+ {
+ sym->aop = aop = newAsmop (AOP_IMMD);
+ aop->aopu.aop_immd.aop_immd1 = Safe_strdup (sym->rname);
+ aop->size = getSize (sym->type);
+ return aop;
+ }
+
+ /* only remaining is far space */
+ /* in which case DPTR gets the address */
+ sym->aop = aop = newAsmop (AOP_DPTR);
+
+ rtrackLoadDptrWithSym (sym->rname);
+
+ aop->size = getSize (sym->type);
+
+ /* if it is in code space */
+ if (IN_CODESPACE (space))
+ aop->code = 1;
+
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForRemat - rematerializes an object */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForRemat (symbol * sym)
+{
+ iCode *ic = sym->rematiCode;
+ asmop *aop = newAsmop (AOP_IMMD);
+ int ptr_type = 0;
+ int val = 0;
+ sym_link *from_type = NULL;
+ const char *from_name = NULL;
+ struct dbuf_s dbuf;
+
+ for (;;)
+ {
+ if (ic->op == '+')
+ {
+ val += (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ }
+ else if (ic->op == '-')
+ {
+ val -= (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ }
+ else if (IS_CAST_ICODE (ic))
+ {
+ from_type = operandType (IC_RIGHT (ic));
+ from_name = IS_SYMOP (IC_RIGHT (ic)) ? OP_SYMBOL (IC_RIGHT (ic))->name : NULL;
+ aop->aopu.aop_immd.from_cast_remat = 1;
+ ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ dbuf_init (&dbuf, 128);
+ if (val)
+ {
+ dbuf_printf (&dbuf, "(%s %c 0x%04x)", OP_SYMBOL (IC_LEFT (ic))->rname, val >= 0 ? '+' : '-', abs (val) & 0xffff);
+ }
+ else
+ {
+ dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname);
+ }
+
+ aop->aopu.aop_immd.aop_immd1 = dbuf_detach_c_str (&dbuf);
+ /* set immd2 field if required */
+ if (aop->aopu.aop_immd.from_cast_remat)
+ {
+ ptr_type = pointerTypeToGPByte (DCL_TYPE (from_type), from_name, sym->name);
+ dbuf_init (&dbuf, 128);
+ dbuf_tprintf (&dbuf, "#!constbyte", ptr_type);
+ aop->aopu.aop_immd.aop_immd2 = dbuf_detach_c_str (&dbuf);
+ }
+
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* regsInCommon - two operands have some registers in common */
+/*-----------------------------------------------------------------*/
+static bool
+regsInCommon (operand * op1, operand * op2)
+{
+ symbol *sym1, *sym2;
+ int i;
+
+ /* if they have registers in common */
+ if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
+ return FALSE;
+
+ sym1 = OP_SYMBOL (op1);
+ sym2 = OP_SYMBOL (op2);
+
+ if (sym1->nRegs == 0 || sym2->nRegs == 0)
+ return FALSE;
+
+ for (i = 0; i < sym1->nRegs; i++)
+ {
+ int j;
+ if (!sym1->regs[i])
+ continue;
+
+ for (j = 0; j < sym2->nRegs; j++)
+ {
+ if (!sym2->regs[j])
+ continue;
+
+ if (sym2->regs[j] == sym1->regs[i])
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsEqu - equivalent */
+/*-----------------------------------------------------------------*/
+static bool
+operandsEqu (operand * op1, operand * op2)
+{
+ symbol *sym1, *sym2;
+
+ /* if they're not symbols */
+ if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
+ return FALSE;
+
+ sym1 = OP_SYMBOL (op1);
+ sym2 = OP_SYMBOL (op2);
+
+ /* if both are itemps & one is spilt
+ and the other is not then false */
+ if (IS_ITEMP (op1) && IS_ITEMP (op2) && sym1->isspilt != sym2->isspilt)
+ return FALSE;
+
+ /* if they are the same */
+ if (sym1 == sym2)
+ return TRUE;
+
+ /* if they have the same rname */
+ if (sym1->rname[0] && sym2->rname[0] && EQ (sym1->rname, sym2->rname) && !(IS_PARM (op2) && IS_ITEMP (op1)))
+ return TRUE;
+
+ /* if left is a tmp & right is not */
+ if (IS_ITEMP (op1) && !IS_ITEMP (op2) && sym1->isspilt && (sym1->usl.spillLoc == sym2))
+ return TRUE;
+
+ if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (sym2->usl.spillLoc == sym1))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* sameByte - two asmops have the same address at given offsets */
+/*-----------------------------------------------------------------*/
+static bool
+sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
+{
+ if (aop1 == aop2 && off1 == off2)
+ return TRUE;
+
+ if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
+ return FALSE;
+
+ if (aop1->type != aop2->type)
+ return FALSE;
+
+ if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
+ return FALSE;
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* sameRegs - two asmops have the same registers */
+/*-----------------------------------------------------------------*/
+static bool
+sameRegs (asmop * aop1, asmop * aop2)
+{
+ int i;
+
+ if (aop1 == aop2)
+ return TRUE;
+
+ if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
+ return FALSE;
+
+ if (aop1->type != aop2->type)
+ return FALSE;
+
+ if (aop1->size != aop2->size)
+ return FALSE;
+
+ for (i = 0; i < aop1->size; i++)
+ if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopOp - allocates an asmop for an operand : */
+/*-----------------------------------------------------------------*/
+static void
+aopOp (operand * op, iCode * ic, bool result)
+{
+ asmop *aop;
+ symbol *sym;
+ int i;
+
+ if (!op)
+ return;
+
+ /* if this a literal */
+ if (IS_OP_LITERAL (op))
+ {
+ op->aop = aop = newAsmop (AOP_LIT);
+ aop->aopu.aop_lit = OP_VALUE (op);
+ aop->size = getSize (operandType (op));
+ return;
+ }
+
+ /* if already has a asmop then continue */
+ if (op->aop)
+ {
+ op->aop->allocated++;
+ return;
+ }
+
+ /* if the underlying symbol has a aop */
+ if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
+ {
+ op->aop = OP_SYMBOL (op)->aop;
+ op->aop->allocated++;
+ return;
+ }
+
+ /* if this is a true symbol */
+ if (IS_TRUE_SYMOP (op))
+ {
+ op->aop = aopForSym (ic, OP_SYMBOL (op), result);
+ return;
+ }
+
+ /* this is a temporary : this has
+ only five choices :
+ a) register
+ b) spillocation
+ c) rematerialize
+ d) conditional
+ e) can be a return use only */
+
+ sym = OP_SYMBOL (op);
+
+ /* if the type is a conditional */
+ if (sym->regType == REG_CND)
+ {
+ sym->aop = op->aop = aop = newAsmop (AOP_CRY);
+ aop->size = sym->ruonly ? 1 : 0;
+ return;
+ }
+
+ /* if it is spilt then two situations
+ a) is rematerialize
+ b) has a spill location */
+ if (sym->isspilt || sym->nRegs == 0)
+ {
+ /* rematerialize it NOW */
+ if (sym->remat)
+ {
+ sym->aop = op->aop = aop = aopForRemat (sym);
+ aop->size = operandSize (op);
+ return;
+ }
+
+ if (sym->accuse)
+ {
+ int i;
+ sym->aop = op->aop = aop = newAsmop (AOP_ACC);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < 2; i++)
+ aop->aopu.aop_str[i] = accUse[i];
+ return;
+ }
+
+ if (sym->ruonly)
+ {
+ unsigned i;
+
+ sym->aop = op->aop = aop = newAsmop (AOP_STR);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < fReturnSizeMCS51; i++)
+ aop->aopu.aop_str[i] = fReturn[i];
+ return;
+ }
+
+ if (sym->isspilt && sym->usl.spillLoc)
+ {
+ asmop *oldAsmOp = NULL;
+
+ if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
+ {
+ /* force a new aop if sizes differ */
+ oldAsmOp = sym->usl.spillLoc->aop;
+ sym->usl.spillLoc->aop = NULL;
+ }
+ sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, result);
+ if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
+ {
+ /* Don't reuse the new aop, go with the last one */
+ sym->usl.spillLoc->aop = oldAsmOp;
+ }
+ 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;
+ }
+
+ /* if the type is a bit register */
+ if (sym->regType == REG_BIT && sym->regs[0]->type == REG_BIT)
+ {
+ sym->aop = op->aop = aop = newAsmop (AOP_CRY);
+ aop->size = sym->nRegs; //1???
+ aop->aopu.aop_reg[0] = sym->regs[0];
+ aop->aopu.aop_dir = sym->regs[0]->name;
+ return;
+ }
+
+ /* must be in a register */
+ sym->aop = op->aop = aop = newAsmop (AOP_REG);
+ aop->size = sym->nRegs;
+ for (i = 0; i < sym->nRegs; i++)
+ aop->aopu.aop_reg[i] = sym->regs[i];
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAsmop - free up the asmop given to an operand */
+/*-----------------------------------------------------------------*/
+static void
+freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
+{
+ asmop *aop;
+ int sz;
+ symbol *sym;
+
+ if (!op)
+ aop = aaop;
+ else
+ aop = op->aop;
+
+ if (!aop)
+ return;
+
+ aop->allocated--;
+
+ if (aop->allocated)
+ goto dealloc;
+
+ /* depending on the asmop type only three cases need work
+ AOP_R0, AOP_R1 & AOP_STK */
+ switch (aop->type)
+ {
+ case AOP_R0:
+ if (R0INB)
+ {
+ emitcode ("mov", "r0,b");
+ R0INB--;
+ }
+ else if (_G.r0Pushed)
+ {
+ if (pop)
+ {
+ emitpop ("ar0");
+ _G.r0Pushed--;
+ }
+ }
+ bitVectUnSetBit (ic->rUsed, R0_IDX);
+ break;
+
+ case AOP_R1:
+ if (R1INB)
+ {
+ emitcode ("mov", "r1,b");
+ R1INB--;
+ }
+ else if (_G.r1Pushed)
+ {
+ if (pop)
+ {
+ emitpop ("ar1");
+ _G.r1Pushed--;
+ }
+ }
+ bitVectUnSetBit (ic->rUsed, R1_IDX);
+ break;
+
+ case AOP_STK:
+ sz = aop->size;
+ sym = aop->aopu.aop_sym;
+ bitVectUnSetBit (ic->rUsed, R0_IDX);
+ bitVectUnSetBit (ic->rUsed, R1_IDX);
+
+ getFreePtr (ic, aop, FALSE);
+
+ aopPtrForSym (sym, FALSE, aop->size - 1, aop, ic);
+
+ while (sz--)
+ {
+ emitpop ("acc");
+ if (aop->paged)
+ emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
+ else
+ emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
+ if (!sz)
+ break;
+ emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
+ }
+ op->aop = aop;
+ freeAsmop (op, NULL, ic, TRUE);
+ if (_G.r1Pushed)
+ {
+ emitpop ("ar1");
+ _G.r1Pushed--;
+ }
+ if (_G.r0Pushed)
+ {
+ emitpop ("ar0");
+ _G.r0Pushed--;
+ }
+ break;
+ }
+
+dealloc:
+ /* all other cases just dealloc */
+ if (op)
+ {
+ op->aop = NULL;
+ if (IS_SYMOP (op))
+ {
+ OP_SYMBOL (op)->aop = NULL;
+ /* if the symbol has a spill */
+ if (SPIL_LOC (op))
+ SPIL_LOC (op)->aop = NULL;
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* freeForBranchAsmop - partial free up of Asmop for a branch; just */
+/* pop r0 or r1 off stack if pushed */
+/*------------------------------------------------------------------*/
+static void
+freeForBranchAsmop (operand * op, iCode * ic)
+{
+ asmop *aop;
+
+ if (!op)
+ return;
+
+ aop = op->aop;
+
+ if (!aop)
+ return;
+
+ if (!aop->allocated)
+ return;
+
+ switch (aop->type)
+ {
+ case AOP_R0:
+ if (R0INB)
+ {
+ emitcode ("mov", "r0,b");
+ }
+ else if (_G.r0Pushed)
+ {
+ emitcode ("pop", "ar0"); /* without pushed-- */
+ }
+ break;
+
+ case AOP_R1:
+ if (R1INB)
+ {
+ emitcode ("mov", "r1,b");
+ }
+ else if (_G.r1Pushed)
+ {
+ emitcode ("pop", "ar1"); /* without pushed-- */
+ }
+ break;
+
+ case AOP_STK:
+ {
+ int sz = aop->size;
+
+ emitcode ("mov", "b,r0");
+ aopPtrForSym (aop->aopu.aop_sym, FALSE, 0, aop, ic);
+
+ while (sz--)
+ {
+ emitcode ("pop", "acc"); /* without pushed-- */
+ if (aop->paged)
+ emitcode ("movx", "@r0,a");
+ else
+ emitcode ("mov", "@r0,a");
+ if (!sz)
+ break;
+ emitcode ("dec", "r0");
+ }
+ emitcode ("mov", "r0,b");
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* freeForBranchAsmops - partial free up of 3 Asmops for a branch; */
+/* just pop r0 or r1 off stack if pushed */
+/*------------------------------------------------------------------*/
+static void
+freeForBranchAsmops (operand * op1, operand * op2, operand * op3, iCode * ic)
+{
+ if (op1)
+ freeForBranchAsmop (op1, ic);
+ if (op2)
+ freeForBranchAsmop (op2, ic);
+ if (op3)
+ freeForBranchAsmop (op3, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* opIsGptr: returns non-zero if the passed operand is */
+/* a generic pointer type. */
+/*-----------------------------------------------------------------*/
+static int
+opIsGptr (operand * op)
+{
+ if (op && (AOP_SIZE (op) == GPTRSIZE) && (IS_GENPTR (operandType (op)) || IFFUNC_ISBANKEDCALL (operandType (op))))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* swapOperands - swap two operands */
+/*-----------------------------------------------------------------*/
+static void
+swapOperands (operand ** left, operand ** right)
+{
+ operand *t = *right;
+ *right = *left;
+ *left = t;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopGetUsesAcc - indicates ahead of time whether aopGet() will */
+/* clobber the accumulator */
+/*-----------------------------------------------------------------*/
+static bool
+aopGetUsesAcc (operand * oper, int offset)
+{
+ asmop *aop = AOP (oper);
+
+ if (offset > (aop->size - 1))
+ return FALSE;
+
+ switch (aop->type)
+ {
+
+ case AOP_R0:
+ case AOP_R1:
+ if (aop->paged)
+ return TRUE;
+ return FALSE;
+ case AOP_DPTR:
+ return TRUE;
+ case AOP_IMMD:
+ return FALSE;
+ case AOP_DIR:
+ return FALSE;
+ case AOP_REG:
+ wassert (!EQ (aop->aopu.aop_reg[offset]->name, "a"));
+ return FALSE;
+ case AOP_CRY:
+ return TRUE;
+ case AOP_ACC:
+ if (offset)
+ return FALSE;
+ return TRUE;
+ case AOP_LIT:
+ return FALSE;
+ case AOP_STR:
+ if (EQ (aop->aopu.aop_str[offset], "a"))
+ return TRUE;
+ return FALSE;
+ case AOP_DUMMY:
+ return FALSE;
+ default:
+ /* Error case --- will have been caught already */
+ wassert (0);
+ return FALSE;
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* aopGet - for fetching value of the aop */
+/*-------------------------------------------------------------------*/
+/*
+ * NOTE: function returns a pointer to a reusable dynamically allocated
+ * buffer, which should never be freed!
+ * Subsequent call to aopGet() will rewrite the result of the previous
+ * call, so the content of the result should be copied to an other
+ * location, usually using Safe_strdup(), in order to perserve it.
+ */
+static const char *
+aopGet (operand * oper, int offset, bool bit16, bool dname)
+{
+ asmop *aop = AOP (oper);
+ static struct dbuf_s dbuf = { 0 };
+
+ if (dbuf_is_initialized (&dbuf))
+ {
+ /* reuse the dynamically allocated buffer */
+ dbuf_set_length (&dbuf, 0);
+ }
+ else
+ {
+ /* first time: initialize the dynamically allocated buffer */
+ dbuf_init (&dbuf, 128);
+ }
+
+ /* offset is greater than
+ size then zero */
+ if (offset > (aop->size - 1) && aop->type != AOP_LIT)
+ {
+ dbuf_append_str (&dbuf, zero);
+ }
+ else
+ {
+ /* depending on type */
+ switch (aop->type)
+ {
+ case AOP_DUMMY:
+ dbuf_append_str (&dbuf, zero);
+ break;
+
+ case AOP_R0:
+ case AOP_R1:
+ /* if we need to increment it */
+ while (offset > aop->coff)
+ {
+ emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
+ aop->coff++;
+ }
+
+ while (offset < aop->coff)
+ {
+ emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
+ aop->coff--;
+ }
+
+ aop->coff = offset;
+ if (aop->paged)
+ {
+ emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
+ dbuf_append_str (&dbuf, dname ? "acc" : "a");
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "@%s", aop->aopu.aop_ptr->name);
+ }
+ break;
+
+ case AOP_DPTR:
+ if (aop->code && aop->coff == 0 && offset >= 1)
+ {
+ emitcode ("mov", "a,#0x%02x", offset);
+ emitcode ("movc", "a,@a+dptr");
+ }
+ else
+ {
+ while (offset > aop->coff)
+ {
+ emitcode ("inc", "dptr");
+ aop->coff++;
+ }
+
+ while (offset < aop->coff)
+ {
+ emitcode ("lcall", "__decdptr");
+ aop->coff--;
+ }
+
+ aop->coff = offset;
+ if (aop->code)
+ {
+ emitcode ("clr", "a");
+ emitcode ("movc", "a,@a+dptr");
+ }
+ else
+ {
+ emitcode ("movx", "a,@dptr");
+ }
+ }
+ dbuf_append_str (&dbuf, dname ? "acc" : "a");
+ break;
+
+ case AOP_IMMD:
+ if (aop->aopu.aop_immd.from_cast_remat && opIsGptr (oper) && offset == GPTRSIZE - 1)
+ {
+ dbuf_printf (&dbuf, "%s", aop->aopu.aop_immd.aop_immd2);
+ }
+ else if (bit16)
+ {
+ dbuf_printf (&dbuf, "#%s", aop->aopu.aop_immd.aop_immd1);
+ }
+ else if (offset)
+ {
+ dbuf_printf (&dbuf, "#(%s >> %d)", aop->aopu.aop_immd.aop_immd1, offset * 8);
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "#%s", aop->aopu.aop_immd.aop_immd1);
+ }
+ break;
+
+ case AOP_DIR:
+ if ((SPEC_SCLS (getSpec (operandType (oper))) == S_SFR) && (aop->size > 1))
+ {
+ dbuf_printf (&dbuf, "((%s >> %d) & 0xFF)", aop->aopu.aop_dir, offset * 8);
+ }
+ else if (offset)
+ {
+ dbuf_printf (&dbuf, "(%s + %d)", aop->aopu.aop_dir, offset);
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "%s", aop->aopu.aop_dir);
+ }
+ break;
+
+ case AOP_REG:
+ dbuf_append_str (&dbuf, dname ? aop->aopu.aop_reg[offset]->dname : aop->aopu.aop_reg[offset]->name);
+ break;
+
+ case AOP_CRY:
+ if (!IS_OP_RUONLY (oper))
+ emitcode ("mov", "c,%s", aop->aopu.aop_dir);
+ emitcode ("clr", "a");
+ emitcode ("rlc", "a");
+ dbuf_append_str (&dbuf, dname ? "acc" : "a");
+ break;
+
+ case AOP_ACC:
+ dbuf_append_str (&dbuf, (!offset && dname) ? "acc" : aop->aopu.aop_str[offset]);
+ break;
+
+ case AOP_LIT:
+ if (opIsGptr (oper) && IS_FUNCPTR (operandType (oper)) && offset == GPTRSIZE - 1)
+ {
+ dbuf_append_str (&dbuf, aopLiteralGptr (NULL, aop->aopu.aop_lit));
+ }
+ else
+ {
+ int size = 1 + (bit16 ? 1 : 0);
+ dbuf_append_str (&dbuf, aopLiteralLong (aop->aopu.aop_lit, offset, size));
+ }
+ break;
+
+ case AOP_STR:
+ aop->coff = offset;
+ if (EQ (aop->aopu.aop_str[offset], "a") && dname)
+ dbuf_append_str (&dbuf, "acc");
+ else
+ dbuf_append_str (&dbuf, aop->aopu.aop_str[offset]);
+ break;
+
+ default:
+ dbuf_destroy (&dbuf);
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopget got unsupported aop->type");
+ exit (EXIT_FAILURE);
+ }
+ }
+ return dbuf_c_str (&dbuf);
+}
+
+/*-----------------------------------------------------------------*/
+/* aopPutUsesAcc - indicates ahead of time whether aopPut() will */
+/* clobber the accumulator */
+/*-----------------------------------------------------------------*/
+static bool
+aopPutUsesAcc (operand * oper, const char *s, int offset)
+{
+ asmop *aop = AOP (oper);
+
+ if (offset > (aop->size - 1))
+ return FALSE;
+
+ switch (aop->type)
+ {
+ case AOP_DUMMY:
+ return TRUE;
+ case AOP_DIR:
+ return FALSE;
+ case AOP_REG:
+ wassert (!EQ (aop->aopu.aop_reg[offset]->name, "a"));
+ return FALSE;
+ case AOP_DPTR:
+ return TRUE;
+ case AOP_R0:
+ case AOP_R1:
+ return ((aop->paged) || (*s == '@'));
+ case AOP_STK:
+ return (*s == '@');
+ case AOP_CRY:
+ return (!aop->aopu.aop_dir || !EQ (s, aop->aopu.aop_dir));
+ case AOP_STR:
+ return FALSE;
+ case AOP_IMMD:
+ return FALSE;
+ case AOP_ACC:
+ return FALSE;
+ default:
+ /* Error case --- will have been caught already */
+ wassert (0);
+ return FALSE;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* aopPut - puts a string for a aop and indicates if acc is in use */
+/*-----------------------------------------------------------------*/
+static bool
+aopPut (operand * result, const char *s, int offset)
+{
+ bool bvolatile = isOperandVolatile (result, FALSE);
+ bool accuse = FALSE;
+ asmop *aop = AOP (result);
+ const char *d = NULL;
+ static struct dbuf_s dbuf = { 0 };
+
+ if (dbuf_is_initialized (&dbuf))
+ {
+ /* reuse the dynamically allocated buffer */
+ dbuf_set_length (&dbuf, 0);
+ }
+ else
+ {
+ /* first time: initialize the dynamically allocated buffer */
+ dbuf_init (&dbuf, 128);
+ }
+
+ if (aop->size && offset > (aop->size - 1))
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got offset > aop->size");
+ exit (EXIT_FAILURE);
+ }
+
+ /* will assign value to value */
+ /* depending on where it is ofcourse */
+ switch (aop->type)
+ {
+ case AOP_DUMMY:
+ MOVA (s); /* read s in case it was volatile */
+ accuse = TRUE;
+ break;
+
+ case AOP_DIR:
+ if ((SPEC_SCLS (getSpec (operandType (result))) == S_SFR) && (aop->size > 1))
+ {
+ dbuf_printf (&dbuf, "((%s >> %d) & 0xFF)", aop->aopu.aop_dir, offset * 8);
+ }
+ else if (offset)
+ {
+ dbuf_printf (&dbuf, "(%s + %d)", aop->aopu.aop_dir, offset);
+ }
+ else
+ {
+ dbuf_append_str (&dbuf, aop->aopu.aop_dir);
+ }
+
+ if (!EQ (dbuf_c_str (&dbuf), s) || bvolatile)
+ {
+ emitcode ("mov", "%s,%s", dbuf_c_str (&dbuf), s);
+ }
+ if (EQ (dbuf_c_str (&dbuf), "acc"))
+ {
+ accuse = TRUE;
+ }
+ break;
+
+ case AOP_REG:
+ if (!EQ (aop->aopu.aop_reg[offset]->name, s) && !EQ (aop->aopu.aop_reg[offset]->dname, s))
+ {
+ if (*s == '@' ||
+ EQ (s, "r0") || EQ (s, "r1") || EQ (s, "r2") || EQ (s, "r3") ||
+ EQ (s, "r4") || EQ (s, "r5") || EQ (s, "r6") || EQ (s, "r7"))
+ {
+ emitcode ("mov", "%s,%s", aop->aopu.aop_reg[offset]->dname, s);
+ }
+ else
+ {
+ emitcode ("mov", "%s,%s", aop->aopu.aop_reg[offset]->name, s);
+ }
+ }
+ break;
+
+ case AOP_DPTR:
+ if (aop->code)
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut writing to code space");
+ exit (EXIT_FAILURE);
+ }
+
+ /* if not in accumulator */
+ MOVA (s);
+
+ while (offset > aop->coff)
+ {
+ aop->coff++;
+ emitcode ("inc", "dptr");
+ }
+
+ while (offset < aop->coff)
+ {
+ aop->coff--;
+ emitcode ("lcall", "__decdptr");
+ }
+
+ aop->coff = offset;
+
+ emitcode ("movx", "@dptr,a");
+ break;
+
+ case AOP_R0:
+ case AOP_R1:
+ while (offset > aop->coff)
+ {
+ aop->coff++;
+ emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
+ }
+ while (offset < aop->coff)
+ {
+ aop->coff--;
+ emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
+ }
+ aop->coff = offset;
+
+ if (aop->paged)
+ {
+ MOVA (s);
+ emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
+ }
+ else if (*s == '@')
+ {
+ MOVA (s);
+ emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
+ }
+ else if (EQ (s, "r0") || EQ (s, "r1") || EQ (s, "r2") || EQ (s, "r3") ||
+ EQ (s, "r4") || EQ (s, "r5") || EQ (s, "r6") || EQ (s, "r7"))
+ {
+ dbuf_printf (&dbuf, "a%s", s);
+ emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, dbuf_c_str (&dbuf));
+ }
+ else
+ {
+ emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
+ }
+ break;
+
+ case AOP_STK:
+ emitpush (s);
+ break;
+
+ case AOP_CRY:
+ // destination is carry for return-use-only
+ d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
+
+ // source is no literal and not in carry
+ if (!EQ (s, zero) && !EQ (s, one) && !EQ (s, "c"))
+ {
+ MOVA (s);
+ /* set C, if a >= 1 */
+ emitcode ("add", "a,#!constbyte", 0xff);
+ s = "c";
+ }
+ // now source is zero, one or carry
+
+ /* if result no bit variable */
+ if (!d)
+ {
+ if (EQ (s, "c"))
+ {
+ /* inefficient: move carry into A and use jz/jnz */
+ emitcode ("clr", "a");
+ emitcode ("rlc", "a");
+ accuse = TRUE;
+ }
+ else
+ {
+ MOVA (s);
+ accuse = TRUE;
+ }
+ }
+ else if (EQ (s, zero))
+ emitcode ("clr", "%s", d);
+ else if (EQ (s, one))
+ emitcode ("setb", "%s", d);
+ else if (!EQ (s, d))
+ emitcode ("mov", "%s,c", d);
+ break;
+
+ case AOP_STR:
+ aop->coff = offset;
+ if (!EQ (aop->aopu.aop_str[offset], s) || bvolatile)
+ emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
+ break;
+
+ case AOP_ACC:
+ accuse = TRUE;
+ aop->coff = offset;
+ if (!offset && EQ (s, "acc") && !bvolatile)
+ break;
+
+ if (!EQ (aop->aopu.aop_str[offset], s) && !bvolatile)
+ emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
+ break;
+
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type");
+ exit (EXIT_FAILURE);
+ }
+
+ return accuse;
+}
+
+/*--------------------------------------------------------------------*/
+/* loadDptrFromOperand - load dptr (and optionally B) from operand op */
+/*--------------------------------------------------------------------*/
+static void
+loadDptrFromOperand (operand *op, bool loadBToo)
+{
+ if (AOP_TYPE (op) != AOP_STR)
+ {
+ /* if this is rematerializable */
+ if (AOP_TYPE (op) == AOP_IMMD)
+ {
+ emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
+ if (loadBToo)
+ {
+ if (AOP (op)->aopu.aop_immd.from_cast_remat)
+ emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE));
+ else
+ {
+ wassertl (FALSE, "need pointerCode");
+ emitcode (";", "mov b,???");
+ /* genPointerGet and genPointerSet originally did different
+ ** things for this case. Both seem wrong.
+ ** from genPointerGet:
+ ** emitcode ("mov", "b,#%d", pointerCode (retype));
+ ** from genPointerSet:
+ ** emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
+ */
+ }
+ }
+ }
+ else if (AOP_TYPE (op) == AOP_LIT)
+ {
+ emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
+ if (loadBToo)
+ emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (op) == AOP_DPTR)
+ {
+ emitpush (aopGet (op, 0, FALSE, FALSE));
+ if (loadBToo)
+ {
+ emitpush (aopGet (op, 1, FALSE, FALSE));
+ emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE));
+ emitpop ("dph");
+ }
+ else
+ {
+ emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
+ }
+ emitpop ("dpl");
+ }
+ else
+ {
+ /* we need to get it byte by byte */
+ emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
+ emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
+ if (loadBToo)
+ emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE));
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* reAdjustPreg - points a register back to where it should */
+/*-----------------------------------------------------------------*/
+static void
+reAdjustPreg (asmop * aop)
+{
+ if ((aop->coff == 0) || (aop->size <= 1))
+ return;
+
+ switch (aop->type)
+ {
+ case AOP_R0:
+ case AOP_R1:
+ while (aop->coff--)
+ emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
+ break;
+ case AOP_DPTR:
+ while (aop->coff--)
+ {
+ emitcode ("lcall", "__decdptr");
+ }
+ break;
+ }
+ aop->coff = 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* getDataSize - get the operand data size */
+/*-----------------------------------------------------------------*/
+static int
+getDataSize (operand * op)
+{
+ int size = AOP_SIZE (op);
+
+ if (size == GPTRSIZE)
+ {
+ sym_link *type = operandType (op);
+ if (IS_GENPTR (type))
+ {
+ /* generic pointer; arithmetic operations
+ * should ignore the high byte (pointer type).
+ */
+ size--;
+ }
+ }
+ return size;
+}
+
+/*-----------------------------------------------------------------*/
+/* outAcc - output Acc */
+/*-----------------------------------------------------------------*/
+static void
+outAcc (operand * result)
+{
+ int size, offset;
+ size = getDataSize (result);
+ if (size)
+ {
+ aopPut (result, "a", 0);
+ size--;
+ offset = 1;
+ /* unsigned or positive */
+ while (size--)
+ {
+ aopPut (result, zero, offset++);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitC - output a bit C */
+/*-----------------------------------------------------------------*/
+static void
+outBitC (operand * result)
+{
+ /* if the result is bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if (!IS_OP_RUONLY (result) && !IS_OP_ACCUSE (result))
+ aopPut (result, "c", 0);
+ }
+ else if (AOP_TYPE (result) != AOP_DUMMY)
+ {
+ emitcode ("clr", "a");
+ emitcode ("rlc", "a");
+ outAcc (result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* toBoolean - emit code for orl a,operator(sizeop) */
+/*-----------------------------------------------------------------*/
+static void
+toBoolean (operand * oper)
+{
+ int size = AOP_SIZE (oper) - 1;
+ int offset = 1;
+ bool AccUsed;
+ sym_link *type = operandType (oper);
+ bool pushedB;
+
+ /* always need B for float */
+ AccUsed = IS_FLOAT (type);
+
+ while (!AccUsed && size--)
+ {
+ AccUsed |= aopGetUsesAcc (oper, offset++);
+ }
+
+ if (opIsGptr (oper))
+ {
+ /* assumes that banks never map to address 0x0000
+ so it suffices to check dptr part only and ignore b */
+ size = AOP_SIZE (oper) - 2;
+ }
+ else
+ {
+ size = AOP_SIZE (oper) - 1;
+ }
+
+ offset = 0;
+ if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
+ {
+ pushedB = pushB ();
+ MOVB (aopGet (oper, offset++, FALSE, FALSE));
+ while (--size)
+ {
+ MOVA (aopGet (oper, offset++, FALSE, FALSE));
+ emitcode ("orl", "b,a");
+ }
+ MOVA (aopGet (oper, offset++, FALSE, FALSE));
+ if (IS_FLOAT (type))
+ emitcode ("anl", "a,#0x7F"); //clear sign bit
+ emitcode ("orl", "a,b");
+ popB (pushedB);
+ }
+ else
+ {
+ MOVA (aopGet (oper, offset++, FALSE, FALSE));
+ while (size--)
+ {
+ emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* toCarry - make boolean and move into carry */
+/*-----------------------------------------------------------------*/
+static void
+toCarry (operand *oper)
+{
+ /* if the operand is a literal then
+ we know what the value is */
+ if (AOP_TYPE (oper) == AOP_LIT)
+ {
+ if ((int) operandLitValue (oper))
+ SETC;
+ else
+ CLRC;
+ }
+ else if (AOP_TYPE (oper) == AOP_CRY)
+ {
+ if (!IS_OP_ACCUSE (oper))
+ emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
+ }
+ else if (IS_BOOL (operandType (oper)) || IS_BITFIELD (operandType (oper)) && SPEC_BLEN (getSpec (operandType (oper))) == 1)
+ {
+ MOVA (aopGet (oper, 0, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ }
+ else
+ {
+ /* or the operand into a */
+ toBoolean (oper);
+ /* set C, if a >= 1 */
+ emitcode ("add", "a,#0xff");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignBit - assign operand to bit operand */
+/*-----------------------------------------------------------------*/
+static void
+assignBit (operand * result, operand * right)
+{
+ emitcode (";", "assignBit");
+ /* if the right side is a literal then
+ we know what the value is */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((int) operandLitValue (right))
+ aopPut (result, one, 0);
+ else
+ aopPut (result, zero, 0);
+ }
+ else
+ {
+ toCarry (right);
+ outBitC (result);
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* xch_a_aopGet - for exchanging acc with value of the aop */
+/*-------------------------------------------------------------------*/
+static const char *
+xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
+{
+ const char *l;
+
+ if (aopGetUsesAcc (oper, offset))
+ {
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (oper, offset, bit16, dname));
+ emitcode ("xch", "a,b");
+ aopPut (oper, "a", offset);
+ emitcode ("xch", "a,b");
+ l = "b";
+ }
+ else
+ {
+ l = aopGet (oper, offset, bit16, dname);
+ emitcode ("xch", "a,%s", l);
+ }
+ return l;
+}
+
+/*-----------------------------------------------------------------*/
+/* genNot - generate code for ! operation */
+/*-----------------------------------------------------------------*/
+static void
+genNot (iCode * ic)
+{
+ symbol *tlbl;
+
+ D (emitcode (";", "genNot"));
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* if in bit space then a special case */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+ {
+ /* if left==result then cpl bit */
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+ }
+ else
+ {
+ toCarry (IC_LEFT (ic));
+ emitcode ("cpl", "c");
+ outBitC (IC_RESULT (ic));
+ }
+ goto release;
+ }
+
+ toBoolean (IC_LEFT (ic));
+
+ /* set C, if a == 0 */
+ tlbl = newiTempLabel (NULL);
+ emitcode ("cjne", "a,#0x01,!tlabel", labelKey2num (tlbl->key));
+ emitLabel (tlbl);
+ outBitC (IC_RESULT (ic));
+
+release:
+ /* release the aops */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+}
+
+/*-----------------------------------------------------------------*/
+/* genCpl - generate code for complement */
+/*-----------------------------------------------------------------*/
+static void
+genCpl (iCode * ic)
+{
+ int offset = 0;
+ int size;
+ symbol *tlbl;
+ sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
+
+ D (emitcode (";", "genCpl"));
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* special case if in bit space */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+ {
+ const char *l;
+
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY || (SPEC_USIGN (letype) && IS_CHAR (letype)))
+ {
+ /* promotion rules are responsible for this strange result:
+ bit -> int -> ~int -> bit
+ uchar -> int -> ~int -> bit
+ */
+ emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
+ goto release;
+ }
+
+ tlbl = newiTempLabel (NULL);
+ l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
+ AOP_TYPE (IC_LEFT (ic)) == AOP_REG || IS_AOP_PREG (IC_LEFT (ic)))
+ {
+ emitcode ("cjne", "%s,#0xFF,!tlabel", l, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ MOVA (l);
+ emitcode ("cjne", "a,#0xFF,!tlabel", labelKey2num (tlbl->key));
+ }
+ emitLabel (tlbl);
+ outBitC (IC_RESULT (ic));
+ goto release;
+ }
+
+ size = AOP_SIZE (IC_RESULT (ic));
+ while (size--)
+ {
+ MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
+ emitcode ("cpl", "a");
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+
+release:
+ /* release the aops */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+ int size, offset = 0;
+
+ D (emitcode (";", "genUminusFloat"));
+
+ /* for this we just copy and then flip the bit */
+
+ size = AOP_SIZE (op) - 1;
+
+ while (size--)
+ {
+ aopPut (result, aopGet (op, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+
+ MOVA (aopGet (op, offset, FALSE, FALSE));
+
+ emitcode ("cpl", "acc.7");
+ aopPut (result, "a", offset);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminus - unary minus code generation */
+/*-----------------------------------------------------------------*/
+static void
+genUminus (iCode * ic)
+{
+ int offset, size;
+ sym_link *optype;
+
+ D (emitcode (";", "genUminus"));
+
+ /* assign asmops */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* if both in bit space then special
+ case */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+ {
+
+ emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+ emitcode ("cpl", "c");
+ emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
+ goto release;
+ }
+
+ optype = operandType (IC_LEFT (ic));
+
+ /* if float then do float stuff */
+ if (IS_FLOAT (optype))
+ {
+ genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
+ goto release;
+ }
+
+ /* otherwise subtract from zero */
+ size = AOP_SIZE (IC_LEFT (ic));
+ offset = 0;
+ while (size--)
+ {
+ const char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
+ if (EQ (l, "a"))
+ {
+ if (offset == 0)
+ SETC;
+ emitcode ("cpl", "a");
+ emitcode ("addc", "a,#0x00");
+ }
+ else
+ {
+ if (offset == 0)
+ CLRC;
+ emitcode ("clr", "a");
+ emitcode ("subb", "a,%s", l);
+ }
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+
+ /* if any remaining bytes in the result */
+ /* we just need to propagate the sign */
+ if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
+ {
+ emitcode ("rlc", "a");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+
+release:
+ /* release the aops */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+}
+
+/*-----------------------------------------------------------------*/
+/* inExcludeList - return 1 if the string is in exclude Reg list */
+/*-----------------------------------------------------------------*/
+static int
+regsCmp (void *p1, void *p2)
+{
+ return (STRCASECMP ((char *) p1, (char *) (p2)) == 0);
+}
+
+static bool
+inExcludeList (char *s)
+{
+ const char *p = setFirstItem (options.excludeRegsSet);
+
+ if (p == NULL || STRCASECMP (p, "none") == 0)
+ return FALSE;
+
+ return isinSetWith (options.excludeRegsSet, s, regsCmp);
+}
+
+/*-----------------------------------------------------------------*/
+/* xstackRegisters - create bitmask for registers on xstack */
+/*-----------------------------------------------------------------*/
+static int
+xstackRegisters (bitVect * rsave, bool push, int count, char szRegs[32])
+{
+ int i;
+ int mask = 0;
+
+ szRegs[0] = '\0';
+
+ for (i = mcs51_nRegs; i >= 0; i--)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ reg_info *reg = REG_WITH_INDEX (i);
+ if (reg->type == REG_BIT)
+ {
+ mask |= 0x01;
+ strncat (szRegs, reg->base, 31);
+ }
+ else
+ {
+ if (i == R0_IDX)
+ {
+ mask |= 0x100;
+ }
+ else
+ {
+ //set bit(n) for Rn
+ mask |= (0x01 << reg->offset);
+ }
+ strncat (szRegs, reg->name, 31);
+ }
+ }
+ }
+ return mask ^ 0xFF; //invert all bits for jbc
+}
+
+/*-----------------------------------------------------------------*/
+/* saveRegisters - will look for a call and save the registers */
+/*-----------------------------------------------------------------*/
+static void
+saveRegisters (iCode * lic)
+{
+ int i;
+ iCode *ic;
+ bitVect *rsave;
+
+ /* look for call */
+ for (ic = lic; ic; ic = ic->next)
+ if (ic->op == CALL || ic->op == PCALL)
+ break;
+
+ if (!ic)
+ {
+ fprintf (stderr, "found parameter push with no function call\n");
+ return;
+ }
+
+ /* if the registers have been saved already or don't need to be then
+ do nothing */
+ if (ic->regsSaved)
+ return;
+ if (IS_SYMOP (IC_LEFT (ic)))
+ {
+ sym_link *type = OP_SYM_TYPE (IC_LEFT (ic));
+ if (IFFUNC_ISNAKED (type) && !IFFUNC_ISBANKEDCALL (type))
+ return;
+ if (IFFUNC_CALLEESAVES (type))
+ return;
+ }
+
+ if (IFFUNC_CALLEESAVES (_G.currentFunc->type))
+ {
+ /* save all registers if the caller is callee_saves and the callee is not */
+ rsave = bitVectCopy (mcs51_allBankregs ());
+ if (!inExcludeList ("bits"))
+ {
+ rsave = bitVectUnion (rsave, mcs51_allBitregs ());
+ BitBankUsed = 1;
+ }
+ }
+ else
+ /* save only the registers in use at this time */
+ rsave = bitVectCopy (ic->rMask);
+ /* but skip the ones for the result */
+ rsave = bitVectCplAnd (rsave, mcs51_rUmaskForOp (IC_RESULT (ic)));
+
+ ic->regsSaved = 1;
+ if (options.useXstack)
+ {
+ bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
+ int nBits = bitVectnBitsOn (rsavebits);
+ int count = bitVectnBitsOn (rsave);
+
+ if (nBits != 0)
+ {
+ count = count - nBits + 1;
+ /* remove all but the first bits as they are pushed all at once */
+ rsave = bitVectCplAnd (rsave, rsavebits);
+ rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
+ }
+ freeBitVect (rsavebits);
+
+ if (count == 1)
+ {
+ reg_info *reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
+ emitpush (REG_WITH_INDEX (R0_IDX)->dname);
+ if (reg->type == REG_BIT)
+ {
+ emitcode ("mov", "a,%s", reg->base);
+ }
+ else
+ {
+ emitcode ("mov", "a,%s", reg->name);
+ }
+ emitcode ("mov", "r0,%s", spname);
+ emitcode ("inc", "%s", spname); // allocate before use
+ emitcode ("movx", "@r0,a");
+ _G.stack.xpushed++;
+ emitpop (REG_WITH_INDEX (R0_IDX)->dname);
+ }
+ else if (count != 0)
+ {
+ if ((FUNC_REGBANK (currFunc->type) == 0) && optimize.codeSize)
+ {
+ char szRegs[32];
+ int mask = xstackRegisters (rsave, TRUE, count, szRegs);
+ if (BINUSE)
+ emitpush ("b");
+ emitcode ("mov", "a,#0x%02x", count);
+ emitcode ("mov", "b,#0x%02x", mask & 0xFF);
+ if (mask & 0x100)
+ emitcode ("lcall", "___sdcc_xpush_regs_r0\t;(%s)", szRegs);
+ else
+ emitcode ("lcall", "___sdcc_xpush_regs\t;(%s)", szRegs);
+ genLine.lineCurr->isInline = 1;
+ if (BINUSE)
+ emitpop ("b");
+ _G.stack.xpushed += count;
+ }
+ else
+ {
+ emitpush (REG_WITH_INDEX (R0_IDX)->dname);
+ emitcode ("mov", "r0,%s", spname);
+ if (count == 2)
+ {
+ emitcode ("inc", "%s", spname);
+ emitcode ("inc", "%s", spname);
+ }
+ else
+ {
+ MOVA ("r0");
+ emitcode ("add", "a,#0x%02x", count);
+ emitcode ("mov", "%s,a", spname);
+ }
+ for (i = 0; i < mcs51_nRegs; i++)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ reg_info *reg = REG_WITH_INDEX (i);
+ if (i == R0_IDX)
+ {
+ emitpop ("acc");
+ emitpush ("acc");
+ }
+ else if (reg->type == REG_BIT)
+ {
+ emitcode ("mov", "a,%s", reg->base);
+ }
+ else
+ {
+ emitcode ("mov", "a,%s", reg->name);
+ }
+ emitcode ("movx", "@r0,a");
+ _G.stack.xpushed++;
+ if (--count)
+ {
+ emitcode ("inc", "r0");
+ }
+ }
+ }
+ emitpop (REG_WITH_INDEX (R0_IDX)->dname);
+ }
+ }
+ }
+ else
+ {
+ bool bits_pushed = FALSE;
+ for (i = 0; i < mcs51_nRegs; i++)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ bits_pushed = pushReg (i, bits_pushed);
+ }
+ }
+ }
+ freeBitVect (rsave);
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaveRegisters - pop the pushed registers */
+/*-----------------------------------------------------------------*/
+static void
+unsaveRegisters (iCode * ic)
+{
+ int i;
+ bitVect *rsave;
+
+ if (IFFUNC_CALLEESAVES (_G.currentFunc->type))
+ {
+ /* restore all registers if the caller is callee_saves and the callee is not */
+ rsave = bitVectCopy (mcs51_allBankregs ());
+ if (!inExcludeList ("bits"))
+ {
+ rsave = bitVectUnion (rsave, mcs51_allBitregs ());
+ BitBankUsed = 1;
+ }
+ }
+ else
+ /* restore only the registers in use at this time */
+ rsave = bitVectCopy (ic->rMask);
+ /* but skip the ones for the result */
+ rsave = bitVectCplAnd (rsave, mcs51_rUmaskForOp (IC_RESULT (ic)));
+
+ if (options.useXstack)
+ {
+ bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
+ int nBits = bitVectnBitsOn (rsavebits);
+ int count = bitVectnBitsOn (rsave);
+
+ if (nBits != 0)
+ {
+ count = count - nBits + 1;
+ /* remove all but the first bits as they are popped all at once */
+ rsave = bitVectCplAnd (rsave, rsavebits);
+ rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
+ }
+ freeBitVect (rsavebits);
+
+ if (count == 1)
+ {
+ reg_info *reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
+ emitcode ("mov", "r0,%s", spname);
+ emitcode ("dec", "r0");
+ emitcode ("movx", "a,@r0");
+ _G.stack.xpushed--;
+ if (reg->type == REG_BIT)
+ {
+ emitcode ("mov", "%s,a", reg->base);
+ }
+ else
+ {
+ emitcode ("mov", "%s,a", reg->name);
+ }
+ emitcode ("dec", "%s", spname);
+ }
+ else if (count != 0)
+ {
+ if ((FUNC_REGBANK (currFunc->type) == 0) && optimize.codeSize)
+ {
+ char szRegs[32];
+ int mask = xstackRegisters (rsave, FALSE, count, szRegs);
+ emitcode ("mov", "b,#0x%02x", mask & 0xFF);
+ if (mask & 0x100)
+ emitcode ("lcall", "___sdcc_xpop_regs_r0\t;(%s)", szRegs);
+ else
+ emitcode ("lcall", "___sdcc_xpop_regs\t;(%s)", szRegs);
+ genLine.lineCurr->isInline = 1;
+ _G.stack.xpushed -= count;
+ }
+ else
+ {
+ bool resultInR0 = bitVectBitValue (mcs51_rUmaskForOp (IC_RESULT (ic)), R0_IDX);
+ if (resultInR0)
+ {
+ emitpush (REG_WITH_INDEX (R0_IDX)->dname);
+ }
+ emitcode ("mov", "r0,%s", spname);
+ for (i = mcs51_nRegs; i >= 0; i--)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ reg_info *reg = REG_WITH_INDEX (i);
+ emitcode ("dec", "r0");
+ emitcode ("movx", "a,@r0");
+ _G.stack.xpushed--;
+ if (i == R0_IDX)
+ {
+ emitpush ("acc");
+ }
+ else if (reg->type == REG_BIT)
+ {
+ emitcode ("mov", "%s,a", reg->base);
+ }
+ else
+ {
+ emitcode ("mov", "%s,a", reg->name);
+ }
+ }
+ }
+ emitcode ("mov", "%s,r0", spname);
+ if (bitVectBitValue (rsave, R0_IDX) || resultInR0)
+ {
+ emitpop (REG_WITH_INDEX (R0_IDX)->dname);
+ }
+ }
+ }
+ }
+ else
+ {
+ bool bits_popped = FALSE;
+ for (i = mcs51_nRegs; i >= 0; i--)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ bits_popped = popReg (i, bits_popped);
+ }
+ }
+ }
+ freeBitVect (rsave);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* pushSide - */
+/*-----------------------------------------------------------------*/
+static void
+pushSide (operand * oper, int size, iCode * ic)
+{
+ int offset = 0;
+ int nPushed = _G.r0Pushed + _G.r1Pushed;
+
+ aopOp (oper, ic, FALSE);
+
+ if (nPushed != _G.r0Pushed + _G.r1Pushed)
+ {
+ while (offset < size)
+ {
+ const char *l = aopGet (oper, offset, FALSE, TRUE);
+ emitcode ("mov", "%s,%s", fReturn[offset++], l);
+ }
+ freeAsmop (oper, NULL, ic, TRUE);
+ offset = 0;
+ while (offset < size)
+ {
+ emitpush (fReturn[offset++]);
+ }
+ return;
+ }
+
+ while (size--)
+ {
+ const char *l = aopGet (oper, offset++, FALSE, TRUE);
+ if (AOP_TYPE (oper) != AOP_REG && AOP_TYPE (oper) != AOP_DIR)
+ {
+ MOVA (l);
+ emitpush ("acc");
+ }
+ else
+ {
+ emitpush (l);
+ }
+ }
+
+ freeAsmop (oper, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* assignResultValue - also indicates if acc is in use afterwards */
+/*-----------------------------------------------------------------*/
+static bool
+assignResultValue (operand * oper, operand * func)
+{
+ int offset = 0;
+ int size = AOP_SIZE (oper);
+ bool accuse = FALSE;
+ bool pushedA = FALSE;
+
+ if (func && IS_BIT (getSpec (operandType (func))))
+ {
+ outBitC (oper);
+ return FALSE;
+ }
+ if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
+ {
+ emitpush ("acc");
+ pushedA = TRUE;
+ }
+ while (size--)
+ {
+ if ((offset == 3) && pushedA)
+ emitpop ("acc");
+ accuse |= aopPut (oper, fReturn[offset], offset);
+ offset++;
+ }
+ return accuse;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genXpush - pushes onto the external stack */
+/*-----------------------------------------------------------------*/
+static void
+genXpush (iCode * ic)
+{
+ asmop *aop = newAsmop (0);
+ reg_info *r;
+ int size, offset = 0;
+
+ D (emitcode (";", "genXpush"));
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ r = getFreePtr (ic, aop, FALSE);
+
+ size = AOP_SIZE (IC_LEFT (ic));
+ emitcode ("mov", "%s,%s", r->name, spname);
+
+ // allocate space first
+ if (size <= 2)
+ {
+ emitcode ("inc", "%s", spname);
+ if (size == 2)
+ emitcode ("inc", "%s", spname);
+ }
+ else
+ {
+ MOVA (r->name);
+ emitcode ("add", "a,#0x%02x", size);
+ emitcode ("mov", "%s,a", spname);
+ }
+
+ while (offset < size)
+ {
+ MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
+ emitcode ("movx", "@%s,a", r->name);
+ emitcode ("inc", "%s", r->name);
+ }
+ _G.stack.xpushed += size;
+
+ freeAsmop (NULL, aop, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIpush - generate code for pushing this gets a little complex */
+/*-----------------------------------------------------------------*/
+static void
+genIpush (iCode * ic)
+{
+ int size, offset = 0;
+ char *prev;
+
+ D (emitcode (";", "genIpush"));
+
+ /* if this is not a parm push : ie. it is spill push
+ and spill push is always done on the local stack */
+ if (!ic->parmPush)
+ {
+ /* and the item is spilt then do nothing */
+ if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
+ return;
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+ /* push it on the stack */
+ while (size--)
+ {
+ emitpush (aopGet (IC_LEFT (ic), offset++, FALSE, TRUE));
+ }
+ return;
+ }
+
+ /* this is a parameter push: in this case we call
+ the routine to find the call and save those
+ registers that need to be saved */
+ saveRegisters (ic);
+
+ /* if use external stack then call the external
+ stack pushing routine */
+ if (options.useXstack)
+ {
+ genXpush (ic);
+ return;
+ }
+
+ /* then do the push */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+
+ // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
+ size = AOP_SIZE (IC_LEFT (ic));
+
+ prev = Safe_strdup ("");
+ while (size--)
+ {
+ const char *l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
+ if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG && AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
+ {
+ if (!EQ (l, prev) || *l == '@')
+ MOVA (l);
+ emitpush ("acc");
+ }
+ else
+ {
+ emitpush (l);
+ }
+ Safe_free (prev);
+ prev = Safe_strdup (l);
+ }
+ Safe_free (prev);
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIpop - recover the registers: can happen only for spilling */
+/*-----------------------------------------------------------------*/
+static void
+genIpop (iCode * ic)
+{
+ int size, offset;
+
+ D (emitcode (";", "genIpop"));
+
+ /* if the temp was not pushed then */
+ if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
+ return;
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+ offset = size - 1;
+ while (size--)
+ {
+ emitpop (aopGet (IC_LEFT (ic), offset--, FALSE, TRUE));
+ }
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* popForBranch - recover the spilt registers for a branch */
+/*-----------------------------------------------------------------*/
+static void
+popForBranch (iCode * ic, bool markGenerated)
+{
+ while (ic && ic->op == IPOP)
+ {
+ int pushed = _G.stack.pushed;
+ genIpop (ic);
+ if (markGenerated)
+ ic->generated = 1; /* mark the icode as generated */
+ else
+ _G.stack.pushed = pushed;
+ ic = ic->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* emitDummyCall - emit a dummy call for --no-ret-without-call */
+/*-----------------------------------------------------------------*/
+static void
+emitDummyCall(void)
+{
+ symbol *dummyLabel;
+
+ if (!options.no_ret_without_call)
+ return;
+ dummyLabel = newiTempLabel (NULL);
+ emitcode ("lcall", "!tlabel", labelKey2num (dummyLabel->key));
+ emitLabel (dummyLabel);
+ emitcode ("dec", "sp");
+ emitcode ("dec", "sp");
+}
+
+/*-----------------------------------------------------------------*/
+/* saveRBank - saves an entire register bank on the stack */
+/*-----------------------------------------------------------------*/
+static void
+saveRBank (int bank, iCode * ic, bool pushPsw)
+{
+ int i;
+ int count = 8 + (pushPsw ? 1 : 0);
+ asmop *aop = NULL;
+ reg_info *r = NULL;
+
+ if (options.useXstack)
+ {
+ if (!ic)
+ {
+ /* Assume r0 is available for use. */
+ r = REG_WITH_INDEX (R0_IDX);
+ }
+ else
+ {
+ aop = newAsmop (0);
+ r = getFreePtr (ic, aop, FALSE);
+ }
+ // allocate space first
+ emitcode ("mov", "%s,%s", r->name, spname);
+ MOVA (r->name);
+ emitcode ("add", "a,#!constbyte", count);
+ emitcode ("mov", "%s,a", spname);
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ if (options.useXstack)
+ {
+ emitcode ("mov", "a,(%s+%d)", regs8051[i].base, 8 * bank + regs8051[i].offset);
+ emitcode ("movx", "@%s,a", r->name);
+ _G.stack.xpushed++;
+ if (--count)
+ emitcode ("inc", "%s", r->name);
+ }
+ else
+ {
+ char buf[16] = "";
+ SNPRINTF (buf, 16, "(%s+%d)", regs8051[i].base, 8 * bank + regs8051[i].offset);
+ emitpush (buf);
+ }
+ }
+
+ if (pushPsw)
+ {
+ if (options.useXstack)
+ {
+ emitcode ("mov", "a,psw");
+ emitcode ("movx", "@%s,a", r->name);
+ _G.stack.xpushed++;
+ }
+ else
+ {
+ emitpush ("psw");
+ }
+
+ emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
+ }
+
+ if (aop)
+ {
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+
+ if (ic)
+ {
+ ic->bankSaved = 1;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaveRBank - restores the register bank from stack */
+/*-----------------------------------------------------------------*/
+static void
+unsaveRBank (int bank, iCode * ic, bool popPsw)
+{
+ int i;
+ asmop *aop = NULL;
+ reg_info *r = NULL;
+
+ if (options.useXstack)
+ {
+ if (!ic)
+ {
+ /* Assume r0 is available for use. */
+ r = REG_WITH_INDEX (R0_IDX);
+ }
+ else
+ {
+ aop = newAsmop (0);
+ r = getFreePtr (ic, aop, FALSE);
+ }
+ emitcode ("mov", "%s,%s", r->name, spname);
+ }
+
+ if (popPsw)
+ {
+ if (options.useXstack)
+ {
+ emitcode ("dec", "%s", r->name);
+ emitcode ("movx", "a,@%s", r->name);
+ emitcode ("mov", "psw,a");
+ _G.stack.xpushed--;
+ }
+ else
+ {
+ emitpop ("psw");
+ }
+ }
+
+ for (i = 7; i >= 0; i--)
+ {
+ if (options.useXstack)
+ {
+ emitcode ("dec", "%s", r->name);
+ emitcode ("movx", "a,@%s", r->name);
+ emitcode ("mov", "(%s+%d),a", regs8051[i].base, 8 * bank + regs8051[i].offset);
+ _G.stack.xpushed--;
+ }
+ else
+ {
+ char buf[16] = "";
+ SNPRINTF (buf, 16, "(%s+%d)", regs8051[i].base, 8 * bank + regs8051[i].offset);
+ emitpop (buf);
+ }
+ }
+
+ if (options.useXstack)
+ {
+ emitcode ("mov", "%s,%s", spname, r->name);
+ }
+
+ if (aop)
+ {
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genSend - gen code for SEND */
+/*-----------------------------------------------------------------*/
+static void
+genSend (set * sendSet)
+{
+ iCode *sic;
+ int bit_count = 0;
+
+ /* first we do all bit parameters */
+ for (sic = setFirstItem (sendSet); sic; sic = setNextItem (sendSet))
+ {
+ if (sic->argreg > 12)
+ {
+ int bit = sic->argreg - 13;
+
+ aopOp (IC_LEFT (sic), sic, FALSE);
+
+ /* if left is a literal then
+ we know what the value is */
+ if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
+ {
+ if (((int) operandLitValue (IC_LEFT (sic))))
+ emitcode ("setb", "b[%d]", bit);
+ else
+ emitcode ("clr", "b[%d]", bit);
+ }
+ else
+ {
+ /* we need to or */
+ toCarry (IC_LEFT (sic));
+ emitcode ("mov", "b[%d],c", bit);
+ }
+ bit_count++;
+ BitBankUsed = 1;
+
+ freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
+ }
+ }
+
+ if (options.useXstack || bit_count || setFirstItem (sendSet) && operandSize (IC_LEFT ((iCode *)(setFirstItem (sendSet)))) >= 6)
+ {
+ if (bit_count)
+ BITSINB++;
+ saveRegisters (setFirstItem (sendSet));
+ if (bit_count)
+ BITSINB--;
+ }
+
+ if (bit_count)
+ {
+ emitcode ("mov", "bits,b");
+ }
+
+ /* then we do all other parameters */
+ for (sic = setFirstItem (sendSet); sic; sic = setNextItem (sendSet))
+ {
+ if (sic->argreg <= 12)
+ {
+ int size, offset = 0;
+ aopOp (IC_LEFT (sic), sic, FALSE);
+ size = AOP_SIZE (IC_LEFT (sic));
+
+ if (sic->argreg == 1)
+ {
+ if (AOP_TYPE (IC_LEFT (sic)) != AOP_DPTR)
+ {
+ bool pushedA = FALSE;
+ while (size--)
+ {
+ const char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
+ if (!EQ (l, fReturn[offset]))
+ if (fReturn[offset][0] == 'r' && (AOP_TYPE (IC_LEFT (sic)) == AOP_REG || AOP_TYPE (IC_LEFT (sic)) == AOP_R0 || AOP_TYPE (IC_LEFT (sic)) == AOP_R1))
+ emitcode ("mov", "a%s,%s", fReturn[offset], l); // use register's direct address instead of name
+ else
+ emitcode ("mov", "%s,%s", fReturn[offset], l);
+ else if (EQ (l, "a") && size != 0)
+ {
+ emitpush ("acc");
+ pushedA = TRUE;
+ }
+ offset++;
+ }
+ if (pushedA)
+ emitpop ("acc");
+ }
+ else /* need to load dpl, dph, etc from @dptr */
+ {
+ while (size--)
+ {
+ MOVA (aopGet (IC_LEFT (sic), offset, FALSE, FALSE));
+ emitpush ("acc");
+ offset++;
+ }
+ size = AOP_SIZE (IC_LEFT (sic));
+ while (size--)
+ {
+ offset--;
+ if (!EQ ("a", fReturn[offset]))
+ {
+ emitpop (fReturn[offset]);
+ }
+ else
+ {
+ emitpop ("acc");
+ }
+ }
+ }
+ }
+ else
+ {
+ while (size--)
+ {
+ emitcode ("mov", "%s,%s", rb1regs[sic->argreg + offset - 5], aopGet (IC_LEFT (sic), offset, FALSE, FALSE));
+ offset++;
+ }
+ }
+ freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* selectRegBank - emit code to select the register bank */
+/*-----------------------------------------------------------------*/
+static void
+selectRegBank (short bank, bool keepFlags)
+{
+ /* if f.e. result is in carry */
+ if (keepFlags)
+ {
+ emitcode ("anl", "psw,#0xE7");
+ if (bank)
+ emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
+ }
+ else
+ {
+ emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCall - generates a call statement */
+/*-----------------------------------------------------------------*/
+static void
+genCall (iCode * ic)
+{
+ sym_link *dtype;
+ sym_link *etype;
+ bool swapBanks = FALSE;
+ bool accuse = FALSE;
+ bool accPushed = FALSE;
+ bool resultInF0 = FALSE;
+ bool assignResultGenerated = FALSE;
+
+ D (emitcode (";", "genCall"));
+
+ dtype = operandType (IC_LEFT (ic));
+ etype = getSpec (dtype);
+ /* if send set is not empty then assign */
+ if (_G.sendSet)
+ {
+ if (IFFUNC_ISREENT (dtype))
+ {
+ /* need to reverse the send set */
+ genSend (reverseSet (_G.sendSet));
+ }
+ else
+ {
+ genSend (_G.sendSet);
+ }
+ _G.sendSet = NULL;
+ }
+
+ /* if we are calling a not _naked function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
+ (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && !IFFUNC_ISISR (dtype))
+ {
+ swapBanks = TRUE;
+ }
+
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters (ic);
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#!constbyte", ((FUNC_REGBANK (dtype)) << 3) & 0xff);
+ }
+
+ /* make the call */
+ if (IFFUNC_ISBANKEDCALL (dtype))
+ {
+ if (IFFUNC_CALLEESAVES (dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ if (IS_LITERAL (etype))
+ {
+ emitcode ("mov", "r0,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 1));
+ emitcode ("mov", "r1,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 1, 1));
+ emitcode ("mov", "r2,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 2, 1));
+ }
+ else
+ {
+ char *name = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
+ OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name);
+ emitcode ("mov", "r0,#%s", name);
+ emitcode ("mov", "r1,#(%s >> 8)", name);
+ emitcode ("mov", "r2,#(%s >> 16)", name);
+ }
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else
+ {
+ if (IS_LITERAL (etype))
+ {
+ emitcode ("lcall", "0x%04X", ulFromVal (OP_VALUE (IC_LEFT (ic))));
+ }
+ else
+ {
+ emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
+ OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name));
+ }
+ }
+
+ if (swapBanks)
+ {
+ selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
+ }
+
+ /* if we need assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
+ OP_SYMBOL (IC_RESULT (ic))->accuse ||
+ OP_SYMBOL (IC_RESULT (ic))->spildir || IS_BIT (etype))) || IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+
+ accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
+ assignResultGenerated = TRUE;
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* adjust the stack for parameters if required */
+ if (ic->parmBytes)
+ {
+ int i;
+ if (ic->parmBytes > 3)
+ {
+ if (accuse)
+ {
+ emitpush ("acc");
+ accPushed = TRUE;
+ }
+ if (IS_BIT (etype) && IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
+ {
+ emitcode ("mov", "F0,c");
+ resultInF0 = TRUE;
+ }
+
+ emitcode ("mov", "a,%s", spname);
+ emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
+ emitcode ("mov", "%s,a", spname);
+ if (options.useXstack)
+ _G.stack.xpushed -= ic->parmBytes;
+ else
+ _G.stack.pushed -= ic->parmBytes;
+
+ /* unsaveRegisters from xstack needs acc, but */
+ /* unsaveRegisters from stack needs this popped */
+ if (accPushed && !options.useXstack)
+ {
+ emitpop ("acc");
+ accPushed = FALSE;
+ }
+ }
+ else
+ {
+ for (i = 0; i < ic->parmBytes; i++)
+ emitcode ("dec", "%s", spname);
+ if (options.useXstack)
+ _G.stack.xpushed -= ic->parmBytes;
+ else
+ _G.stack.pushed -= ic->parmBytes;
+ }
+ }
+
+ /* if we had saved some registers then unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
+ {
+ if (accuse && !accPushed && options.useXstack)
+ {
+ /* xstack needs acc, but doesn't touch normal stack */
+ emitpush ("acc");
+ accPushed = TRUE;
+ }
+ unsaveRegisters (ic);
+ }
+
+ if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
+ {
+ if (resultInF0)
+ emitcode ("mov", "c,F0");
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ if (accPushed)
+ emitpop ("acc");
+}
+
+/*-----------------------------------------------------------------*/
+/* genPcall - generates a call by pointer statement */
+/*-----------------------------------------------------------------*/
+static void
+genPcall (iCode * ic)
+{
+ sym_link *dtype;
+ sym_link *etype;
+ bool swapBanks = FALSE;
+ bool resultInF0 = FALSE;
+
+ D (emitcode (";", "genPcall"));
+
+ dtype = operandType (IC_LEFT (ic))->next;
+ etype = getSpec (dtype);
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters (ic);
+
+ /* if we are calling a not _naked function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
+ (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && !IFFUNC_ISISR (dtype))
+ {
+ swapBanks = TRUE;
+ // need caution message to user here
+ }
+
+ if (IS_LITERAL (etype))
+ {
+ /* if send set is not empty then assign */
+ if (_G.sendSet)
+ {
+ genSend (reverseSet (_G.sendSet));
+ _G.sendSet = NULL;
+ }
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK (dtype)) << 3) & 0xff);
+ }
+
+ if (IFFUNC_ISBANKEDCALL (dtype))
+ {
+ if (IFFUNC_CALLEESAVES (dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ emitcode ("mov", "r0,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 1));
+ emitcode ("mov", "r1,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 1, 1));
+ emitcode ("mov", "r2,#%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 2, 1));
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else
+ {
+ emitcode ("lcall", "0x%04X", ulFromVal (OP_VALUE (IC_LEFT (ic))));
+ }
+ }
+ else
+ {
+ if (IFFUNC_ISBANKEDCALL (dtype))
+ {
+ if (IFFUNC_CALLEESAVES (dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ aopOp (IC_LEFT (ic), ic, FALSE);
+
+ emitpush (aopGet (IC_LEFT (ic), 0, FALSE, TRUE));
+ emitpush (aopGet (IC_LEFT (ic), 1, FALSE, TRUE));
+ emitpush (aopGet (IC_LEFT (ic), 2, FALSE, TRUE));
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+ /* if send set is not empty then assign */
+ if (_G.sendSet)
+ {
+ genSend (reverseSet (_G.sendSet));
+ _G.sendSet = NULL;
+ }
+
+ if (swapBanks)
+ {
+ char buf[8] = "";
+ int reg = ((FUNC_REGBANK (dtype)) << 3) & 0xff;
+ emitcode ("mov", "psw,#0x%02x", reg);
+ SNPRINTF (buf, 8, "0x%02x", reg + 2);
+ emitpop (buf);
+ SNPRINTF (buf, 8, "0x%02x", reg + 1);
+ emitpop (buf);
+ SNPRINTF (buf, 8, "0x%02x", reg + 0);
+ emitpop (buf);
+ }
+ else
+ {
+ emitpop ("ar2");
+ emitpop ("ar1");
+ emitpop ("ar0");
+ }
+ /* make the call */
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else if (_G.sendSet) /* the send set is not empty */
+ {
+ symbol *callLabel = newiTempLabel (NULL);
+ symbol *returnLabel = newiTempLabel (NULL);
+
+ /* create the return address on the stack */
+ emitcode ("lcall", "!tlabel", labelKey2num (callLabel->key));
+ emitcode ("ljmp", "!tlabel", labelKey2num (returnLabel->key));
+ emitLabel (callLabel);
+ _G.stack.pushed += 2;
+
+ emitDummyCall();
+ /* now push the function address */
+ pushSide (IC_LEFT (ic), FARPTRSIZE, ic);
+
+ /* send set is not empty: assign */
+ genSend (reverseSet (_G.sendSet));
+ _G.sendSet = NULL;
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK (dtype)) << 3) & 0xff);
+ }
+
+ /* make the call */
+ emitcode ("ret", "");
+ _G.stack.pushed -= 4;
+ emitLabel (returnLabel);
+ }
+ else /* the send set is empty */
+ {
+ /* now get the called address into dptr */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
+ {
+ emitcode ("mov", "r0,%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("mov", "dph,%s", aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
+ emitcode ("mov", "dpl,r0");
+ }
+ else
+ {
+ emitcode ("mov", "dpl,%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("mov", "dph,%s", aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
+ }
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK (dtype)) << 3) & 0xff);
+ }
+
+ /* make the call */
+ emitcode ("lcall", "__sdcc_call_dptr");
+ }
+ }
+ if (swapBanks)
+ {
+ selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
+ }
+
+ /* if we need assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->accuse || OP_SYMBOL (IC_RESULT (ic))->spildir)) || IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+
+ assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* adjust the stack for parameters if required */
+ if (ic->parmBytes)
+ {
+ int i;
+ if (ic->parmBytes > 3)
+ {
+ if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) && IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
+ {
+ emitcode ("mov", "F0,c");
+ resultInF0 = TRUE;
+ }
+
+ emitcode ("mov", "a,%s", spname);
+ emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
+ emitcode ("mov", "%s,a", spname);
+ if (options.useXstack)
+ _G.stack.xpushed -= ic->parmBytes;
+ else
+ _G.stack.pushed -= ic->parmBytes;
+ }
+ else
+ {
+ for (i = 0; i < ic->parmBytes; i++)
+ emitcode ("dec", "%s", spname);
+ if (options.useXstack)
+ _G.stack.xpushed -= ic->parmBytes;
+ else
+ _G.stack.pushed -= ic->parmBytes;
+ }
+ }
+
+ /* if we had saved some registers then unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
+ unsaveRegisters (ic);
+
+ if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
+ {
+ if (resultInF0)
+ emitcode ("mov", "c,F0");
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* resultRemat - result is rematerializable */
+/*-----------------------------------------------------------------*/
+static int
+resultRemat (iCode * ic)
+{
+ if (SKIP_IC (ic) || ic->op == IFX)
+ return 0;
+
+ if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
+ {
+ symbol *sym = OP_SYMBOL (IC_RESULT (ic));
+ if (sym->remat && !POINTER_SET (ic))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* genFunction - generated code for function entry */
+/*-----------------------------------------------------------------*/
+static void
+genFunction (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+ sym_link *ftype = operandType (IC_LEFT (ic));
+ bool switchedPSW = FALSE;
+ int calleesaves_saved_register = -1;
+ int stackAdjust = sym->stack;
+ int accIsFree = sym->recvSize < 4;
+ char *freereg = NULL;
+ iCode *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
+ bool fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
+
+ /* create the function header */
+ emitcode (";", "-----------------------------------------");
+ emitcode (";", " function %s", sym->name);
+ emitcode (";", "-----------------------------------------");
+
+ emitcode ("", "%s:", sym->rname);
+ genLine.lineCurr->isLabel = 1;
+ _G.currentFunc = sym;
+
+ if (IFFUNC_ISNAKED (ftype))
+ {
+ emitcode (";", "naked function: no prologue.");
+ return;
+ }
+
+ /* here we need to generate the equates for the
+ register bank if required */
+ if (FUNC_REGBANK (ftype) != rbank)
+ {
+ int i;
+
+ rbank = FUNC_REGBANK (ftype);
+ for (i = 0; i < mcs51_nRegs; i++)
+ {
+ if (regs8051[i].type != REG_BIT)
+ {
+ if (EQ (regs8051[i].base, "0"))
+ emitcode ("", "%s !equ !constbyte", regs8051[i].dname, 8 * rbank + regs8051[i].offset);
+ else
+ emitcode ("", "%s !equ %s + !constbyte", regs8051[i].dname, regs8051[i].base, 8 * rbank + regs8051[i].offset);
+ }
+ }
+ }
+
+ _G.stack.param_offset = 0;
+ _G.stack.offset = sym->stack;
+ _G.stack.xoffset = sym->xstack;
+ wassertl (_G.stack.pushed == 0, "stack over/underflow");
+ wassertl (_G.stack.xpushed == 0, "xstack over/underflow");
+
+ /* if this is an interrupt service routine then
+ save acc, b, dpl, dph */
+ if (IFFUNC_ISISR (ftype))
+ {
+ bitVect *rsavebits;
+
+ /* weird but possible, one should better use a different priority */
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ emitcode ("clr", "ea");
+ }
+
+ rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
+ if (IFFUNC_HASFCALL (ftype) || !bitVectIsZero (rsavebits))
+ {
+ if (!inExcludeList ("bits"))
+ {
+ emitpush ("bits");
+ BitBankUsed = 1;
+ }
+ }
+ freeBitVect (rsavebits);
+
+ if (!inExcludeList ("acc"))
+ emitpush ("acc");
+ if (!inExcludeList ("b"))
+ emitpush ("b");
+ if (!inExcludeList ("dpl"))
+ emitpush ("dpl");
+ if (!inExcludeList ("dph"))
+ emitpush ("dph");
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+ registers :-) */
+ if (!FUNC_REGBANK (ftype))
+ {
+ int i;
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (!IFFUNC_HASFCALL (ftype))
+ {
+ /* if any registers used */
+ if (!bitVectIsZero (sym->regsUsed))
+ {
+ /* save the registers used */
+ for (i = 0; i < sym->regsUsed->size; i++)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ pushReg (i, TRUE);
+ }
+ }
+ }
+ else
+ {
+ /* this function has a function call. We cannot
+ determine register usage so we will have to push the
+ entire bank */
+ saveRBank (0, ic, FALSE);
+ if (options.parms_in_bank1)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ emitpush (rb1regs[i]);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* This ISR uses a non-zero bank.
+ *
+ * We assume that the bank is available for our
+ * exclusive use.
+ *
+ * However, if this ISR calls a function which uses some
+ * other bank, we must save that bank entirely.
+ */
+ unsigned long banksToSave = 0;
+
+ if (IFFUNC_HASFCALL (ftype))
+ {
+ iCode *i;
+ int ix;
+
+ for (i = ic; i; i = i->next)
+ {
+ sym_link *dtype = NULL;
+
+ if (i->op == ENDFUNCTION)
+ {
+ /* we got to the end OK. */
+ break;
+ }
+
+ if (i->op == CALL)
+ {
+ dtype = operandType (IC_LEFT (i));
+ }
+ if (i->op == PCALL)
+ {
+ /* This is a mess; we have no idea what
+ * register bank the called function might
+ * use.
+ *
+ * The only thing I can think of to do is
+ * throw a warning and hope.
+ */
+// werror (W_FUNCPTR_IN_USING_ISR);
+ dtype = operandType (IC_LEFT (i))->next;
+ }
+ if (dtype && FUNC_REGBANK (dtype) != FUNC_REGBANK (ftype))
+ {
+ /* Mark this bank for saving. */
+ if (FUNC_REGBANK (dtype) >= MAX_REGISTER_BANKS)
+ {
+ werror (E_NO_SUCH_BANK, FUNC_REGBANK (dtype));
+ }
+ else
+ {
+ banksToSave |= (1 << FUNC_REGBANK (dtype));
+ }
+
+ /* And note that we don't need to do it in
+ * genCall.
+ */
+ i->bankSaved = 1;
+ }
+ }
+
+ if (banksToSave && options.useXstack)
+ {
+ /* Since we aren't passing it an ic,
+ * saveRBank will assume r0 is available to abuse.
+ *
+ * So switch to our (trashable) bank now, so
+ * the caller's R0 isn't trashed.
+ */
+ emitpush ("psw");
+ emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
+ switchedPSW = TRUE;
+ }
+
+ for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
+ {
+ if (banksToSave & (1 << ix))
+ {
+ saveRBank (ix, NULL, FALSE);
+ }
+ }
+ }
+ // TODO: this needs a closer look
+ SPEC_ISR_SAVED_BANKS (currFunc->etype) = banksToSave;
+ }
+
+ /* Set the register bank to the desired value if nothing else */
+ /* has done so yet. */
+ if (!switchedPSW)
+ {
+ emitpush ("psw");
+ emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (ftype) << 3) & 0x00ff);
+ }
+ }
+ else
+ {
+ /* This is a non-ISR function. */
+
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitLabel (tlbl);
+ emitpush ("psw"); /* save old ea via c in psw */
+ }
+
+ /* The caller has already switched register banks if */
+ /* necessary, so just handle the callee-saves option. */
+
+ /* if callee-save to be used for this function
+ then save the registers being used in this function */
+ if (IFFUNC_CALLEESAVES (ftype))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ bool bits_pushed = FALSE;
+ /* save the registers used */
+ for (i = 0; i < sym->regsUsed->size; i++)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ {
+ /* remember one saved register for later usage */
+ if (calleesaves_saved_register < 0)
+ calleesaves_saved_register = i;
+ bits_pushed = pushReg (i, bits_pushed);
+ _G.stack.param_offset--;
+ }
+ }
+ }
+ }
+ }
+
+ if (fReentrant && !options.omitFramePtr)
+ {
+ if (options.useXstack)
+ {
+ if (sym->xstack || FUNC_HASSTACKPARM (ftype))
+ {
+ emitcode ("mov", "r0,%s", spname);
+ emitcode ("inc", "%s", spname);
+ emitcode ("xch", "a,_bpx");
+ emitcode ("movx", "@r0,a");
+ emitcode ("inc", "r0");
+ emitcode ("mov", "a,r0");
+ emitcode ("xch", "a,_bpx");
+ }
+ if (sym->stack)
+ {
+ /* save the callers stack, but without pushed++ */
+ emitcode ("push", "_bp");
+ emitcode ("mov", "_bp,sp");
+ }
+ }
+ else
+ {
+ if (sym->stack || FUNC_HASSTACKPARM (ftype))
+ {
+ /* set up the stack */
+ /* save the callers stack, but without pushed++ */
+ emitcode ("push", "_bp");
+ emitcode ("mov", "_bp,sp");
+ }
+ }
+ }
+
+ /* For some cases it is worthwhile to perform a RECEIVE iCode */
+ /* before setting up the stack frame completely. */
+ if (ric && ric->argreg == 1 && IC_RESULT (ric))
+ {
+ symbol *rsym = OP_SYMBOL (IC_RESULT (ric));
+
+ if (rsym->isitmp)
+ {
+ if (rsym && rsym->regType == REG_CND)
+ rsym = NULL;
+ if (rsym && (rsym->accuse || rsym->ruonly))
+ rsym = NULL;
+ if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
+ rsym = rsym->usl.spillLoc;
+ }
+
+ /* If the RECEIVE operand immediately spills to the first entry on the */
+ /* stack, we can push it directly (since sp = _bp + 1 at this point) */
+ /* rather than the usual @r0/r1 machinations. */
+ if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
+ {
+ int ofs;
+
+ genLine.lineElement.ic = ric;
+ D (emitcode (";", "genReceive"));
+ for (ofs = 0; ofs < sym->recvSize; ofs++)
+ {
+ emitpush (fReturn[ofs]);
+ _G.stack.pushed--; /* cancel out pushed++ from emitpush()*/
+ }
+ stackAdjust -= sym->recvSize;
+ if (stackAdjust < 0)
+ {
+ assert (stackAdjust >= 0);
+ stackAdjust = 0;
+ }
+ genLine.lineElement.ic = ic;
+ ric->generated = 1;
+ accIsFree = 1;
+ }
+ /* If the RECEIVE operand is 4 registers, we can do the moves now */
+ /* to free up the accumulator. */
+ else if (rsym && rsym->nRegs && sym->recvSize == 4)
+ {
+ int ofs;
+
+ genLine.lineElement.ic = ric;
+ D (emitcode (";", "genReceive"));
+ for (ofs = 0; ofs < sym->recvSize; ofs++)
+ {
+ emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
+ }
+ genLine.lineElement.ic = ic;
+ ric->generated = 1;
+ accIsFree = 1;
+ }
+ }
+
+ /* If the accumulator is not free, we will need another register */
+ /* to clobber. No need to worry about a possible conflict with */
+ /* the above early RECEIVE optimizations since they would have */
+ /* freed the accumulator if they were generated. */
+ if (IFFUNC_CALLEESAVES (ftype))
+ {
+ /* if it's a callee-saves function we need a saved register */
+ if (calleesaves_saved_register >= 0)
+ {
+ freereg = REG_WITH_INDEX (calleesaves_saved_register)->dname;
+ }
+ }
+ else
+ {
+ /* not callee-saves, we can clobber r0 */
+ freereg = "r0";
+ }
+
+ /* adjust the stack for the function */
+ if (stackAdjust)
+ {
+ int i = stackAdjust & 0xff;
+ if (stackAdjust > 256)
+ werror (W_STACK_OVERFLOW, sym->name);
+
+ if (i > 3 && accIsFree)
+ {
+ emitcode ("mov", "a,sp");
+ emitcode ("add", "a,#!constbyte", i & 0xff);
+ emitcode ("mov", "sp,a");
+ }
+ else if (i > 4)
+ {
+ if (freereg)
+ {
+ emitcode ("xch", "a,%s", freereg);
+ emitcode ("mov", "a,sp");
+ emitcode ("add", "a,#!constbyte", i & 0xff);
+ emitcode ("mov", "sp,a");
+ emitcode ("xch", "a,%s", freereg);
+ }
+ else
+ {
+ /* do it the hard way */
+ while (i--)
+ emitcode ("inc", "sp");
+ }
+ }
+ else
+ {
+ while (i--)
+ emitcode ("inc", "sp");
+ }
+ }
+
+ if (sym->xstack)
+ {
+ int i = sym->xstack & 0xff;
+ if (sym->xstack > 256)
+ werror (W_STACK_OVERFLOW, sym->name);
+
+ if (i > 3 && accIsFree)
+ {
+ emitcode ("mov", "a,_spx");
+ emitcode ("add", "a,#!constbyte", i & 0xff);
+ emitcode ("mov", "_spx,a");
+ }
+ else if (i > 4)
+ {
+ if (freereg)
+ emitcode ("xch", "a,%s", freereg);
+ else
+ emitpush ("acc");
+ emitcode ("mov", "a,_spx");
+ emitcode ("add", "a,#0x%02x", i & 0xff);
+ emitcode ("mov", "_spx,a");
+ if (freereg)
+ emitcode ("xch", "a,%s", freereg);
+ else
+ emitpop ("acc");
+ }
+ else
+ {
+ while (i--)
+ emitcode ("inc", "_spx");
+ }
+ }
+
+ _G.stack.param_offset = options.useXstack ? _G.stack.xpushed : _G.stack.pushed;
+ _G.stack.pushedregs = _G.stack.pushed;
+ _G.stack.xpushedregs = _G.stack.xpushed;
+ _G.stack.pushed = 0;
+ _G.stack.xpushed = 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndFunction - generates epilogue for functions */
+/*-----------------------------------------------------------------*/
+static void
+genEndFunction (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+ sym_link *ftype = operandType (IC_LEFT (ic));
+ bool fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
+ lineNode *lineBodyEnd = genLine.lineCurr;
+ lineNode *linePrologueStart = NULL;
+ lineNode *lnp;
+ bitVect *regsUsed;
+ bitVect *regsUnneeded;
+ int idx;
+
+ _G.currentFunc = NULL;
+ if (IFFUNC_ISNAKED (ftype))
+ {
+ emitcode (";", "naked function: no epilogue.");
+ if (options.debug && currFunc)
+ debugFile->writeEndFunction (currFunc, ic, 0);
+ return;
+ }
+
+ _G.stack.xpushed = _G.stack.xpushedregs;
+ _G.stack.pushed = _G.stack.pushedregs;
+
+ if (fReentrant)
+ {
+ if (options.omitFramePtr)
+ {
+ bool cy_in_r0 = FALSE;
+ bool acc_in_r0 = FALSE;
+
+ if (sym->stack > 3)
+ {
+ if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
+ {
+ emitcode ("mov", "r0,psw"); /* save cy in r0 */
+ cy_in_r0 = TRUE;
+ }
+ if (getSize (OP_SYM_ETYPE (IC_LEFT (ic))) >= 4)
+ {
+ emitcode ("xch", "a,r0"); /* save a in r0 */
+ acc_in_r0 = TRUE;
+ }
+
+ emitcode ("mov", "a,sp");
+ emitcode ("add", "a,#!constbyte", (-sym->stack) & 0xff);
+ emitcode ("mov", "sp,a");
+ }
+ else
+ {
+ int i = sym->stack;
+ while (i--)
+ emitcode ("dec", "sp");
+ }
+ if (sym->xstack > 3)
+ {
+ if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
+ {
+ if (!cy_in_r0)
+ emitcode ("mov", "r0,psw"); /* save cy in r0 */
+ cy_in_r0 = TRUE;
+ }
+ if (getSize (OP_SYM_ETYPE (IC_LEFT (ic))) >= 4)
+ {
+ if (!acc_in_r0)
+ emitcode ("xch", "a,r0"); /* save a in r0 */
+ acc_in_r0 = TRUE;
+ }
+
+ emitcode ("mov", "a,_spx");
+ emitcode ("add", "a,#!constbyte", (-sym->xstack) & 0xff);
+ emitcode ("mov", "_spx,a");
+ }
+ else
+ {
+ int i = sym->xstack;
+ while (i--)
+ emitcode ("dec", "_spx");
+ }
+
+ if (acc_in_r0)
+ emitcode ("xch", "a,r0"); /* restore a from r0 */
+
+ if (cy_in_r0)
+ emitcode ("mov", "psw,r0"); /* restore c from r0 */
+ }
+ else
+ {
+ if (options.useXstack)
+ {
+ if (sym->stack)
+ {
+ if (sym->stack == 1)
+ emitcode ("dec", "sp");
+ else
+ emitcode ("mov", "sp,_bp");
+ emitcode ("pop", "_bp"); /* without pushed-- */
+ }
+ if (sym->xstack || FUNC_HASSTACKPARM (ftype))
+ {
+ emitcode ("xch", "a,_bpx");
+ emitcode ("mov", "r0,a");
+ emitcode ("dec", "r0");
+ emitcode ("movx", "a,@r0");
+ emitcode ("xch", "a,_bpx");
+ emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
+ }
+ }
+ else if (sym->stack || FUNC_HASSTACKPARM (ftype))
+ {
+ if (sym->stack == 1)
+ emitcode ("dec", "sp");
+ else if (sym->stack)
+ emitcode ("mov", "sp,_bp");
+ emitcode ("pop", "_bp"); /* without pushed-- */
+ }
+ }
+ }
+
+ /* restore the register bank */
+ if (IFFUNC_ISISR (ftype))
+ {
+ if (!FUNC_REGBANK (ftype) || !options.useXstack)
+ {
+ /* Special case of ISR using non-zero bank with useXstack
+ * is handled below.
+ */
+ emitpop ("psw");
+ }
+ }
+
+ if (IFFUNC_ISISR (ftype))
+ {
+ bitVect *rsavebits;
+
+ /* now we need to restore the registers */
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+ registers :-) */
+ if (!FUNC_REGBANK (ftype))
+ {
+ int i;
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (!IFFUNC_HASFCALL (ftype))
+ {
+ /* if any registers used */
+ if (!bitVectIsZero (sym->regsUsed))
+ {
+ /* restore the registers used */
+ for (i = sym->regsUsed->size; i >= 0; i--)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ popReg (i, TRUE);
+ }
+ }
+ }
+ else
+ {
+ if (options.parms_in_bank1)
+ {
+ for (i = 7; i >= 0; i--)
+ {
+ emitpop (rb1regs[i]);
+ }
+ }
+ /* this function has a function call. We cannot
+ determine register usage so we will have to pop the
+ entire bank */
+ unsaveRBank (0, ic, FALSE);
+ }
+ }
+ else
+ {
+ /* This ISR uses a non-zero bank.
+ *
+ * Restore any register banks saved by genFunction
+ * in reverse order.
+ */
+ unsigned savedBanks = SPEC_ISR_SAVED_BANKS (currFunc->etype);
+ int ix;
+
+ for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
+ {
+ if (savedBanks & (1 << ix))
+ {
+ unsaveRBank (ix, NULL, FALSE);
+ }
+ }
+
+ if (options.useXstack)
+ {
+ /* Restore bank AFTER calling unsaveRBank,
+ * since it can trash r0.
+ */
+ emitpop ("psw");
+ }
+ }
+
+ if (!inExcludeList ("dph"))
+ emitpop ("dph");
+ if (!inExcludeList ("dpl"))
+ emitpop ("dpl");
+ if (!inExcludeList ("b"))
+ emitpop ("b");
+ if (!inExcludeList ("acc"))
+ emitpop ("acc");
+
+ rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
+ if (IFFUNC_HASFCALL (ftype) || !bitVectIsZero (rsavebits))
+ {
+ if (!inExcludeList ("bits"))
+ emitpop ("bits");
+ }
+ freeBitVect (rsavebits);
+
+ /* weird but possible, one should better use a different priority */
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ emitcode ("setb", "ea");
+ }
+
+ /* if debug then send end of function */
+ if (options.debug && currFunc)
+ {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+
+ emitcode ("reti", "");
+ }
+ else
+ {
+ if (IFFUNC_CALLEESAVES (ftype))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ /* save the registers used */
+ for (i = sym->regsUsed->size; i >= 0; i--)
+ {
+ if (bitVectBitValue (sym->regsUsed, i) || (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+ emitpop (REG_WITH_INDEX (i)->dname);
+ }
+ }
+ else if (mcs51_ptrRegReq)
+ {
+ emitpop (REG_WITH_INDEX (R1_IDX)->dname);
+ emitpop (REG_WITH_INDEX (R0_IDX)->dname);
+ }
+ }
+
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
+ {
+ emitcode ("rlc", "a"); /* save c in a */
+ emitpop ("psw"); /* restore ea via c in psw */
+ emitcode ("mov", "ea,c");
+ emitcode ("rrc", "a"); /* restore c from a */
+ }
+ else
+ {
+ emitpop ("psw"); /* restore ea via c in psw */
+ emitcode ("mov", "ea,c");
+ }
+ }
+
+ /* if debug then send end of function */
+ if (options.debug && currFunc)
+ {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+
+ if (IFFUNC_ISBANKEDCALL (ftype))
+ {
+ emitcode ("ljmp", "__sdcc_banked_ret");
+ }
+ else
+ {
+ emitcode ("ret", "");
+ }
+ }
+
+ wassertl (_G.stack.pushed == 0, "stack over/underflow");
+ wassertl (_G.stack.xpushed == 0, "xstack over/underflow");
+
+ if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
+ return;
+
+ /* If this was an interrupt handler using bank 0 that called another */
+ /* function, then all registers must be saved; nothing to optimize. */
+ if (IFFUNC_ISISR (ftype) && IFFUNC_HASFCALL (ftype) && !FUNC_REGBANK (ftype))
+ return;
+
+ /* There are no push/pops to optimize if not callee-saves or ISR */
+ if (!(FUNC_CALLEESAVES (ftype) || FUNC_ISISR (ftype)))
+ return;
+
+ /* If there were stack parameters, we cannot optimize without also */
+ /* fixing all of the stack offsets; this is too dificult to consider. */
+ if (FUNC_HASSTACKPARM (ftype))
+ return;
+
+ /* Compute the registers actually used */
+ regsUsed = newBitVect (mcs51_nRegs);
+ lnp = lineBodyEnd;
+ while (lnp)
+ {
+ /* Remove change of register bank if no registers used */
+ if (lnp->ic && lnp->ic->op == FUNCTION &&
+ !strncmp (lnp->line, "mov", 3) &&
+ bitVectFirstBit (port->peep.getRegsWritten (lnp)) == CND_IDX &&
+ !bitVectBitsInCommon (mcs51_allBankregs (), regsUsed) &&
+ !IFFUNC_HASFCALL (ftype))
+ {
+ emitcode (";", "eliminated unneeded mov psw,# (no regs used in bank)");
+ connectLine (lnp->prev, lnp->next);
+ }
+ else
+ {
+ regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten (lnp));
+ }
+
+ if (lnp->ic && lnp->ic->op == FUNCTION)
+ {
+ if (!lnp->prev || (lnp->prev->ic && lnp->prev->ic->op != FUNCTION))
+ break;
+ }
+ lnp = lnp->prev;
+ }
+ linePrologueStart = lnp;
+
+ /* If this was an interrupt handler that called another function */
+ /* function, then assume A, B, DPH, & DPL may be modified by it. */
+ if (IFFUNC_ISISR (ftype) && IFFUNC_HASFCALL (ftype))
+ {
+ regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
+ regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
+ regsUsed = bitVectSetBit (regsUsed, B_IDX);
+ regsUsed = bitVectSetBit (regsUsed, A_IDX);
+ regsUsed = bitVectSetBit (regsUsed, CND_IDX);
+ }
+
+ /* Remove the unneeded push/pops */
+ regsUnneeded = newBitVect (mcs51_nRegs);
+ for (lnp = genLine.lineCurr; lnp != linePrologueStart; lnp = lnp->prev)
+ {
+ if (lnp->ic)
+ {
+ if (lnp->ic && (lnp->ic->op == FUNCTION) && !strncmp (lnp->line, "push", 4))
+ {
+ idx = bitVectFirstBit (port->peep.getRegsRead (lnp));
+ if (idx >= 0 && !bitVectBitValue (regsUsed, idx))
+ {
+ connectLine (lnp->prev, lnp->next);
+ regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+ }
+ }
+ if (lnp->ic && (lnp->ic->op == ENDFUNCTION) && !strncmp (lnp->line, "pop", 3))
+ {
+ idx = bitVectFirstBit (port->peep.getRegsWritten (lnp));
+ if (idx >= 0 && !bitVectBitValue (regsUsed, idx))
+ {
+ connectLine (lnp->prev, lnp->next);
+ regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+ }
+ }
+ }
+ }
+
+ for (idx = 0; idx < regsUnneeded->size; idx++)
+ if (bitVectBitValue (regsUnneeded, idx))
+ emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
+
+ freeBitVect (regsUnneeded);
+ freeBitVect (regsUsed);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRet - generate code for return statement */
+/*-----------------------------------------------------------------*/
+static void
+genRet (iCode * ic)
+{
+ int size, offset = 0, pushed = 0;
+ bool pushedA = FALSE;
+
+ D (emitcode (";", "genRet"));
+
+ /* if we have no return value then
+ just generate the "ret" */
+ if (!IC_LEFT (ic))
+ goto jumpret;
+
+ /* we have something to return then
+ move the return value into place */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+
+ if (IS_BIT (_G.currentFunc->etype))
+ {
+ if (!IS_OP_RUONLY (IC_LEFT (ic)))
+ toCarry (IC_LEFT (ic));
+ }
+ else
+ {
+ while (size--)
+ {
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
+ {
+ /* #NOCHANGE */
+ emitpush (aopGet (IC_LEFT (ic), offset++, FALSE, TRUE));
+ pushed++;
+ }
+ else
+ {
+ const char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
+ if (!EQ (fReturn[offset], l))
+ if (fReturn[offset][0] == 'r' && (AOP_TYPE (IC_LEFT (ic)) == AOP_REG || AOP_TYPE (IC_LEFT (ic)) == AOP_R0 || AOP_TYPE (IC_LEFT (ic)) == AOP_R1))
+ emitcode ("mov", "a%s,%s", fReturn[offset], l); // use register's direct address instead of name
+ else
+ emitcode ("mov", "%s,%s", fReturn[offset], l);
+ if (size && !strcmp(fReturn[offset], "a") && aopGetUsesAcc (IC_LEFT (ic), offset+1))
+ {
+ emitpush ("acc");
+ pushedA = TRUE;
+ }
+ offset++;
+ }
+ }
+ if (pushedA)
+ {
+ emitpop ("acc");
+ }
+
+ while (pushed)
+ {
+ pushed--;
+ if (!EQ (fReturn[pushed], "a"))
+ emitpop (fReturn[pushed]);
+ else
+ emitpop ("acc");
+ }
+ }
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+jumpret:
+ /* generate a jump to the return label
+ if the next is not the return statement */
+ if (!(ic->next && ic->next->op == LABEL && IC_LABEL (ic->next) == returnLabel))
+ {
+ emitcode ("ljmp", "!tlabel", labelKey2num (returnLabel->key));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genLabel - generates a label */
+/*-----------------------------------------------------------------*/
+static void
+genLabel (iCode * ic)
+{
+ /* special case never generate */
+ if (IC_LABEL (ic) == entryLabel)
+ return;
+
+ emitLabel (IC_LABEL (ic));
+}
+
+/*-----------------------------------------------------------------*/
+/* genGoto - generates a ljmp */
+/*-----------------------------------------------------------------*/
+static void
+genGoto (iCode * ic)
+{
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_LABEL (ic)->key));
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlusIncr :- does addition with increment if possible */
+/*-----------------------------------------------------------------*/
+static bool
+genPlusIncr (iCode * ic)
+{
+ unsigned int icount;
+ unsigned int size = getDataSize (IC_RESULT (ic)), offset;
+
+ /* will try to generate an increment */
+ /* if the right side is not a literal
+ we cannot */
+ if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
+ return FALSE;
+
+ icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+
+ D (emitcode (";", "genPlusIncr"));
+
+ /* if increment >=16 bits in register or direct space */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
+ AOP_TYPE (IC_LEFT (ic)) == AOP_DIR ||
+ (IS_AOP_PREG (IC_LEFT (ic)) && !AOP_NEEDSACC (IC_LEFT (ic)))) &&
+ sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+ !isOperandVolatile (IC_RESULT (ic), FALSE) && (size > 1) && (icount == 1))
+ {
+ symbol *tlbl;
+ const char *l;
+
+ tlbl = newiTempLabel (NULL);
+ l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE);
+ emitcode ("inc", "%s", l);
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("cjne", "%s,%s,!tlabel", l, zero, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ emitcode ("clr", "a");
+ emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key));
+ }
+
+ l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE);
+ emitcode ("inc", "%s", l);
+
+ for(offset = 2; size > 2; size--, offset++)
+ {
+ if (EQ (l, "acc"))
+ {
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ }
+ else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("cjne", "%s,%s,!tlabel", l, zero, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key));
+ }
+
+ l = aopGet (IC_RESULT (ic), offset, FALSE, FALSE);
+ emitcode ("inc", "%s", l);
+ }
+
+ emitLabel (tlbl);
+ return TRUE;
+ }
+
+ /* if result is dptr */
+ if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
+ (AOP_SIZE (IC_RESULT (ic)) == 2) &&
+ !strncmp (AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) && !strncmp (AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
+ {
+ if (aopGetUsesAcc (IC_LEFT (ic), 0))
+ return FALSE;
+
+ if (icount > 9)
+ return FALSE;
+
+ if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
+ return FALSE;
+
+ aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
+ aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
+ while (icount--)
+ emitcode ("inc", "dptr");
+
+ return TRUE;
+ }
+
+ /* if the literal value of the right hand side
+ is greater than 4 then it is not worth it */
+ if (icount > 4)
+ return FALSE;
+
+ /* if the sizes are greater than 1 then we cannot */
+ if (AOP_SIZE (IC_RESULT (ic)) > 1 || AOP_SIZE (IC_LEFT (ic)) > 1)
+ return FALSE;
+
+ /* we can if the aops of the left & result match or
+ if they are in registers and the registers are the
+ same */
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ if (icount > 3)
+ {
+ MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
+ aopPut (IC_RESULT (ic), "a", 0);
+ }
+ else
+ {
+ while (icount--)
+ {
+ emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ }
+ }
+
+ return TRUE;
+ }
+
+ if (icount == 1)
+ {
+ MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("inc", "a");
+ aopPut (IC_RESULT (ic), "a", 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitAcc - output a bit in acc */
+/*-----------------------------------------------------------------*/
+static void
+outBitAcc (operand * result)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ aopPut (result, "a", 0);
+ }
+ else
+ {
+ emitcode ("jz", "!tlabel", labelKey2num (tlbl->key));
+ emitcode ("mov", "a,%s", one);
+ emitLabel (tlbl);
+ outAcc (result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlusBits - generates code for addition of two bits */
+/*-----------------------------------------------------------------*/
+static void
+genPlusBits (iCode * ic)
+{
+ D (emitcode (";", "genPlusBits"));
+
+ emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, labelKey2num (lbl->key));
+ emitcode ("cpl", "c");
+ emitLabel (lbl);
+ outBitC (IC_RESULT (ic));
+ }
+ else
+ {
+ emitcode ("clr", "a");
+ emitcode ("rlc", "a");
+ emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
+ emitcode ("addc", "a,%s", zero);
+ outAcc (IC_RESULT (ic));
+ }
+}
+
+static void
+adjustArithmeticResult (iCode * ic)
+{
+ if (opIsGptr (IC_RESULT (ic)))
+ {
+ struct dbuf_s dbuf;
+
+ if (opIsGptr (IC_LEFT (ic)))
+ {
+ if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
+ {
+ aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE), GPTRSIZE - 1);
+ }
+ return;
+ }
+
+ if (opIsGptr (IC_RIGHT (ic)))
+ {
+ if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
+ {
+ aopPut (IC_RESULT (ic), aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE), GPTRSIZE - 1);
+ }
+ return;
+ }
+
+ dbuf_init (&dbuf, 128);
+ if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
+ IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
+ !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
+ {
+ dbuf_printf (&dbuf, "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
+ aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1);
+ }
+ else if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
+ {
+ dbuf_printf (&dbuf, "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
+ aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1);
+ }
+ else if (IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
+ {
+ dbuf_printf (&dbuf, "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_RIGHT (ic)))), NULL, NULL));
+ aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1);
+ }
+ dbuf_destroy (&dbuf);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlus - generates code for addition */
+/*-----------------------------------------------------------------*/
+static void
+genPlus (iCode * ic)
+{
+ int size, offset = 0;
+ int skip_bytes = 0;
+ char *add = "add";
+ bool swappedLR = FALSE;
+ operand *leftOp, *rightOp;
+ operand *op;
+
+ D (emitcode (";", "genPlus"));
+
+ /* special cases :- */
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* if literal, literal on the right or
+ if left requires ACC or right is already
+ in ACC */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) || (AOP_NEEDSACC (IC_LEFT (ic))) || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
+ {
+ swapOperands (&IC_LEFT (ic), &IC_RIGHT (ic));
+ swappedLR = TRUE;
+ }
+
+ /* if both left & right are in bit space */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+ {
+ genPlusBits (ic);
+ goto release;
+ }
+
+ /* if left in bit space & right literal */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
+ {
+ emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
+ /* if result in bit space */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+ {
+ if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
+ emitcode ("cpl", "c");
+ outBitC (IC_RESULT (ic));
+ }
+ else
+ {
+ size = getDataSize (IC_RESULT (ic));
+ while (size--)
+ {
+ MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
+ emitcode ("addc", "a,%s", zero);
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+ }
+ goto release;
+ }
+
+ /* if I can do an increment instead
+ of add then GOOD for ME */
+ if (genPlusIncr (ic) == TRUE)
+ goto release;
+
+ size = getDataSize (IC_RESULT (ic));
+ leftOp = IC_LEFT (ic);
+ rightOp = IC_RIGHT (ic);
+ op = IC_LEFT (ic);
+
+ /* if this is an add for an array access
+ at a 256 byte boundary */
+ if (2 == size
+ && AOP_TYPE (op) == AOP_IMMD
+ && IS_SYMOP (op)
+ && IS_SPEC (OP_SYM_ETYPE (op)) && SPEC_ABSA (OP_SYM_ETYPE (op)) && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0)
+ {
+ D (emitcode (";", "genPlus aligned array"));
+ aopPut (IC_RESULT (ic), aopGet (rightOp, 0, FALSE, FALSE), 0);
+
+ if (1 == getDataSize (IC_RIGHT (ic)))
+ {
+ aopPut (IC_RESULT (ic), aopGet (leftOp, 1, FALSE, FALSE), 1);
+ }
+ else
+ {
+ MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
+ emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
+ aopPut (IC_RESULT (ic), "a", 1);
+ }
+ goto release;
+ }
+
+ /* if the lower bytes of a literal are zero skip the addition */
+ if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
+ {
+ while ((0 == ((unsigned int) ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes * 8))) &&
+ (skip_bytes + 1 < size))
+ {
+ skip_bytes++;
+ }
+ if (skip_bytes)
+ D (emitcode (";", "genPlus shortcut"));
+ }
+
+ while (size--)
+ {
+ if (offset >= skip_bytes)
+ {
+ if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
+ {
+ bool pushedB;
+ MOVA (aopGet (leftOp, offset, FALSE, FALSE));
+ pushedB = pushB ();
+ emitcode ("xch", "a,b");
+ MOVA (aopGet (rightOp, offset, FALSE, FALSE));
+ emitcode (add, "a,b");
+ popB (pushedB);
+ }
+ else if (aopGetUsesAcc (leftOp, offset))
+ {
+ MOVA (aopGet (leftOp, offset, FALSE, FALSE));
+ emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (rightOp, offset, FALSE, FALSE));
+ emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, FALSE));
+ }
+ aopPut (IC_RESULT (ic), "a", offset);
+ add = "addc"; /* further adds must propagate carry */
+ }
+ else
+ {
+ if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) || isOperandVolatile (IC_RESULT (ic), FALSE))
+ {
+ /* just move */
+ aopPut (IC_RESULT (ic), aopGet (leftOp, offset, FALSE, FALSE), offset);
+ }
+ }
+ offset++;
+ }
+
+ adjustArithmeticResult (ic);
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ if (swappedLR)
+ swapOperands (&IC_LEFT (ic), &IC_RIGHT (ic));
+ freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinusDec :- does subtraction with decrement if possible */
+/*-----------------------------------------------------------------*/
+static bool
+genMinusDec (iCode * ic)
+{
+ unsigned int icount;
+ unsigned int size = getDataSize (IC_RESULT (ic));
+
+ /* will try to generate a decrement */
+ /* if the right side is not a literal
+ we cannot */
+ if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
+ return FALSE;
+
+ /* if the literal value of the right hand side
+ is greater than 4 then it is not worth it */
+ if ((icount = (unsigned int) ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
+ return FALSE;
+
+ D (emitcode (";", "genMinusDec"));
+
+ /* if decrement >=16 bits in register or direct space */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
+ AOP_TYPE (IC_LEFT (ic)) == AOP_DIR ||
+ (IS_AOP_PREG (IC_LEFT (ic)) && !AOP_NEEDSACC (IC_LEFT (ic)))) &&
+ sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && (icount == 1))
+ {
+ symbol *tlbl;
+ const char *l;
+
+ tlbl = newiTempLabel (NULL);
+ l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE);
+ emitcode ("dec", "%s", l);
+
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ emitcode ("mov", "a,#!constbyte", 0xff);
+ emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key));
+ }
+ l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE);
+ emitcode ("dec", "%s", l);
+ if (size > 2)
+ {
+ if (EQ (l, "acc"))
+ {
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ }
+ else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key));
+ }
+ l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE);
+ emitcode ("dec", "%s", l);
+ }
+ if (size > 3)
+ {
+ if (EQ (l, "acc"))
+ {
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ }
+ else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key));
+ }
+ else
+ {
+ emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key));
+ }
+ emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
+ }
+ emitLabel (tlbl);
+ 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)
+ return FALSE;
+
+ /* we can if the aops of the left & result match or
+ if they are in registers and the registers are the
+ same */
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ const char *l;
+
+ if (aopGetUsesAcc (IC_LEFT (ic), 0))
+ {
+ MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
+ l = "a";
+ }
+ else
+ {
+ l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
+ }
+
+ while (icount--)
+ {
+ emitcode ("dec", "%s", l);
+ }
+
+ if (AOP_NEEDSACC (IC_RESULT (ic)))
+ aopPut (IC_RESULT (ic), "a", 0);
+
+ return TRUE;
+ }
+
+ if (icount == 1)
+ {
+ MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("dec", "a");
+ aopPut (IC_RESULT (ic), "a", 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* addSign - complete with sign */
+/*-----------------------------------------------------------------*/
+static void
+addSign (operand * result, int offset, int sign)
+{
+ int size = (getDataSize (result) - offset);
+ if (size > 0)
+ {
+ if (sign)
+ {
+ emitcode ("rlc", "a");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ {
+ aopPut (result, "a", offset++);
+ }
+ }
+ else
+ {
+ while (size--)
+ {
+ aopPut (result, zero, offset++);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinusBits - generates code for subtraction of two bits */
+/*-----------------------------------------------------------------*/
+static void
+genMinusBits (iCode * ic)
+{
+ symbol *lbl = newiTempLabel (NULL);
+
+ D (emitcode (";", "genMinusBits"));
+
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
+ emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, labelKey2num (lbl->key));
+ emitcode ("cpl", "c");
+ emitLabel (lbl);
+ outBitC (IC_RESULT (ic));
+ }
+ else
+ {
+ emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
+ emitcode ("subb", "a,acc");
+ emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, labelKey2num (lbl->key));
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ aopPut (IC_RESULT (ic), "a", 0);
+ addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinus - generates code for subtraction */
+/*-----------------------------------------------------------------*/
+static void
+genMinus (iCode * ic)
+{
+ int size, offset = 0;
+
+ D (emitcode (";", "genMinus"));
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* special cases :- */
+ /* if both left & right are in bit space */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+ {
+ genMinusBits (ic);
+ goto release;
+ }
+
+ /* if I can do a decrement instead
+ of subtract then GOOD for ME */
+ if (genMinusDec (ic) == TRUE)
+ goto release;
+
+ size = getDataSize (IC_RESULT (ic));
+
+ /* if literal, add a,#-lit, else normal subb */
+ if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
+ {
+ unsigned long long lit = 0L;
+ bool useCarry = FALSE;
+
+ lit = ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+ lit = -(long long) lit;
+
+ while (size--)
+ {
+ if (useCarry || ((lit >> (offset * 8)) & 0x0ffll))
+ {
+ MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
+ if (!offset && !size && lit == (unsigned long long) - 1)
+ {
+ emitcode ("dec", "a");
+ }
+ else if (!useCarry)
+ {
+ /* first add without previous c */
+ emitcode ("add", "a,#!constbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0ffll));
+ useCarry = TRUE;
+ }
+ else
+ {
+ emitcode ("addc", "a,#!constbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0ffll));
+ }
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+ else
+ {
+ /* no need to add zeroes */
+ if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
+ {
+ aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE), offset);
+ }
+ offset++;
+ }
+ }
+ }
+ else
+ {
+ operand *leftOp, *rightOp;
+
+ leftOp = IC_LEFT (ic);
+ rightOp = IC_RIGHT (ic);
+
+ while (size--)
+ {
+ if (aopGetUsesAcc (rightOp, offset))
+ {
+ if (aopGetUsesAcc (leftOp, offset))
+ {
+ bool pushedB;
+
+ MOVA (aopGet (rightOp, offset, FALSE, FALSE));
+ pushedB = pushB ();
+ emitcode ("mov", "b,a");
+ if (offset == 0)
+ CLRC;
+ MOVA (aopGet (leftOp, offset, FALSE, FALSE));
+ emitcode ("subb", "a,b");
+ popB (pushedB);
+ }
+ else
+ {
+ /* reverse subtraction with 2's complement */
+ if (offset == 0)
+ emitcode ("setb", "c");
+ else
+ emitcode ("cpl", "c");
+ wassertl (!aopGetUsesAcc (leftOp, offset), "accumulator clash");
+ MOVA (aopGet (rightOp, offset, FALSE, FALSE));
+ emitcode ("subb", "a,%s", aopGet (leftOp, offset, FALSE, FALSE));
+ emitcode ("cpl", "a");
+ if (size) /* skip if last byte */
+ emitcode ("cpl", "c");
+ }
+ }
+ else
+ {
+ MOVA (aopGet (leftOp, offset, FALSE, FALSE));
+ if (offset == 0)
+ CLRC;
+ emitcode ("subb", "a,%s", aopGet (rightOp, offset, FALSE, FALSE));
+ }
+
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+ }
+
+ adjustArithmeticResult (ic);
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMultbits :- multiplication of bits */
+/*-----------------------------------------------------------------*/
+static void
+genMultbits (operand * left, operand * right, operand * result)
+{
+ D (emitcode (";", "genMultbits"));
+
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
+ outBitC (result);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMultOneByte : 8*8=8/16 bit multiplication */
+/*-----------------------------------------------------------------*/
+static void
+genMultOneByte (operand * left, operand * right, operand * result)
+{
+ symbol *lbl;
+ int size = AOP_SIZE (result);
+ bool runtimeSign, compiletimeSign;
+ bool lUnsigned, rUnsigned, pushedB;
+
+ D (emitcode (";", "genMultOneByte"));
+
+ if (size < 1 || size > 2)
+ {
+ /* this should never happen */
+ fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", AOP_SIZE (result), __FILE__, lineno);
+ exit (EXIT_FAILURE);
+ }
+
+ /* (if two literals: the value is computed before) */
+ /* if one literal, literal on the right */
+ if (AOP_TYPE (left) == AOP_LIT || AOP_TYPE (right) == AOP_ACC)
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ /* emitcode (";", "swapped left and right"); */
+ }
+ /* if no literal, unsigned on the right: shorter code */
+ if (AOP_TYPE (right) != AOP_LIT && SPEC_USIGN (getSpec (operandType (left))))
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+ pushedB = pushB ();
+
+ if (size == 1 /* no, this is not a bug; with a 1 byte result there's
+ no need to take care about the signedness! */
+ || (lUnsigned && rUnsigned))
+ {
+ /* just an unsigned 8 * 8 = 8 multiply
+ or 8u * 8u = 16u */
+ /* emitcode (";","unsigned"); */
+ /* TODO: check for accumulator clash between left & right aops? */
+
+ /*if (AOP_TYPE (right) == AOP_ACC)
+ MOVB (aopGet (left, 0, FALSE, FALSE));
+ else*/ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* moving to accumulator first helps peepholes */
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ }
+ else
+ {
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ }
+
+ emitcode ("mul", "ab");
+ aopPut (result, "a", 0);
+ if (size == 2)
+ aopPut (result, "b", 1);
+
+ popB (pushedB);
+ return;
+ }
+
+ /* we have to do a signed multiply */
+ /* emitcode (";", "signed"); */
+
+ /* now sign adjust for both left & right */
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
+ }
+
+ /* save the signs of the operands */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
+
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#!constbyte", -val);
+ else
+ emitcode ("mov", "b,#!constbyte", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned) /* emitcode (";", "signed"); */
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
+
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#!constbyte", -val);
+ else
+ emitcode ("mov", "a,#!constbyte", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+
+ if (!lUnsigned)
+ {
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ }
+ }
+
+ /* now the multiplication */
+ emitcode ("mul", "ab");
+ if (runtimeSign || compiletimeSign)
+ {
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ if (size != 2)
+ emitcode ("inc", "a"); /* inc doesn't set carry flag */
+ else
+ {
+ emitcode ("add", "a,#0x01"); /* this sets carry flag */
+ emitcode ("xch", "a,b");
+ emitcode ("cpl", "a"); /* msb 2's complement */
+ emitcode ("addc", "a,#0x00");
+ emitcode ("xch", "a,b");
+ }
+ emitLabel (lbl);
+ }
+ aopPut (result, "a", 0);
+ if (size == 2)
+ aopPut (result, "b", 1);
+
+ popB (pushedB);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMult - generates code for multiplication */
+/*-----------------------------------------------------------------*/
+static void
+genMult (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ D (emitcode (";", "genMult"));
+
+ /* assign the asmops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ genMultbits (left, right, result);
+ goto release;
+ }
+
+ /* if both are of size == 1 */
+#if 0 // one of them can be a sloc shared with the result
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+#else
+ if (getSize (operandType (left)) == 1 && getSize (operandType (right)) == 1)
+#endif
+ {
+ genMultOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ fprintf (stderr, "left: %d right: %d\n", getSize (OP_SYMBOL (left)->type), getSize (OP_SYMBOL (right)->type));
+ assert (0);
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivbits :- division of bits */
+/*-----------------------------------------------------------------*/
+static void
+genDivbits (operand * left, operand * right, operand * result)
+{
+ bool pushedB;
+
+ D (emitcode (";", "genDivbits"));
+
+ pushedB = pushB ();
+
+ /* the result must be bit */
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+
+ emitcode ("div", "ab");
+ emitcode ("rrc", "a");
+
+ popB (pushedB);
+
+ aopPut (result, "c", 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivOneByte : 8 bit division */
+/*-----------------------------------------------------------------*/
+static void
+genDivOneByte (operand * left, operand * right, operand * result)
+{
+ bool lUnsigned, rUnsigned, pushedB;
+ bool runtimeSign, compiletimeSign;
+ bool accuse = FALSE;
+ bool pushedA = FALSE;
+ symbol *lbl;
+ int size, offset;
+
+ D (emitcode (";", "genDivOneByte"));
+
+ /* Why is it necessary that genDivOneByte() can return an int result?
+ Have a look at:
+
+ volatile unsigned char uc;
+ volatile signed char sc1, sc2;
+ volatile int i;
+
+ uc = 255;
+ sc1 = -1;
+ i = uc / sc1;
+
+ Or:
+
+ sc1 = -128;
+ sc2 = -1;
+ i = sc1 / sc2;
+
+ In all cases a one byte result would overflow, the following cast to int
+ would return the wrong result.
+
+ Two possible solution:
+ a) cast operands to int, if ((unsigned) / (signed)) or
+ ((signed) / (signed))
+ b) return an 16 bit signed int; this is what we're doing here!
+ */
+
+ size = AOP_SIZE (result) - 1;
+ offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+ pushedB = pushB ();
+
+ /* signed or unsigned */
+ if (lUnsigned && rUnsigned)
+ {
+ /* unsigned is easy */
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("div", "ab");
+ aopPut (result, "a", 0);
+ while (size--)
+ aopPut (result, zero, offset++);
+
+ popB (pushedB);
+ return;
+ }
+
+ /* signed is a little bit more difficult */
+
+ /* now sign adjust for both left & right */
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ if (!lUnsigned)
+ {
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign = TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ if (!rUnsigned)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* signed literal */
+ signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
+ if (val < 0)
+ compiletimeSign ^= TRUE;
+ }
+ else
+ /* signed but not literal */
+ runtimeSign = TRUE;
+ }
+
+ /* initialize F0, which stores the runtime sign */
+ if (runtimeSign)
+ {
+ if (compiletimeSign)
+ emitcode ("setb", "F0"); /* set sign flag */
+ else
+ emitcode ("clr", "F0"); /* reset sign flag */
+ }
+
+ /* save the signs of the operands */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
+
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
+
+ if (!lUnsigned && val < 0)
+ emitcode ("mov", "a,#0x%02x", -val);
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+
+ if (!lUnsigned)
+ {
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "F0"); /* complement sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ }
+ }
+
+ /* now the division */
+ emitcode ("div", "ab");
+
+ if (runtimeSign || compiletimeSign)
+ {
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "a"); /* lsb 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+
+ accuse = aopPut (result, "a", 0);
+ if (size > 0)
+ {
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ if (accuse)
+ {
+ emitpush ("acc");
+ pushedA = TRUE;
+ }
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (result, "a", offset++);
+ }
+ else /* compiletimeSign */
+ {
+ if (aopPutUsesAcc (result, "#0xff", offset))
+ {
+ emitpush ("acc");
+ pushedA = TRUE;
+ }
+ while (size--)
+ aopPut (result, "#0xff", offset++);
+ }
+ }
+ }
+ else
+ {
+ aopPut (result, "a", 0);
+ while (size--)
+ aopPut (result, zero, offset++);
+ }
+
+ if (pushedA)
+ emitpop ("acc");
+ popB (pushedB);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDiv - generates code for division */
+/*-----------------------------------------------------------------*/
+static void
+genDiv (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ D (emitcode (";", "genDiv"));
+
+ /* assign the asmops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ genDivbits (left, right, result);
+ goto release;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+ {
+ genDivOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genModbits :- modulus of bits */
+/*-----------------------------------------------------------------*/
+static void
+genModbits (operand * left, operand * right, operand * result)
+{
+ bool pushedB;
+
+ D (emitcode (";", "genModbits"));
+
+ pushedB = pushB ();
+
+ /* the result must be bit */
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+
+ emitcode ("div", "ab");
+ emitcode ("mov", "a,b");
+ emitcode ("rrc", "a");
+
+ popB (pushedB);
+
+ aopPut (result, "c", 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genModOneByte : 8 bit modulus */
+/*-----------------------------------------------------------------*/
+static void
+genModOneByte (operand * left, operand * right, operand * result)
+{
+ bool lUnsigned, rUnsigned, pushedB;
+ bool runtimeSign, compiletimeSign;
+ symbol *lbl;
+ int size, offset;
+
+ D (emitcode (";", "genModOneByte"));
+
+ size = AOP_SIZE (result) - 1;
+ offset = 1;
+ lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+ rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+
+ /* if right is a literal, check it for 2^n */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned char val = abs ((int) operandLitValue (right));
+ symbol *lbl2 = NULL;
+
+ switch (val)
+ {
+ case 1: /* sometimes it makes sense (on tricky code and hardware)... */
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ if (lUnsigned)
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "modulus of unsigned char by 2^n literal shouldn't be processed here");
+ /* because iCode should have been changed to genAnd */
+ /* see file "SDCCopt.c", function "convertToFcall()" */
+
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("mov", "c,acc.7");
+ emitcode ("anl", "a,#0x%02x", val - 1);
+ lbl = newiTempLabel (NULL);
+ emitcode ("jz", "!tlabel", labelKey2num (lbl->key));
+ emitcode ("jnc", "!tlabel", labelKey2num (lbl->key));
+ emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
+ if (size)
+ {
+ int size2 = size;
+ int offs2 = offset;
+
+ aopPut (result, "a", 0);
+ while (size2--)
+ aopPut (result, "#0xff", offs2++);
+ lbl2 = newiTempLabel (NULL);
+ emitcode ("sjmp", "!tlabel", labelKey2num (lbl2->key));
+ }
+ emitLabel (lbl);
+ aopPut (result, "a", 0);
+ while (size--)
+ aopPut (result, zero, offset++);
+ if (lbl2)
+ {
+ emitLabel (lbl2);
+ }
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ pushedB = pushB ();
+
+ /* signed or unsigned */
+ if (lUnsigned && rUnsigned)
+ {
+ /* unsigned is easy */
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("div", "ab");
+ aopPut (result, "b", 0);
+ while (size--)
+ aopPut (result, zero, offset++);
+
+ popB (pushedB);
+ return;
+ }
+
+ /* signed is a little bit more difficult */
+
+ /* now sign adjust for both left & right */
+
+ /* modulus: sign of the right operand has no influence on the result! */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ signed char val = (signed char) operandLitValue (right);
+
+ if (!rUnsigned && val < 0)
+ emitcode ("mov", "b,#0x%02x", -val);
+ else
+ emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+ }
+ else /* not literal */
+ {
+ if (rUnsigned)
+ emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
+ else
+ {
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ emitcode ("mov", "b,a");
+ }
+ }
+
+ /* let's see what's needed: */
+ /* apply negative sign during runtime */
+ runtimeSign = FALSE;
+ /* negative sign from literals */
+ compiletimeSign = FALSE;
+
+ /* sign adjust left side */
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
+
+ if (!lUnsigned && val < 0)
+ {
+ compiletimeSign = TRUE; /* set sign flag */
+ emitcode ("mov", "a,#0x%02x", -val);
+ }
+ else
+ emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+ }
+ else /* ! literal */
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+
+ if (!lUnsigned)
+ {
+ runtimeSign = TRUE;
+ emitcode ("clr", "F0"); /* clear sign flag */
+
+ lbl = newiTempLabel (NULL);
+ emitcode ("jnb", "acc.7,!tlabel", labelKey2num (lbl->key));
+ emitcode ("setb", "F0"); /* set sign flag */
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+ }
+ }
+
+ /* now the modulus */
+ emitcode ("div", "ab");
+
+ if (runtimeSign || compiletimeSign)
+ {
+ emitcode ("mov", "a,b");
+ lbl = newiTempLabel (NULL);
+ if (runtimeSign)
+ emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key));
+ emitcode ("cpl", "a"); /* 2's complement */
+ emitcode ("inc", "a");
+ emitLabel (lbl);
+
+ aopPut (result, "a", 0);
+ if (size > 0)
+ {
+ /* msb is 0x00 or 0xff depending on the sign */
+ if (runtimeSign)
+ {
+ emitcode ("mov", "c,F0");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (result, "a", offset++);
+ }
+ else /* compiletimeSign */
+ while (size--)
+ aopPut (result, "#0xff", offset++);
+ }
+ }
+ else
+ {
+ aopPut (result, "b", 0);
+ while (size--)
+ aopPut (result, zero, offset++);
+ }
+
+ popB (pushedB);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMod - generates code for division */
+/*-----------------------------------------------------------------*/
+static void
+genMod (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ D (emitcode (";", "genMod"));
+
+ /* assign the asmops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ genModbits (left, right, result);
+ goto release;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+ {
+ genModOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfxJump :- will create a jump depending on the ifx */
+/*-----------------------------------------------------------------*/
+static void
+genIfxJump (iCode * ic, const char *jval, operand * left, operand * right, operand * result, iCode * popIc)
+{
+ symbol *jlbl;
+ symbol *tlbl = newiTempLabel (NULL);
+ char *inst;
+
+ /* if there is something to be popped then do it first */
+ popForBranch (popIc, TRUE);
+
+ D (emitcode (";", "genIfxJump"));
+
+ /* if true label then we jump if condition
+ supplied is true */
+ if (IC_TRUE (ic))
+ {
+ jlbl = IC_TRUE (ic);
+ inst = ((EQ (jval, "a") ? "jz" : (EQ (jval, "c") ? "jnc" : "jnb")));
+ }
+ else
+ {
+ /* false label is present */
+ jlbl = IC_FALSE (ic);
+ inst = ((EQ (jval, "a") ? "jnz" : (EQ (jval, "c") ? "jc" : "jb")));
+ }
+ if (EQ (inst, "jb") || EQ (inst, "jnb"))
+ emitcode (inst, "%s,!tlabel", jval, labelKey2num (tlbl->key));
+ else
+ emitcode (inst, "!tlabel", labelKey2num (tlbl->key));
+ freeForBranchAsmops (result, right, left, ic);
+ emitcode ("ljmp", "!tlabel", labelKey2num (jlbl->key));
+ emitLabel (tlbl);
+
+ /* mark the icode as generated */
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmp :- greater or less than comparison */
+/*-----------------------------------------------------------------*/
+static void
+genCmp (operand * left, operand * right, operand * result, iCode * ifx, int sign, iCode * ic)
+{
+ int size, offset = 0;
+ unsigned long long lit = 0L;
+ bool rightInB;
+
+ D (emitcode (";", "genCmp"));
+
+ /* if left & right are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ /* generic pointers require special handling since all NULL pointers must compare equal */
+ else if (opIsGptr (left) || opIsGptr (right))
+ {
+ /* push right */
+ while (offset < GPTRSIZE)
+ {
+ emitpush (aopGet (right, offset++, FALSE, TRUE));
+ }
+ loadDptrFromOperand (left, TRUE);
+ emitcode ("lcall", "___gptr_cmp");
+ for (offset = 0; offset < GPTRSIZE; offset++)
+ emitpop (NULL);
+ }
+ else
+ {
+ /* subtract right from left if at the
+ end the carry flag is set then we know that
+ left is greater than right */
+ size = max (AOP_SIZE (left), AOP_SIZE (right));
+
+ /* if unsigned char cmp with lit, do cjne left,#right,zz */
+ if (size == 1 && !sign && AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE));
+ symbol *lbl = newiTempLabel (NULL);
+ emitcode ("cjne", "%s,%s,!tlabel", l, aopGet (right, offset, FALSE, FALSE), labelKey2num (lbl->key));
+ Safe_free (l);
+ emitLabel (lbl);
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = ullFromVal (AOP (right)->aopu.aop_lit);
+ /* optimize if(x < 0) or if(x >= 0) */
+ if (lit == 0ll)
+ {
+ if (!sign)
+ {
+ CLRC;
+ }
+ else
+ {
+ MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
+ if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+ {
+ genIfxJump (ifx, "acc.7", left, right, result, ic->next);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+
+ return;
+ }
+ else
+ {
+ emitcode ("rlc", "a");
+ }
+ }
+ goto release;
+ }
+ else
+ {
+ //nonzero literal
+ int bytelit = ((lit >> (offset * 8)) & 0x0ffll);
+ while (size && (bytelit == 0))
+ {
+ offset++;
+ bytelit = ((lit >> (offset * 8)) & 0x0ffll);
+ size--;
+ }
+ CLRC;
+ while (size--)
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ if (sign && size == 0)
+ {
+ emitcode ("xrl", "a,#0x80");
+ emitcode ("subb", "a,#0x%02x", 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0ffll));
+ }
+ else
+ {
+ emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ offset++;
+ }
+ goto release;
+ }
+ }
+ CLRC;
+ while (size--)
+ {
+ bool pushedB = FALSE;
+ rightInB = aopGetUsesAcc (right, offset);
+ if (rightInB)
+ {
+ pushedB = pushB ();
+ emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ if (sign && size == 0)
+ {
+ emitcode ("xrl", "a,#0x80");
+ if (!rightInB)
+ {
+ pushedB = pushB ();
+ rightInB++;
+ MOVB (aopGet (right, offset, FALSE, FALSE));
+ }
+ emitcode ("xrl", "b,#0x80");
+ emitcode ("subb", "a,b");
+ }
+ else
+ {
+ if (rightInB)
+ emitcode ("subb", "a,b");
+ else
+ emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ if (rightInB)
+ popB (pushedB);
+ offset++;
+ }
+ }
+ }
+
+release:
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
+ {
+ outBitC (result);
+ }
+ else
+ {
+ /* if the result is used in the next
+ ifx conditional branch then generate
+ code a little differently */
+ if (ifx)
+ {
+ genIfxJump (ifx, "c", NULL, NULL, result, ic->next);
+ }
+ else
+ {
+ outBitC (result);
+ }
+ /* leave the result in acc */
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpGt :- greater than comparison */
+/*-----------------------------------------------------------------*/
+static void
+genCmpGt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign = 0;
+
+ D (emitcode (";", "genCmpGt"));
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
+ {
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
+ (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
+ }
+ /* assign the asmops */
+ aopOp (result, ic, TRUE);
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+
+ genCmp (right, left, result, ifx, sign, ic);
+
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpLt - less than comparisons */
+/*-----------------------------------------------------------------*/
+static void
+genCmpLt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign = 0;
+
+ D (emitcode (";", "genCmpLt"));
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
+ {
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
+ (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
+ }
+ /* assign the asmops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ genCmp (left, right, result, ifx, sign, ic);
+
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjneshort - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencjneshort (operand * left, operand * right, symbol * lbl)
+{
+ int size = max (AOP_SIZE (left), AOP_SIZE (right));
+ int offset = 0;
+
+ D (emitcode (";", "gencjneshort"));
+
+ /* if the left side is a immediate/literal or
+ if the right is in a pointer register and left is not */
+ if (IS_AOP_IMMEDIATE (left) ||
+ (AOP_TYPE (left) == AOP_DIR && !IS_AOP_IMMEDIATE (right)) ||
+ (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+
+ /* generic pointers require special handling since all NULL pointers must compare equal */
+ if (opIsGptr (left) || opIsGptr (right))
+ {
+ /* push right */
+ while (offset < size)
+ {
+ emitpush (aopGet (right, offset++, FALSE, TRUE));
+ }
+ loadDptrFromOperand (left, TRUE);
+ emitcode ("lcall", "___gptr_cmp");
+ for (offset = 0; offset < GPTRSIZE; offset++)
+ emitpop (NULL);
+ emitcode ("jnz", "!tlabel", labelKey2num (lbl->key));
+ }
+
+ /* if the right side is a literal then anything goes */
+ else if (IS_AOP_IMMEDIATE (right) &&
+ AOP_TYPE (left) != AOP_DIR && !IS_AOP_IMMEDIATE (left))
+ {
+ while (size--)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE));
+ const char *r = aopGet (right, offset, FALSE, FALSE);
+ if (EQ (l, "a") && EQ (r, zero))
+ emitcode ("jnz", "!tlabel", labelKey2num (lbl->key));
+ else
+ emitcode ("cjne", "%s,%s,!tlabel", l, r, labelKey2num (lbl->key));
+ Safe_free (l);
+ offset++;
+ }
+ }
+
+ /* if the right side is in a register or in direct space or
+ if the left is a pointer register & right is not */
+ else if (AOP_TYPE (right) == AOP_REG ||
+ AOP_TYPE (right) == AOP_DIR ||
+ IS_AOP_IMMEDIATE (right) ||
+ (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int val[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ bool chk[8] = {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
+ int rsize = AOP_SIZE (right);
+ int pidx = -1;
+ int lidx, cidx;
+ unsigned long long lit = ullFromVal (AOP (right)->aopu.aop_lit);
+
+ switch (rsize)
+ {
+ case 8:
+ val[7] = (lit >> 56) & 0xff;
+ chk[7] = TRUE;
+ val[6] = (lit >> 48) & 0xff;
+ chk[6] = TRUE;
+ val[5] = (lit >> 40) & 0xff;
+ chk[5] = TRUE;
+ val[4] = (lit >> 32) & 0xff;
+ chk[4] = TRUE;
+ //fallthrough
+ case 4:
+ val[3] = (lit >> 24) & 0xff;
+ chk[3] = TRUE;
+ //fallthrough
+ case 3:
+ val[2] = (lit >> 16) & 0xff;
+ chk[2] = TRUE;
+ //fallthrough
+ case 2:
+ val[1] = (lit >> 8) & 0xff;
+ chk[1] = TRUE;
+ //fallthrough
+ default:
+ val[0] = (lit >> 0) & 0xff;
+ chk[0] = TRUE;
+ }
+ if (optimize.codeSize && (rsize > 1))
+ {
+ if ((!chk[0] || val[0] == 0x00) &&
+ (!chk[1] || val[1] == 0x00) &&
+ (!chk[2] || val[2] == 0x00) &&
+ (!chk[3] || val[3] == 0x00) &&
+ (!chk[4] || val[4] == 0x00) &&
+ (!chk[5] || val[5] == 0x00) &&
+ (!chk[6] || val[6] == 0x00) &&
+ (!chk[7] || val[7] == 0x00))
+ {
+ MOVA(aopGet(left, 0, FALSE, FALSE));
+ for (cidx = 1; cidx < size; cidx++)
+ if (chk[cidx])
+ emitcode ("orl", "a,%s", aopGet(left, cidx, FALSE, FALSE));
+ emitcode ("jnz", "%05d$", lbl->key + 100);
+ return;
+ }
+ if ((!chk[0] || val[0] == 0xFF) &&
+ (!chk[1] || val[1] == 0xFF) &&
+ (!chk[2] || val[2] == 0xFF) &&
+ (!chk[3] || val[3] == 0xFF) &&
+ (!chk[4] || val[4] == 0xFF) &&
+ (!chk[5] || val[5] == 0xFF) &&
+ (!chk[6] || val[6] == 0xFF) &&
+ (!chk[7] || val[7] == 0xFF))
+ {
+ MOVA(aopGet(left, 0, FALSE, FALSE));
+ for (cidx = 1; cidx < size; cidx++)
+ if (chk[cidx])
+ emitcode ("anl", "a,%s", aopGet(left, cidx, FALSE, FALSE));
+ emitcode ("cjne", "a,#0xFF,%05d$", lbl->key + 100);
+ return;
+ }
+ }
+
+ for (lidx = 0; lidx < size; lidx++)
+ {
+ if (chk[lidx] && !aopGetUsesAcc(left, lidx))
+ {
+ if (pidx >= 0)
+ {
+ if (val[pidx] == val[lidx])
+ {
+ chk[lidx] = FALSE;
+ }
+ if ((~val[pidx] & 0xff) == val[lidx])
+ {
+ emitcode ("cpl", "a");
+ chk[lidx] = FALSE;
+ }
+ else if (((val[pidx] + 1) & 0xff) == val[lidx])
+ {
+ emitcode ("inc", "a");
+ chk[lidx] = FALSE;
+ }
+ else if (((val[pidx] - 1) & 0xff) == val[lidx])
+ {
+ emitcode ("dec", "a");
+ chk[lidx] = FALSE;
+ }
+ }
+ pidx = lidx;
+ if (chk[lidx])
+ {
+ MOVA(aopGet(right, lidx, FALSE, FALSE));
+ chk[lidx] = FALSE;
+ }
+ emitcode ("cjne", "a,%s,%05d$", aopGet(left, lidx, FALSE, TRUE), lbl->key + 100);
+
+ for (cidx = lidx + 1; cidx < size; cidx++)
+ {
+ if (chk[cidx] && val[lidx] == val[cidx] && !IS_AOP_PREG (left))
+ {
+ chk[cidx] = FALSE;
+ emitcode ("cjne", "a,%s,%05d$", aopGet(left, cidx, FALSE, TRUE), lbl->key + 100);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ while (size--)
+ {
+ const char *r;
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ r = aopGet (right, offset, FALSE, TRUE);
+ if (EQ (r, zero))
+ emitcode ("jnz", "!tlabel", labelKey2num (lbl->key));
+ else
+ emitcode ("cjne", "a,%s,!tlabel", r, labelKey2num (lbl->key));
+ offset++;
+ }
+ }
+ else
+ {
+ /* right is a pointer reg need both a & b */
+ while (size--)
+ {
+ //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
+ wassertl (!BINUSE, "B was in use");
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("cjne", "a,b,!tlabel", labelKey2num (lbl->key));
+ offset++;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjne - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ D (emitcode (";", "gencjne"));
+
+ gencjneshort (left, right, lbl);
+
+ if (useCarry)
+ SETC;
+ else
+ MOVA (one);
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl->key));
+ emitLabel (lbl);
+ if (useCarry)
+ CLRC;
+ else
+ MOVA (zero);
+ emitLabel (tlbl);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpEq - generates code for equal to */
+/*-----------------------------------------------------------------*/
+static void
+genCmpEq (iCode * ic, iCode * ifx)
+{
+ bool swappedLR = FALSE;
+ operand *left, *right, *result;
+ iCode *popIc = ic->next;
+
+ D (emitcode (";", "genCmpEq"));
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ /* if literal, literal on the right or
+ if the right is in a pointer register and left
+ is not */
+ if ((AOP_TYPE (left) == AOP_LIT) || (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
+ {
+ swapOperands (&left, &right);
+ swappedLR = TRUE;
+ }
+
+ if (ifx && !AOP_SIZE (result))
+ {
+ symbol *tlbl;
+ /* if they are both bit variables */
+ if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ if (lit == 0L)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("cpl", "c");
+ }
+ else if (lit == 1L)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ emitcode ("clr", "c");
+ }
+ /* AOP_TYPE(right) == AOP_CRY */
+ }
+ else
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, labelKey2num ((lbl->key)));
+ emitcode ("cpl", "c");
+ emitLabel (lbl);
+ }
+ /* if true label then we jump if condition
+ supplied is true */
+ tlbl = newiTempLabel (NULL);
+ if (IC_TRUE (ifx))
+ {
+ emitcode ("jnc", "!tlabel", labelKey2num (tlbl->key));
+ freeForBranchAsmops (result, right, left, ic);
+ popForBranch (popIc, FALSE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key));
+ }
+ else
+ {
+ emitcode ("jc", "!tlabel", labelKey2num (tlbl->key));
+ freeForBranchAsmops (result, right, left, ic);
+ popForBranch (popIc, FALSE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ifx)->key));
+ }
+ emitLabel (tlbl);
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ gencjneshort (left, right, tlbl);
+ if (IC_TRUE (ifx))
+ {
+ freeForBranchAsmops (result, right, left, ic);
+ popForBranch (popIc, FALSE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key));
+ emitLabel (tlbl);
+ }
+ else
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key));
+ emitLabel (tlbl);
+ freeForBranchAsmops (result, right, left, ic);
+ popForBranch (popIc, FALSE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ifx)->key));
+ emitLabel (lbl);
+ }
+ }
+ /* mark the icode as generated */
+ ifx->generated = 1;
+ goto release;
+ }
+
+ /* if they are both bit variables */
+ if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ if (lit == 0L)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("cpl", "c");
+ }
+ else if (lit == 1L)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ emitcode ("clr", "c");
+ }
+ /* AOP_TYPE(right) == AOP_CRY */
+ }
+ else
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, labelKey2num (lbl->key));
+ emitcode ("cpl", "c");
+ emitLabel (lbl);
+ }
+ /* c = 1 if egal */
+ if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
+ {
+ outBitC (result);
+ goto release;
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, "c", left, right, result, popIc);
+ goto release;
+ }
+ /* if the result is used in an arithmetic operation
+ then put the result in place */
+ outBitC (result);
+ }
+ else
+ {
+ bool useCarry = (AOP_TYPE (result) == AOP_CRY);
+ gencjne (left, right, newiTempLabel (NULL), useCarry);
+ if (useCarry && AOP_SIZE (result))
+ {
+ aopPut (result, "c", 0);
+ goto release;
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, useCarry ? "c" : "a", left, right, result, popIc);
+ goto release;
+ }
+ /* if the result is used in an arithmetic operation
+ then put the result in place */
+ if (!useCarry)
+ outAcc (result);
+ /* leave the result in acc */
+ }
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ if (swappedLR)
+ swapOperands (&left, &right);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* hasInc - operand is incremented before any other use */
+/*-----------------------------------------------------------------*/
+static iCode *
+hasInc (operand * op, iCode * ic, int osize)
+{
+ sym_link *type = operandType (op);
+ sym_link *retype = getSpec (type);
+ iCode *lic = ic->next;
+ int isize;
+
+ /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
+ if (!IS_SYMOP (op))
+ return NULL;
+
+ if (IS_BITVAR (retype) || !IS_PTR (type))
+ return NULL;
+ if (IS_AGGREGATE (type->next))
+ return NULL;
+ if (osize != (isize = getSize (type->next)))
+ return NULL;
+
+ while (lic)
+ {
+ /* if operand of the form op = op + <sizeof *op> */
+ if (lic->op == '+' && isOperandEqual (IC_LEFT (lic), op) &&
+ isOperandEqual (IC_RESULT (lic), op) &&
+ isOperandLiteral (IC_RIGHT (lic)) && operandLitValue (IC_RIGHT (lic)) == isize)
+ {
+ return lic;
+ }
+ /* if the operand used or deffed */
+ if (bitVectBitValue (OP_USES (op), lic->key) || lic->defKey == op->key)
+ {
+ return NULL;
+ }
+ /* if GOTO or IFX */
+ if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL)
+ break;
+ lic = lic->next;
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAndOp - for && operation */
+/*-----------------------------------------------------------------*/
+static void
+genAndOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl;
+
+ D (emitcode (";", "genAndOp"));
+
+ /* note here that && operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE);
+
+ /* if both are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
+ outBitC (result);
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ toBoolean (left);
+ emitcode ("jz", "!tlabel", labelKey2num (tlbl->key));
+ toBoolean (right);
+ emitLabel (tlbl);
+ outBitAcc (result);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genOrOp - for || operation */
+/*-----------------------------------------------------------------*/
+static void
+genOrOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl;
+
+ D (emitcode (";", "genOrOp"));
+
+ /* note here that || operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE);
+
+ /* if both are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
+ outBitC (result);
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ toBoolean (left);
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ toBoolean (right);
+ emitLabel (tlbl);
+ outBitAcc (result);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* isLiteralBit - test if lit == 2^n */
+/*-----------------------------------------------------------------*/
+static int
+isLiteralBit (unsigned long long lit)
+{
+ unsigned long long w = 1;
+ int idx;
+
+ for (idx = 0; idx < 64; idx++, w<<=1)
+ if (lit == w)
+ return idx + 1;
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* continueIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+continueIfTrue (iCode * ic, iCode * popIc)
+{
+ if (IC_TRUE (ic))
+ {
+ popForBranch (popIc, TRUE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ic)->key));
+ }
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+jumpIfTrue (iCode * ic, iCode * popIc)
+{
+ if (!IC_TRUE (ic))
+ {
+ popForBranch (popIc, TRUE);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ic)->key));
+ }
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse - */
+/*-----------------------------------------------------------------*/
+static void
+jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand * left, operand * right, operand * result, iCode * popIc)
+{
+ // ugly but optimized by peephole
+ if (IC_TRUE (ic))
+ {
+ symbol *nlbl = newiTempLabel (NULL);
+ emitcode ("sjmp", "!tlabel", labelKey2num (nlbl->key));
+ emitLabel (tlbl);
+ popForBranch (popIc, FALSE);
+ freeForBranchAsmops (result, right, left, ic);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ic)->key));
+ emitLabel (nlbl);
+ }
+ else
+ {
+ popForBranch (popIc, FALSE);
+ freeForBranchAsmops (result, right, left, ic);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ic)->key));
+ emitLabel (tlbl);
+ }
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAnd - code for and */
+/*-----------------------------------------------------------------*/
+static void
+genAnd (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long long lit = 0ull;
+ int bytelit = 0;
+
+ D (emitcode (";", "genAnd"));
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+#ifdef DEBUG_TYPE
+ emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right));
+ emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right));
+#endif
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange left and right */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = ullFromVal (AOP (right)->aopu.aop_lit);
+ }
+
+ size = AOP_SIZE (result);
+
+ // if(bit & yy)
+ // result = bit & yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ // c = bit & literal;
+ if (lit & 1)
+ {
+ if (size && sameRegs (AOP (result), AOP (left)))
+ // no change
+ goto release;
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ // bit(result) = 0;
+ if (size && (AOP_TYPE (result) == AOP_CRY))
+ {
+ emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+ if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ {
+ jumpIfTrue (ifx, ic->next);
+ goto release;
+ }
+ emitcode ("clr", "c");
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ // c = bit & bit;
+ if (IS_OP_ACCUSE (left))
+ {
+ emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
+ }
+ else if (IS_OP_ACCUSE (right))
+ {
+ emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ else if (AOP_TYPE (right) == AOP_DIR && IS_BOOL (operandType (right)) && AOP_TYPE (left) == AOP_CRY)
+ {
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ emitcode ("anl", "c,acc.0");
+ }
+ else
+ {
+ // c = bit & val;
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ // c = lsb
+ emitcode ("rrc", "a");
+ emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ // bit = c
+ // val = c
+ if (size)
+ outBitC (result);
+ // if(bit & ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c", left, right, result, ic->next);
+ goto release;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
+ {
+ int posbit = isLiteralBit (lit);
+ /* left & 2^n */
+ if (posbit)
+ {
+ posbit--;
+ MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
+ // bit = left & 2^n
+ if (size)
+ {
+ switch (posbit & 0x07)
+ {
+ case 0:
+ emitcode ("rrc", "a");
+ break;
+ case 7:
+ emitcode ("rlc", "a");
+ break;
+ default:
+ emitcode ("mov", "c,acc.%d", posbit & 0x07);
+ break;
+ }
+ }
+ // if(left & 2^n)
+ else
+ {
+ if (ifx)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "acc.%d", posbit & 0x07);
+ genIfxJump (ifx, dbuf_c_str (&dbuf), left, right, result, ic->next);
+ dbuf_destroy (&dbuf);
+ }
+ else
+ {
+ emitcode ("anl", "a,#!constbyte", 1 << (posbit & 0x07));
+ }
+ goto release;
+ }
+ }
+ else
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+ if (size)
+ emitcode ("setb", "c");
+ while (sizel--)
+ {
+ if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ // byte == 2^n ?
+ if ((posbit = isLiteralBit (bytelit)) != 0)
+ emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, labelKey2num (tlbl->key));
+ else
+ {
+ if (bytelit != 0x0FFL)
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, TRUE));
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ }
+ }
+ offset++;
+ }
+ // bit = left & literal
+ if (size)
+ {
+ emitcode ("clr", "c");
+ emitLabel (tlbl);
+ }
+ // if(left & literal)
+ else
+ {
+ if (ifx)
+ jmpTrueOrFalse (ifx, tlbl, left, right, result, ic->next);
+ else
+ emitLabel (tlbl);
+ goto release;
+ }
+ }
+ outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0ffull);
+ if (bytelit == 0x0FF)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ else
+ continue;
+ }
+ else if (bytelit == 0)
+ {
+ aopPut (result, zero, offset);
+ }
+ else if (IS_AOP_PREG (result))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else if (AOP_TYPE (left) != AOP_DPTR)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("anl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ }
+ else
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("anl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ aopPut (result, "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ if (offset)
+ emitcode ("mov", "b,a");
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ aopPut (result, "a", offset);
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ if (IS_AOP_PREG (result))
+ {
+ emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left & right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
+ if (size)
+ emitcode ("setb", "c");
+ while (sizer--)
+ {
+ if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ emitLabel (tlbl);
+ outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl, left, right, result, ic->next);
+ else
+ emitLabel (tlbl);
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0ffull);
+ if (bytelit == 0x0FF)
+ {
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), offset);
+ continue;
+ }
+ else if (bytelit == 0)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ aopPut (result, zero, offset);
+ continue;
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("anl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, l, offset);
+ Safe_free (l);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+ aopPut (result, "a", offset);
+ }
+ }
+ }
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genOr - code for or */
+/*-----------------------------------------------------------------*/
+static void
+genOr (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+
+ D (emitcode (";", "genOr"));
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+#ifdef DEBUG_TYPE
+ emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right));
+ emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right));
+#endif
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange left and right */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ }
+
+ size = AOP_SIZE (result);
+
+ // if(bit | yy)
+ // xx = bit | yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ // c = bit | literal;
+ if (lit)
+ {
+ // lit != 0 => result = 1
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if (size)
+ emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
+ else if (ifx)
+ continueIfTrue (ifx, ic->next);
+ goto release;
+ }
+ emitcode ("setb", "c");
+ }
+ else
+ {
+ // lit == 0 => result = left
+ if (size && sameRegs (AOP (result), AOP (left)))
+ goto release;
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ // c = bit | bit;
+ if (IS_OP_ACCUSE (left))
+ {
+ emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
+ }
+ else if (IS_OP_ACCUSE (right))
+ {
+ emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ else
+ {
+ // c = bit | val;
+ if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("jb", "%s,!tlabel", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key));
+ toBoolean (right);
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ jmpTrueOrFalse (ifx, tlbl, left, right, result, ic->next);
+ goto release;
+ }
+ else
+ {
+ toCarry (right);
+ emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ }
+ // bit = c
+ // val = c
+ if (size)
+ outBitC (result);
+ // if(bit | ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c", left, right, result, ic->next);
+ goto release;
+ }
+
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
+ {
+ if (lit)
+ {
+ // result = 1
+ if (size)
+ emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
+ else if (ifx)
+ continueIfTrue (ifx, ic->next);
+ goto release;
+ }
+ else
+ {
+ // lit = 0, result = boolean(left)
+ if (size)
+ SETC;
+ toBoolean (left);
+ if (size)
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ CLRC;
+ emitLabel (tlbl);
+ }
+ else
+ {
+ /* FIXME, thats pretty fishy, check for ifx!=0, testcase .. */
+ assert (ifx);
+ genIfxJump (ifx, "a", left, right, result, ic->next);
+ goto release;
+ }
+ }
+ outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
+ if (bytelit == 0)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ else
+ continue;
+ }
+ else if (bytelit == 0x0FF)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ aopPut (result, "#0xff", offset);
+ }
+ else if (IS_AOP_PREG (left))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else if (AOP_TYPE (left) != AOP_DPTR)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("orl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ }
+ else
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("orl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ aopPut (result, "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ if (offset)
+ emitcode ("mov", "b,a");
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ aopPut (result, "a", offset);
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ if (IS_AOP_PREG (left))
+ {
+ emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left | right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
+ if (size)
+ emitcode ("setb", "c");
+ while (sizer--)
+ {
+ if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ emitLabel (tlbl);
+ outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl, left, right, result, ic->next);
+ else
+ emitLabel (tlbl);
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left | right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
+ if (bytelit == 0)
+ {
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), offset);
+ continue;
+ }
+ else if (bytelit == 0x0FF)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ aopPut (result, "#0xff", offset);
+ continue;
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ // this should be the only use of left so A,B can be overwritten
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("orl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, l, offset);
+ Safe_free (l);
+ continue;
+ }
+ }
+ // faster than result <- left, orl result,right
+ // and better if result is SFR
+ if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+ aopPut (result, "a", offset);
+ }
+ }
+ }
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genXor - code for xclusive or */
+/*-----------------------------------------------------------------*/
+static void
+genXor (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+
+ D (emitcode (";", "genXor"));
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+#ifdef DEBUG_TYPE
+ emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right));
+ emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right));
+#endif
+
+ /* if left is a literal & right is not ||
+ if left needs acc & right does not */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange left and right */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ }
+
+ size = AOP_SIZE (result);
+
+ // if(bit ^ yy)
+ // xx = bit ^ yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ // c = bit ^ literal;
+ if (lit >> 1)
+ {
+ // lit>>1 != 0 => result = 1
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if (size)
+ emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
+ else if (ifx)
+ continueIfTrue (ifx, ic->next);
+ goto release;
+ }
+ emitcode ("setb", "c");
+ }
+ else
+ {
+ // lit == (0 or 1)
+ if (lit == 0)
+ {
+ // lit == 0, result = left
+ if (size && sameRegs (AOP (result), AOP (left)))
+ goto release;
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ // lit == 1, result = not(left)
+ if (size && sameRegs (AOP (result), AOP (left)))
+ {
+ emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+ else
+ {
+ emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ emitcode ("cpl", "c");
+ }
+ }
+ }
+ }
+ else
+ {
+ // right != literal
+ symbol *tlbl = newiTempLabel (NULL);
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ // c = bit ^ bit;
+ if (IS_OP_ACCUSE (left))
+ {
+ // left already is in the carry
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ else
+ {
+ toCarry (right);
+ }
+ }
+ else
+ {
+ // c = bit ^ val
+ toCarry (right);
+ }
+ emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key));
+ emitcode ("cpl", "c");
+ emitLabel (tlbl);
+ }
+ // bit = c
+ // val = c
+ if (size)
+ outBitC (result);
+ // if(bit ^ ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c", left, right, result, ic->next);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
+ if (bytelit == 0)
+ {
+ /* dummy read of volatile operand */
+ if (isOperandVolatile (left, FALSE))
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ else
+ continue;
+ }
+ else if (IS_AOP_PREG (left))
+ {
+ MOVA (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else if (AOP_TYPE (left) != AOP_DPTR)
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("xrl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ }
+ else
+ {
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE));
+ emitcode ("xrl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ Safe_free (l);
+ aopPut (result, "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ if (offset)
+ emitcode ("mov", "b,a");
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ aopPut (result, "a", offset);
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ if (IS_AOP_PREG (left))
+ {
+ emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left ^ right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
+
+ if (size)
+ emitcode ("setb", "c");
+ while (sizer--)
+ {
+ if ((AOP_TYPE (right) == AOP_LIT) && (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ }
+ else if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+
+ emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ emitLabel (tlbl);
+ outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl, left, right, result, ic->next);
+ else
+ emitLabel (tlbl);
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left ^ right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
+ if (bytelit == 0)
+ {
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), offset);
+ continue;
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ // this should be the only use of left so A,B can be overwritten
+ char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("xrl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE));
+ aopPut (result, l, offset);
+ Safe_free (l);
+ continue;
+ }
+ }
+ // faster than result <- left, xrl result,right
+ // and better if result is SFR
+ if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR)
+ && AOP_TYPE (left) == AOP_ACC)
+ {
+ if (offset)
+ emitcode ("mov", "a,b");
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else if (AOP_TYPE (left) == AOP_ACC)
+ {
+ if (!offset)
+ {
+ //B contains high byte of left
+ emitpush ("b");
+ emitcode ("mov", "b,a");
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ emitpop ("b");
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ }
+ }
+ else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
+ {
+ MOVB (aopGet (left, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,b");
+ }
+ else if (aopGetUsesAcc (left, offset))
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, FALSE));
+ }
+ aopPut (result, "a", offset);
+ }
+ }
+ }
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRRC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset;
+
+ D (emitcode (";", "genRRC"));
+
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* move it to the result */
+ size = AOP_SIZE (result);
+ offset = size - 1;
+ if (size == 1)
+ {
+ /* special case for 1 byte */
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("rr", "a");
+ goto release;
+ }
+ /* no need to clear carry, bit7 will be written later */
+ while (size--)
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ if (AOP_SIZE (result) > 1)
+ aopPut (result, "a", offset--);
+ }
+ /* now we need to put the carry into the
+ highest order byte of the result */
+ if (AOP_SIZE (result) > 1)
+ {
+ MOVA (aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE));
+ }
+ emitcode ("mov", "acc.7,c");
+release:
+ aopPut (result, "a", AOP_SIZE (result) - 1);
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRLC - generate code for rotate left with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRLC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset;
+
+ D (emitcode (";", "genRLC"));
+
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* move it to the result */
+ size = AOP_SIZE (result);
+ offset = 0;
+ if (size--)
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ if (size == 0)
+ {
+ /* special case for 1 byte */
+ emitcode ("rl", "a");
+ goto release;
+ }
+ emitcode ("rlc", "a"); /* bit0 will be written later */
+ if (AOP_SIZE (result) > 1)
+ {
+ aopPut (result, "a", offset++);
+ }
+
+ while (size--)
+ {
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ if (AOP_SIZE (result) > 1)
+ aopPut (result, "a", offset++);
+ }
+ }
+ /* now we need to put the carry into the
+ highest order byte of the result */
+ if (AOP_SIZE (result) > 1)
+ {
+ MOVA (aopGet (result, 0, FALSE, FALSE));
+ }
+ emitcode ("mov", "acc.0,c");
+release:
+ aopPut (result, "a", 0);
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetAbit - generates code get a single bit */
+/*-----------------------------------------------------------------*/
+static void
+genGetAbit (iCode * ic)
+{
+ operand *left, *right, *result;
+ int shCount;
+
+ D (emitcode (";", "genGetAbit"));
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+
+ /* get the needed byte into a */
+ MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
+ shCount %= 8;
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if ((shCount) == 7)
+ emitcode ("rlc", "a");
+ else if ((shCount) == 0)
+ emitcode ("rrc", "a");
+ else
+ emitcode ("mov", "c,acc[%d]", shCount);
+ outBitC (result);
+ }
+ else
+ {
+ switch (shCount)
+ {
+ case 2:
+ emitcode ("rr", "a");
+ //fallthrough
+ case 1:
+ emitcode ("rr", "a");
+ //fallthrough
+ case 0:
+ emitcode ("anl", "a,#0x01");
+ break;
+ case 3:
+ case 5:
+ emitcode ("mov", "c,acc[%d]", shCount);
+ emitcode ("clr", "a");
+ emitcode ("rlc", "a");
+ break;
+ case 4:
+ emitcode ("swap", "a");
+ emitcode ("anl", "a,#0x01");
+ break;
+ case 6:
+ emitcode ("rl", "a");
+ //fallthrough
+ case 7:
+ emitcode ("rl", "a");
+ emitcode ("anl", "a,#0x01");
+ break;
+ }
+ outAcc (result);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetByte - generates code get a single byte */
+/*-----------------------------------------------------------------*/
+static void
+genGetByte (iCode * ic)
+{
+ operand *left, *right, *result;
+ int offset;
+
+ D (emitcode (";", "genGetByte"));
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), 0);
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetWord - generates code get two bytes */
+/*-----------------------------------------------------------------*/
+static void
+genGetWord (iCode * ic)
+{
+ operand *left, *right, *result;
+ int offset;
+
+ D (emitcode (";", "genGetWord"));
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), 0);
+ aopPut (result, aopGet (left, offset + 1, FALSE, FALSE), 1);
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genSwap - generates code to swap nibbles or bytes */
+/*-----------------------------------------------------------------*/
+static void
+genSwap (iCode * ic)
+{
+ operand *left, *result;
+
+ D (emitcode (";", "genSwap"));
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ switch (AOP_SIZE (left))
+ {
+ case 1: /* swap nibbles in byte */
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("swap", "a");
+ aopPut (result, "a", 0);
+ break;
+ case 2: /* swap bytes in word */
+ if (AOP_TYPE (left) == AOP_REG && sameRegs (AOP (left), AOP (result)))
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
+ aopPut (result, "a", 1);
+ }
+ else if (operandsEqu (left, result))
+ {
+ char *reg = "a";
+ bool pushedB = FALSE, leftInB = FALSE;
+
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ if (aopGetUsesAcc (left, 1) || aopGetUsesAcc (result, 0))
+ {
+ pushedB = pushB ();
+ emitcode ("mov", "b,a");
+ reg = "b";
+ leftInB = TRUE;
+ }
+ aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
+ aopPut (result, reg, 1);
+
+ if (leftInB)
+ popB (pushedB);
+ }
+ else
+ {
+ aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
+ aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
+ }
+ break;
+ default:
+ wassertl (FALSE, "unsupported SWAP operand size");
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRol - rotate left accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRol (int shCount)
+{
+ shCount &= 0x0007; // shCount : 0..7
+
+ switch (shCount)
+ {
+ case 0:
+ break;
+ case 1:
+ emitcode ("rl", "a");
+ break;
+ case 2:
+ emitcode ("rl", "a");
+ emitcode ("rl", "a");
+ break;
+ case 3:
+ emitcode ("swap", "a");
+ emitcode ("rr", "a");
+ break;
+ case 4:
+ emitcode ("swap", "a");
+ break;
+ case 5:
+ emitcode ("swap", "a");
+ emitcode ("rl", "a");
+ break;
+ case 6:
+ emitcode ("rr", "a");
+ emitcode ("rr", "a");
+ break;
+ case 7:
+ emitcode ("rr", "a");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccLsh - left shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccLsh (int shCount)
+{
+ if (shCount != 0)
+ {
+ if (shCount == 1)
+ emitcode ("add", "a,acc");
+ else if (shCount == 2)
+ {
+ emitcode ("add", "a,acc");
+ emitcode ("add", "a,acc");
+ }
+ else
+ {
+ /* rotate left accumulator */
+ AccRol (shCount);
+ /* and kill the lower order bits */
+ emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRsh (int shCount)
+{
+ if (shCount != 0)
+ {
+ if (shCount == 1)
+ {
+ CLRC;
+ emitcode ("rrc", "a");
+ }
+ else
+ {
+ /* rotate right accumulator */
+ AccRol (8 - shCount);
+ /* and kill the higher order bits */
+ emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccSRsh - signed right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccSRsh (int shCount)
+{
+ symbol *tlbl;
+ if (shCount != 0)
+ {
+ if (shCount == 1)
+ {
+ emitcode ("mov", "c,acc.7");
+ emitcode ("rrc", "a");
+ }
+ else if (shCount == 2)
+ {
+ emitcode ("mov", "c,acc.7");
+ emitcode ("rrc", "a");
+ emitcode ("mov", "c,acc.7");
+ emitcode ("rrc", "a");
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ /* rotate right accumulator */
+ AccRol (8 - shCount);
+ /* and kill the higher order bits */
+ emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
+ emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, labelKey2num (tlbl->key));
+ emitcode ("orl", "a,#!constbyte", (unsigned char) ~SRMask[shCount]);
+ emitLabel (tlbl);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR1Left2Result - shift right one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR1Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign)
+{
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ /* shift right accumulator */
+ if (sign)
+ AccSRsh (shCount);
+ else
+ AccRsh (shCount);
+ aopPut (result, "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL1Left2Result - shift left one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL1Left2Result (operand * left, int offl, operand * result, int offr, int shCount)
+{
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ /* shift left accumulator */
+ AccLsh (shCount);
+ aopPut (result, "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* movLeft2Result - move byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+movLeft2Result (operand * left, int offl, operand * result, int offr, int sign)
+{
+ const char *l;
+ if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
+ {
+ l = aopGet (left, offl, FALSE, FALSE);
+
+ if (*l == '@' && (IS_AOP_PREG (result)))
+ {
+ emitcode ("mov", "a,%s", l);
+ aopPut (result, "a", offr);
+ }
+ else
+ {
+ if (!sign)
+ {
+ aopPut (result, l, offr);
+ }
+ else
+ {
+ /* MSB sign in acc.7 ! */
+ if (getDataSize (left) == offl + 1)
+ {
+ MOVA (l);
+ aopPut (result, "a", offr);
+ }
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRrl1 - right rotate c->a:x->c by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRrl1 (const char *x)
+{
+ emitcode ("rrc", "a");
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rrc", "a");
+ emitcode ("xch", "a,%s", x);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLrl1 (const char *x)
+{
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rlc", "a");
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rlc", "a");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh1 - left shift a:x<-0 by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLsh1 (const char *x)
+{
+ emitcode ("xch", "a,%s", x);
+ emitcode ("add", "a,acc");
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rlc", "a");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh - left shift a:x by known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLsh (const char *x, int shCount)
+{
+ unsigned char mask;
+
+ switch (shCount)
+ {
+ case 0:
+ break;
+ case 1:
+ AccAXLsh1 (x);
+ break;
+ case 2:
+ AccAXLsh1 (x);
+ AccAXLsh1 (x);
+ break;
+ case 3:
+ case 4:
+ case 5: // AAAAABBB:CCCCCDDD
+ mask = SLMask[shCount];
+ AccRol (shCount); // BBBAAAAA:CCCCCDDD
+ emitcode ("anl", "a,#!constbyte", mask); // BBB00000:CCCCCDDD
+ emitcode ("xch", "a,%s", x); // CCCCCDDD:BBB00000
+ AccRol (shCount); // DDDCCCCC:BBB00000
+ emitcode ("xch", "a,%s", x); // BBB00000:DDDCCCCC
+ emitcode ("xrl", "a,%s", x); // (BBB^DDD)CCCCC:DDDCCCCC
+ emitcode ("xch", "a,%s", x); // DDDCCCCC:(BBB^DDD)CCCCC
+ emitcode ("anl", "a,#!constbyte", mask); // DDD00000:(BBB^DDD)CCCCC
+ emitcode ("xch", "a,%s", x); // (BBB^DDD)CCCCC:DDD00000
+ emitcode ("xrl", "a,%s", x); // BBBCCCCC:DDD00000
+ break;
+ case 6: // AAAAAABB:CCCCCCDD
+ mask = SRMask[shCount];
+ emitcode ("anl", "a,#!constbyte", mask); // 000000BB:CCCCCCDD
+ emitcode ("mov", "c,acc.0"); // c = B
+ emitcode ("xch", "a,%s", x); // CCCCCCDD:000000BB
+ emitcode ("rrc", "a");
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rrc", "a");
+ emitcode ("mov", "c,acc.0"); //<< get correct bit
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rrc", "a");
+ emitcode ("xch", "a,%s", x);
+ emitcode ("rrc", "a");
+ emitcode ("xch", "a,%s", x);
+ break;
+ case 7: // a:x <<= 7
+ mask = SRMask[shCount];
+ emitcode ("anl", "a,#!constbyte", mask); // 0000000B:CCCCCCCD
+ emitcode ("mov", "c,acc.0"); // c = B
+ emitcode ("xch", "a,%s", x); // CCCCCCCD:0000000B
+ AccAXRrl1 (x); // BCCCCCCC:D0000000
+ break;
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRsh - right shift a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRsh (const char *x, int shCount)
+{
+ unsigned char mask = SRMask[shCount];
+
+ switch (shCount)
+ {
+ case 0:
+ break;
+ case 1:
+ CLRC;
+ AccAXRrl1 (x); // 0->a:x
+ break;
+ case 2:
+ CLRC;
+ AccAXRrl1 (x); // 0->a:x
+ CLRC;
+ AccAXRrl1 (x); // 0->a:x
+ break;
+ case 3:
+ case 4:
+ case 5: // AAAAABBB:CCCCCDDD = a:x
+ AccRol (8 - shCount); // BBBAAAAA:DDDCCCCC
+ emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA
+ AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA
+ emitcode ("anl", "a,#!constbyte", mask); // 000CCCCC:BBBAAAAA
+ emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA
+ emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA)
+ emitcode ("anl", "a,#!constbyte", mask); // 000AAAAA:BBB(CCCCC^AAAAA)
+ emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA
+ emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA
+ emitcode ("xch", "a,%s", x); // 000AAAAA:BBBCCCCC
+ break;
+ case 6: // AABBBBBB:CCDDDDDD
+ emitcode ("mov", "c,acc.7");
+ AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA
+ emitcode ("mov", "c,acc.7");
+ AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA
+ emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC
+ emitcode ("anl", "a,#!constbyte", mask); // 000000AA:BBBBBBCC
+ break;
+ case 7: // ABBBBBBB:CDDDDDDD
+ emitcode ("mov", "c,acc.7"); // c = A
+ AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA
+ emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC
+ emitcode ("anl", "a,#!constbyte", mask); // 0000000A:BBBBBBBC
+ break;
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRshS - right shift signed a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRshS (const char *x, int shCount)
+{
+ symbol *tlbl;
+ unsigned char mask = SRMask[shCount];
+
+ switch (shCount)
+ {
+ case 0:
+ break;
+ case 1:
+ emitcode ("mov", "c,acc.7");
+ AccAXRrl1 (x); // s->a:x
+ break;
+ case 2:
+ emitcode ("mov", "c,acc.7");
+ AccAXRrl1 (x); // s->a:x
+ emitcode ("mov", "c,acc.7");
+ AccAXRrl1 (x); // s->a:x
+ break;
+ case 3:
+ case 4:
+ case 5: // AAAAABBB:CCCCCDDD = a:x
+ tlbl = newiTempLabel (NULL);
+ AccRol (8 - shCount); // BBBAAAAA:CCCCCDDD
+ emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA
+ AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA
+ emitcode ("anl", "a,#!constbyte", mask); // 000CCCCC:BBBAAAAA
+ emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA
+ emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA)
+ emitcode ("anl", "a,#!constbyte", mask); // 000AAAAA:BBB(CCCCC^AAAAA)
+ emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA
+ emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA
+ emitcode ("xch", "a,%s", x); // 000SAAAA:BBBCCCCC
+ emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, labelKey2num (tlbl->key));
+ mask = ~SRMask[shCount];
+ emitcode ("orl", "a,#!constbyte", mask); // 111AAAAA:BBBCCCCC
+ emitLabel (tlbl);
+ break; // SSSSAAAA:BBBCCCCC
+ case 6: // AABBBBBB:CCDDDDDD
+ tlbl = newiTempLabel (NULL);
+ emitcode ("mov", "c,acc.7");
+ AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA
+ emitcode ("mov", "c,acc.7");
+ AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA
+ emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC
+ emitcode ("anl", "a,#!constbyte", mask); // 000000AA:BBBBBBCC
+ emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, labelKey2num (tlbl->key));
+ mask = ~SRMask[shCount];
+ emitcode ("orl", "a,#!constbyte", mask); // 111111AA:BBBBBBCC
+ emitLabel (tlbl);
+ break;
+ case 7: // ABBBBBBB:CDDDDDDD
+ tlbl = newiTempLabel (NULL);
+ emitcode ("mov", "c,acc.7"); // c = A
+ AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA
+ emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC
+ emitcode ("anl", "a,#!constbyte", mask); // 0000000A:BBBBBBBC
+ emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, labelKey2num (tlbl->key));
+ mask = ~SRMask[shCount];
+ emitcode ("orl", "a,#!constbyte", mask); // 1111111A:BBBBBBBC
+ emitLabel (tlbl);
+ break;
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL2Left2Result - shift left two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL2Left2Result (operand * left, int offl, operand * result, int offr, int shCount)
+{
+ const char *x;
+ bool pushedB = FALSE;
+ bool usedB = FALSE;
+
+ if (sameRegs (AOP (result), AOP (left)) && ((offl + MSB16) == offr))
+ {
+ /* don't crash result[offr] */
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
+ usedB = !strncmp (x, "b", 1);
+ }
+ else if (aopGetUsesAcc (result, offr))
+ {
+ movLeft2Result (left, offl, result, offr, 0);
+ pushedB = pushB ();
+ usedB = TRUE;
+ emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
+ MOVA (aopGet (result, offr, FALSE, FALSE));
+ emitcode ("xch", "a,b");
+ x = "b";
+ }
+ else
+ {
+ movLeft2Result (left, offl, result, offr, 0);
+ MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
+ x = aopGet (result, offr, FALSE, FALSE);
+ }
+ /* ax << shCount (x = lsb(result)) */
+ AccAXLsh (x, shCount);
+ if (usedB)
+ {
+ emitcode ("xch", "a,b");
+ aopPut (result, "a", offr);
+ aopPut (result, "b", offr + MSB16);
+ popB (pushedB);
+ }
+ else
+ {
+ aopPut (result, "a", offr + MSB16);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR2Left2Result - shift right two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR2Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign)
+{
+ const char *x;
+ bool pushedB = FALSE;
+ bool usedB = FALSE;
+
+ if (sameRegs (AOP (result), AOP (left)) && ((offl + MSB16) == offr))
+ {
+ /* don't crash result[offr] */
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
+ usedB = !strncmp (x, "b", 1);
+ }
+ else if (aopGetUsesAcc (result, offr))
+ {
+ movLeft2Result (left, offl, result, offr, 0);
+ pushedB = pushB ();
+ usedB = TRUE;
+ emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
+ MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
+ x = "b";
+ }
+ else
+ {
+ movLeft2Result (left, offl, result, offr, 0);
+ MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
+ x = aopGet (result, offr, FALSE, FALSE);
+ }
+ /* a:x >> shCount (x = lsb(result)) */
+ if (sign)
+ AccAXRshS (x, shCount);
+ else
+ AccAXRsh (x, shCount);
+ if (usedB)
+ {
+ emitcode ("xch", "a,b");
+ aopPut (result, "a", offr);
+ emitcode ("xch", "a,b");
+ popB (pushedB);
+ }
+ if (getDataSize (result) > 1)
+ aopPut (result, "a", offr + MSB16);
+}
+
+/*------------------------------------------------------------------*/
+/* shiftLLeftOrResult - shift left one byte from left, or to result */
+/*------------------------------------------------------------------*/
+static void
+shiftLLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount)
+{
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ /* shift left accumulator */
+ AccLsh (shCount);
+ /* or with result */
+ if (aopGetUsesAcc (result, offr))
+ {
+ emitcode ("xch", "a,b");
+ MOVA (aopGet (result, offr, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ else
+ {
+ emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
+ }
+ /* back to result */
+ aopPut (result, "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRLeftOrResult - shift right one byte from left,or to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftRLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount)
+{
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ /* shift right accumulator */
+ AccRsh (shCount);
+ /* or with result */
+ if (aopGetUsesAcc (result, offr))
+ {
+ emitcode ("xch", "a,b");
+ MOVA (aopGet (result, offr, FALSE, FALSE));
+ emitcode ("orl", "a,b");
+ }
+ else
+ {
+ emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
+ }
+ /* back to result */
+ aopPut (result, "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftLLong - shift left one long from left to result */
+/* offl = LSB or MSB16 */
+/*-----------------------------------------------------------------*/
+static void
+shiftLLong (operand * left, operand * result, int offr)
+{
+ int offl = LSB;
+ int size = AOP_SIZE (result);
+ int useXch = (sameRegs (AOP (left), AOP (result)) && size >= MSB16 + offr && offr != LSB);
+
+ if (size > offl + offr)
+ {
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ emitcode ("add", "a,acc");
+ if (useXch)
+ xch_a_aopGet (left, offl + offr, FALSE, FALSE);
+ else
+ aopPut (result, "a", offl + offr);
+ }
+
+ for (offl = LSB + 1; offl < LSB + 8; offl++)
+ {
+ if (size > offl + offr)
+ {
+ if (!useXch)
+ MOVA (aopGet (left, offl, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ if (useXch)
+ xch_a_aopGet (left, offl + offr, FALSE, FALSE);
+ else
+ aopPut (result, "a", offl + offr);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshFixed - shift four byte by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genlshFixed (operand *result, operand *left, int shCount)
+{
+ int size, b;
+ int full_bytes;
+
+ D (emitcode (";", "genlshFixed"));
+
+ size = AOP_SIZE (result);
+
+ full_bytes = shCount / 8;
+ shCount -= full_bytes * 8;
+ if (shCount == 0)
+ {
+ for (b = size - 1; b > full_bytes - 1; b--)
+ movLeft2Result (left, b - full_bytes, result, b, 0);
+ }
+ else if ((shCount == 1) && (full_bytes < 2))
+ {
+ shiftLLong (left, result, full_bytes);
+ }
+ else if ((shCount == 2) && (full_bytes == 0))
+ {
+ shiftLLong (left, result, full_bytes);
+ shiftLLong (result, result, full_bytes);
+ }
+ else
+ {
+ int off;
+ for (off = size - 2; off - full_bytes >= 0; off -= 2)
+ {
+ shiftL2Left2Result (left, off - full_bytes, result, off, shCount);
+ if (off - full_bytes - 1 >= 0)
+ shiftRLeftOrResult (left, off - full_bytes - 1, result, off, 8 - shCount);
+ }
+ if (off - full_bytes == -1)
+ {
+ shiftL1Left2Result (left, LSB, result, full_bytes, shCount);
+ }
+ }
+ for (b = LSB; b < full_bytes; b++)
+ aopPut (result, zero, b);
+ return;
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshAny - shift any number of bytes by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genlshAny (operand *result, operand *left, int shCount)
+{
+ int size, size2, offset;
+
+ D (emitcode (";", "genlshAny"));
+
+ size = AOP_SIZE (result);
+
+ if (!operandsEqu (result, left))
+ for (size2 = size, offset = 0; size2 > 0; size2--, offset++)
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), offset);
+
+ while (shCount--)
+ {
+ MOVA (aopGet (result, LSB, FALSE, FALSE));
+ emitcode ("add", "a,acc");
+ aopPut (result, "a", 0);
+
+ for(size2 = size - 1, offset = 1; size2 > 0; size2--, offset++)
+ {
+
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ aopPut (result, "a", offset);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShiftLiteral - left shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShiftLiteral (operand * left, operand * right, operand * result, iCode * ic)
+{
+ unsigned int shCount = (unsigned int) ulFromVal (AOP (right)->aopu.aop_lit);
+ unsigned int size;
+
+ size = getSize (operandType (result));
+
+ D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size));
+
+ freeAsmop (right, NULL, ic, TRUE);
+
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+#if VIEW_SIZE
+ emitcode ("; shift left ", "result %d, left %d", size, AOP_SIZE (left));
+#endif
+
+ switch (size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ genlshFixed (result, left, shCount);
+ break;
+
+ default:
+ genlshAny (result, left, shCount);
+ break;
+ }
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShift - generates code for left shifting */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShift (iCode * ic)
+{
+ operand *left, *right, *result;
+ int size, offset;
+ symbol *tlbl, *tlbl1;
+ bool pushedB;
+
+ D (emitcode (";", "genLeftShift"));
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genLeftShiftLiteral (left, right, result, ic);
+ return;
+ }
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits makes no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ pushedB = pushB ();
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* Really should be handled by genLeftShiftLiteral,
+ * but since I'm too lazy to fix that today, at least we can make
+ * some small improvement.
+ */
+ emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
+ }
+ else
+ {
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ emitcode ("inc", "b");
+ }
+ freeAsmop (right, NULL, ic, TRUE);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* now move the left to the result if they are not the same */
+ if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1)
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ const char *l = aopGet (left, offset, FALSE, TRUE);
+ if (*l == '@' && (IS_AOP_PREG (result)))
+ {
+
+ emitcode ("mov", "a,%s", l);
+ aopPut (result, "a", offset);
+ }
+ else
+ aopPut (result, l, offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = 0;
+ tlbl1 = newiTempLabel (NULL);
+
+ /* if it is only one byte then */
+ if (size == 1)
+ {
+ symbol *tlbl1 = newiTempLabel (NULL);
+
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ emitcode ("add", "a,acc");
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+ aopPut (result, "a", 0);
+ goto release;
+ }
+
+ reAdjustPreg (AOP (result));
+
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("add", "a,acc");
+ aopPut (result, "a", offset++);
+ while (--size)
+ {
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ aopPut (result, "a", offset++);
+ }
+ reAdjustPreg (AOP (result));
+
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshOne - right shift a one byte quantity by known count */
+/*-----------------------------------------------------------------*/
+static void
+genrshOne (operand * result, operand * left, int shCount, int sign)
+{
+ D (emitcode (";", "genrshOne"));
+
+ shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshTwo - right shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshTwo (operand * result, operand * left, int shCount, int sign)
+{
+ D (emitcode (";", "genrshTwo"));
+
+ /* if shCount >= 8 */
+ if (shCount >= 8)
+ {
+ shCount -= 8;
+ if (shCount)
+ shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
+ else
+ movLeft2Result (left, MSB16, result, LSB, sign);
+ addSign (result, MSB16, sign);
+ }
+
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRLong - shift right one long from left to result */
+/* offl = LSB or MSB16 */
+/*-----------------------------------------------------------------*/
+static void
+shiftRLong (operand * left, int offl, operand * result, int sign)
+{
+ bool overlapping = regsInCommon (left, result) || operandsEqu (left, result);
+
+ if (overlapping && offl > 1)
+ {
+ // we are in big trouble, but this shouldn't happen
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__);
+ }
+
+ MOVA (aopGet (left, MSB32, FALSE, FALSE));
+
+ if (offl == MSB16)
+ {
+ // shift is > 8
+ if (sign)
+ {
+ emitcode ("rlc", "a");
+ emitcode ("subb", "a,acc");
+ if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
+ {
+ xch_a_aopGet (left, MSB32, FALSE, FALSE);
+ }
+ else
+ {
+ aopPut (result, "a", MSB32);
+ MOVA (aopGet (left, MSB32, FALSE, FALSE));
+ }
+ }
+ else
+ {
+ if (aopPutUsesAcc (result, zero, MSB32))
+ {
+ emitcode ("xch", "a,b");
+ aopPut (result, zero, MSB32);
+ emitcode ("xch", "a,b");
+ }
+ else
+ {
+ aopPut (result, zero, MSB32);
+ }
+ }
+ }
+
+ if (!sign)
+ {
+ emitcode ("clr", "c");
+ }
+ else
+ {
+ emitcode ("mov", "c,acc.7");
+ }
+
+ emitcode ("rrc", "a");
+
+ if (overlapping && offl == MSB16 && sameByte (AOP (left), MSB24, AOP (result), MSB32 - offl))
+ {
+ xch_a_aopGet (left, MSB24, FALSE, FALSE);
+ }
+ else
+ {
+ aopPut (result, "a", MSB32 - offl);
+ MOVA (aopGet (left, MSB24, FALSE, FALSE));
+ }
+
+ emitcode ("rrc", "a");
+ if (overlapping && offl == MSB16 && sameByte (AOP (left), MSB16, AOP (result), MSB24 - offl))
+ {
+ xch_a_aopGet (left, MSB16, FALSE, FALSE);
+ }
+ else
+ {
+ aopPut (result, "a", MSB24 - offl);
+ MOVA (aopGet (left, MSB16, FALSE, FALSE));
+ }
+
+ emitcode ("rrc", "a");
+ if (offl != LSB)
+ {
+ aopPut (result, "a", MSB16 - offl);
+ }
+ else
+ {
+ if (overlapping && sameByte (AOP (left), LSB, AOP (result), MSB16 - offl))
+ {
+ xch_a_aopGet (left, LSB, FALSE, FALSE);
+ }
+ else
+ {
+ aopPut (result, "a", MSB16 - offl);
+ MOVA (aopGet (left, LSB, FALSE, FALSE));
+ }
+ emitcode ("rrc", "a");
+ aopPut (result, "a", LSB);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshFour - shift four byte by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshFour (operand *result, operand *left, int shCount, int sign)
+{
+ D (emitcode (";", "genrshFour"));
+
+ /* if shifting more that 3 bytes */
+ if (shCount >= 24)
+ {
+ shCount -= 24;
+ if (shCount)
+ shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
+ else
+ movLeft2Result (left, MSB32, result, LSB, sign);
+ addSign (result, MSB16, sign);
+ }
+ else if (shCount >= 16)
+ {
+ shCount -= 16;
+ if (shCount)
+ shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
+ else
+ {
+ movLeft2Result (left, MSB24, result, LSB, 0);
+ movLeft2Result (left, MSB32, result, MSB16, sign);
+ }
+ addSign (result, MSB24, sign);
+ }
+ else if (shCount >= 8)
+ {
+ shCount -= 8;
+ if (shCount == 1)
+ {
+ shiftRLong (left, MSB16, result, sign);
+ }
+ else if (shCount == 0)
+ {
+ movLeft2Result (left, MSB16, result, LSB, 0);
+ movLeft2Result (left, MSB24, result, MSB16, 0);
+ movLeft2Result (left, MSB32, result, MSB24, sign);
+ addSign (result, MSB32, sign);
+ }
+ else
+ {
+ shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
+ shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
+ /* the last shift is signed */
+ shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
+ addSign (result, MSB32, sign);
+ }
+ }
+ else
+ {
+ /* 1 <= shCount <= 7 */
+ if (shCount <= 2)
+ {
+ shiftRLong (left, LSB, result, sign);
+ if (shCount == 2)
+ shiftRLong (result, LSB, result, sign);
+ }
+ else
+ {
+ shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
+ shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
+ shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshAny - shift any number of bytes by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshAny (operand *result, operand *left, int shCount, int sign)
+{
+ int size, size2, offset;
+
+ D (emitcode (";", "genrshAny"));
+
+ size = AOP_SIZE (result);
+
+ if (!operandsEqu (result, left))
+ for (size2 = size, offset = 0; size2 > 0; size2--, offset++)
+ aopPut (result, aopGet (left, offset, FALSE, FALSE), offset);
+
+ while (shCount--)
+ {
+ MOVA (aopGet (result, size - 1, FALSE, FALSE));
+ if (!sign)
+ emitcode ("clr", "c");
+ else
+ emitcode ("mov", "c,acc.7");
+ emitcode ("rrc", "a");
+ aopPut (result, "a", size - 1);
+
+ for(size2 = size - 1, offset = size - 2; size2 > 0; size2--, offset--)
+ {
+
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ aopPut (result, "a", offset);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShiftLiteral - right shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genRightShiftLiteral (operand * left, operand * right, operand * result, iCode * ic, int sign)
+{
+ int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ size = getSize (operandType (result)); //getDataSize (left);
+
+ D (emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size));
+
+ freeAsmop (right, NULL, ic, TRUE);
+
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+#if VIEW_SIZE
+ emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result), AOP_SIZE (left));
+#endif
+
+ /* test the LEFT size !!! */
+
+ /* I suppose that the left size >= result size */
+ wassert ((int)getSize (operandType (left)) >= size);
+
+ if (shCount == 0)
+ {
+ size = getDataSize (result);
+ while (size--)
+ movLeft2Result (left, size, result, size, 0);
+ }
+ else if (shCount >= (size * 8))
+ {
+ if (sign)
+ {
+ /* get sign in acc.7 */
+ MOVA (aopGet (left, size - 1, FALSE, FALSE));
+ }
+ addSign (result, LSB, sign);
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genrshOne (result, left, shCount, sign);
+ break;
+
+ case 2:
+ genrshTwo (result, left, shCount, sign);
+ break;
+
+ case 4:
+ genrshFour (result, left, shCount, sign);
+ break;
+
+ default:
+ genrshAny (result, left, shCount, sign);
+ break;
+ }
+ }
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genSignedRightShift - right shift of signed number */
+/*-----------------------------------------------------------------*/
+static void
+genSignedRightShift (iCode * ic)
+{
+ operand *right, *left, *result;
+ int size, offset;
+ symbol *tlbl, *tlbl1;
+ bool pushedB;
+
+ D (emitcode (";", "genSignedRightShift"));
+
+ /* we do it the hard way put the shift count in b
+ and loop thru preserving the sign */
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE);
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genRightShiftLiteral (left, right, result, ic, 1);
+ return;
+ }
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ pushedB = pushB ();
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* Really should be handled by genRightShiftLiteral,
+ * but since I'm too lazy to fix that today, at least we can make
+ * some small improvement.
+ */
+ emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
+ }
+ else
+ {
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ emitcode ("inc", "b");
+ }
+ freeAsmop (right, NULL, ic, TRUE);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1)
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ const char *l = aopGet (left, offset, FALSE, TRUE);
+ if (*l == '@' && IS_AOP_PREG (result))
+ {
+
+ emitcode ("mov", "a,%s", l);
+ aopPut (result, "a", offset);
+ }
+ else
+ aopPut (result, l, offset);
+ offset++;
+ }
+ }
+
+ /* mov the highest order bit to OVR */
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ size = AOP_SIZE (result);
+ offset = size - 1;
+ MOVA (aopGet (left, offset, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ emitcode ("mov", "ov,c");
+ /* if it is only one byte then */
+ if (size == 1)
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ emitcode ("mov", "c,ov");
+ emitcode ("rrc", "a");
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+ aopPut (result, "a", 0);
+ goto release;
+ }
+
+ reAdjustPreg (AOP (result));
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ emitcode ("mov", "c,ov");
+ while (size--)
+ {
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ aopPut (result, "a", offset--);
+ }
+ reAdjustPreg (AOP (result));
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShift - generate code for right shifting */
+/*-----------------------------------------------------------------*/
+static void
+genRightShift (iCode * ic)
+{
+ operand *right, *left, *result;
+ sym_link *letype;
+ int size, offset;
+ symbol *tlbl, *tlbl1;
+ bool pushedB;
+
+ D (emitcode (";", "genRightShift"));
+
+ /* if signed then we do it the hard way preserve the
+ sign bit moving it inwards */
+ letype = getSpec (operandType (IC_LEFT (ic)));
+
+ if (!SPEC_USIGN (letype))
+ {
+ genSignedRightShift (ic);
+ return;
+ }
+
+ /* signed & unsigned types are treated the same : i.e. the
+ signed is NOT propagated inwards : quoting from the
+ ANSI - standard : "for E1 >> E2, is equivalent to division
+ by 2**E2 if unsigned or if it has a non-negative value,
+ otherwise the result is implementation defined ", MY definition
+ is that the sign does not get propagated */
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genRightShiftLiteral (left, right, result, ic, 0);
+ return;
+ }
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ pushedB = pushB ();
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* Really should be handled by genRightShiftLiteral,
+ * but since I'm too lazy to fix that today, at least we can make
+ * some small improvement.
+ */
+ emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
+ }
+ else
+ {
+ MOVB (aopGet (right, 0, FALSE, FALSE));
+ emitcode ("inc", "b");
+ }
+ freeAsmop (right, NULL, ic, TRUE);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1)
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ const char *l = aopGet (left, offset, FALSE, TRUE);
+ if (*l == '@' && IS_AOP_PREG (result))
+ {
+
+ emitcode ("mov", "a,%s", l);
+ aopPut (result, "a", offset);
+ }
+ else
+ aopPut (result, l, offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = size - 1;
+
+ /* if it is only one byte then */
+ if (size == 1)
+ {
+ MOVA (aopGet (left, 0, FALSE, FALSE));
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ CLRC;
+ emitcode ("rrc", "a");
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+ aopPut (result, "a", 0);
+ goto release;
+ }
+
+ reAdjustPreg (AOP (result));
+ emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key));
+ emitLabel (tlbl);
+ CLRC;
+ while (size--)
+ {
+ MOVA (aopGet (result, offset, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ aopPut (result, "a", offset--);
+ }
+ reAdjustPreg (AOP (result));
+
+ emitLabel (tlbl1);
+ emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key));
+ popB (pushedB);
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* emitPtrByteGet - emits code to get a byte into A through a */
+/* pointer register (R0, R1, or DPTR). The */
+/* original value of A can be preserved in B. */
+/*-----------------------------------------------------------------*/
+static void
+emitPtrByteGet (const char *rname, int p_type, bool preserveAinB)
+{
+ switch (p_type)
+ {
+ case IPOINTER:
+ case POINTER:
+ if (preserveAinB)
+ emitcode ("mov", "b,a");
+ emitcode ("mov", "a,@%s", rname);
+ break;
+
+ case PPOINTER:
+ if (preserveAinB)
+ emitcode ("mov", "b,a");
+ emitcode ("movx", "a,@%s", rname);
+ break;
+
+ case FPOINTER:
+ if (preserveAinB)
+ emitcode ("mov", "b,a");
+ emitcode ("movx", "a,@dptr");
+ break;
+
+ case CPOINTER:
+ if (preserveAinB)
+ emitcode ("mov", "b,a");
+ emitcode ("clr", "a");
+ emitcode ("movc", "a,@a+dptr");
+ break;
+
+ case GPOINTER:
+ if (preserveAinB)
+ {
+ emitpush ("b");
+ emitpush ("acc");
+ }
+ emitcode ("lcall", "__gptrget");
+ if (preserveAinB)
+ emitpop ("b");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* emitPtrByteSet - emits code to set a byte from src through a */
+/* pointer register (R0, R1, or DPTR). */
+/*-----------------------------------------------------------------*/
+static void
+emitPtrByteSet (const char *rname, int p_type, const char *src)
+{
+ switch (p_type)
+ {
+ case IPOINTER:
+ case POINTER:
+ if (*src == '@')
+ {
+ MOVA (src);
+ emitcode ("mov", "@%s,a", rname);
+ }
+ else
+ emitcode ("mov", "@%s,%s", rname, src);
+ break;
+
+ case PPOINTER:
+ MOVA (src);
+ emitcode ("movx", "@%s,a", rname);
+ break;
+
+ case FPOINTER:
+ MOVA (src);
+ emitcode ("movx", "@dptr,a");
+ break;
+
+ case GPOINTER:
+ MOVA (src);
+ emitcode ("lcall", "__gptrput");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits */
+/*-----------------------------------------------------------------*/
+static char *
+genUnpackBits (operand * result, const char *rname, int ptype, iCode * ifx)
+{
+ int offset = 0; /* result byte offset */
+ int rsize; /* result size */
+ int rlen = 0; /* remaining bitfield length */
+ sym_link *etype; /* bitfield type information */
+ unsigned blen; /* bitfield length */
+ unsigned bstr; /* bitfield starting bit within byte */
+ static char *const accBits[] = { "acc.0", "acc.1", "acc.2", "acc.3",
+ "acc.4", "acc.5", "acc.6", "acc.7"
+ };
+
+ D (emitcode (";", "genUnpackBits"));
+
+ etype = getSpec (operandType (result));
+ rsize = getSize (operandType (result));
+ blen = SPEC_BLEN (etype);
+ bstr = SPEC_BSTR (etype);
+
+ if (ifx && blen <= 8)
+ {
+ emitPtrByteGet (rname, ptype, FALSE);
+ if (blen == 1)
+ {
+ return accBits[bstr];;
+ }
+ else
+ {
+ if (blen < 8)
+ emitcode ("anl", "a,#!constbyte", (((unsigned char) - 1) >> (8 - blen)) << bstr);
+ return "a";
+ }
+ }
+ wassert (!ifx);
+
+ /* If the bitfield length is less than a byte */
+ if (blen < 8)
+ {
+ emitPtrByteGet (rname, ptype, FALSE);
+ AccRol (8 - bstr);
+ emitcode ("anl", "a,#!constbyte", ((unsigned char) - 1) >> (8 - blen));
+ if (!SPEC_USIGN (etype))
+ {
+ /* signed bitfield */
+ symbol *tlbl = newiTempLabel (NULL);
+
+ emitcode ("jnb", "acc.%d,!tlabel", blen - 1, labelKey2num (tlbl->key));
+ emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
+ emitLabel (tlbl);
+ }
+ aopPut (result, "a", offset++);
+ goto finish;
+ }
+
+ /* Bit field did not fit in a byte. Copy all
+ but the partial byte at the end. */
+ for (rlen = blen; rlen >= 8; rlen -= 8)
+ {
+ emitPtrByteGet (rname, ptype, FALSE);
+ aopPut (result, "a", offset++);
+ if (rlen > 8)
+ emitcode ("inc", "%s", rname);
+ }
+
+ /* Handle the partial byte at the end */
+ if (rlen)
+ {
+ emitPtrByteGet (rname, ptype, FALSE);
+ emitcode ("anl", "a,#!constbyte", ((unsigned char) - 1) >> (8 - rlen));
+ if (!SPEC_USIGN (etype))
+ {
+ /* signed bitfield */
+ symbol *tlbl = newiTempLabel (NULL);
+
+ emitcode ("jnb", "acc.%d,!tlabel", rlen - 1, labelKey2num (tlbl->key));
+ emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
+ emitLabel (tlbl);
+ }
+ aopPut (result, "a", offset++);
+ }
+
+finish:
+ if (offset < rsize)
+ {
+ char *source;
+
+ if (SPEC_USIGN (etype))
+ source = zero;
+ else
+ {
+ /* signed bitfield: sign extension with 0x00 or 0xff */
+ emitcode ("rlc", "a");
+ emitcode ("subb", "a,acc");
+
+ source = "a";
+ }
+ rsize -= offset;
+ while (rsize--)
+ aopPut (result, source, offset++);
+ }
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerGet - generates code when ptr offset is known */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerGet (operand * left, operand * result, iCode * ic)
+{
+ const char *l;
+ int size, offset = 0;
+
+ D (emitcode (";", "genDataPointerGet"));
+
+ aopOp (result, ic, TRUE);
+
+ /* get the string representation of the name */
+ l = aopGet (left, 0, FALSE, TRUE) + 1; // remove #
+ size = AOP_SIZE (result);
+ while (size--)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ if (AOP_SIZE (result) > 1)
+ {
+ dbuf_printf (&dbuf, "(%s + %d)", l, offset);
+ }
+ else
+ {
+ dbuf_append_str (&dbuf, l);
+ }
+ aopPut (result, dbuf_c_str (&dbuf), offset++);
+ dbuf_destroy (&dbuf);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerGet - emitcode for near pointer fetch */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerGet (operand * left, operand * result, iCode * ic, iCode * pi, iCode * ifx)
+{
+ asmop *aop = NULL;
+ reg_info *preg = NULL;
+ const char *rname;
+ char *ifxCond = "a";
+ sym_link *rtype, *retype;
+ sym_link *ltype = operandType (left);
+
+ D (emitcode (";", "genNearPointerGet"));
+
+ rtype = operandType (result);
+ retype = getSpec (rtype);
+
+ aopOp (left, ic, FALSE);
+
+ /* if left is rematerialisable and
+ result is not bitfield variable type and
+ the left is pointer to data space i.e
+ lower 128 bytes of space */
+ if (AOP_TYPE (left) == AOP_IMMD && !IS_BITFIELD (retype) && DCL_TYPE (ltype) == POINTER)
+ {
+ genDataPointerGet (left, result, ic);
+ return;
+ }
+
+ //aopOp (result, ic, FALSE);
+ aopOp (result, ic, result ? TRUE : FALSE);
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG (AOP (left)))
+ {
+ if (IS_AOP_PREG (left))
+ {
+ // Aha, it is a pointer, just in disguise.
+ rname = aopGet (left, 0, FALSE, FALSE);
+ if (EQ (rname, "a"))
+ {
+ // It's in pdata or on xstack
+ rname = AOP (left)->aopu.aop_ptr->name;
+ emitcode ("mov", "%s,a", rname);
+ }
+ else if (*rname != '@')
+ {
+ fprintf (stderr, "probable internal error: unexpected rname '%s' @ %s:%d\n", rname, __FILE__, __LINE__);
+ }
+ else
+ {
+ // Expected case.
+ emitcode ("mov", "a%s,%s", rname + 1, rname);
+ rname++; // skip the '@'.
+ }
+ }
+ else
+ {
+ /* otherwise get a free pointer register */
+ aop = newAsmop (0);
+ preg = getFreePtr (ic, aop, FALSE);
+ emitcode ("mov", "%s,%s", preg->name, aopGet (left, 0, FALSE, TRUE));
+ rname = preg->name;
+ }
+ }
+ else
+ rname = aopGet (left, 0, FALSE, FALSE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITFIELD (retype))
+ ifxCond = genUnpackBits (result, rname, POINTER, ifx);
+ else
+ {
+ /* we can just get the values */
+ int size = AOP_SIZE (result);
+ int offset = 0;
+
+ while (size--)
+ {
+ if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
+ {
+ emitcode ("mov", "a,@%s", rname);
+ if (!ifx)
+ aopPut (result, "a", offset);
+ }
+ else
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "@%s", rname);
+ aopPut (result, dbuf_c_str (&dbuf), offset);
+ dbuf_destroy (&dbuf);
+ }
+ offset++;
+ if (size || pi)
+ emitcode ("inc", "%s", rname);
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) /* we had to allocate for this iCode */
+ {
+ if (pi)
+ {
+ /* post increment present */
+ aopPut (left, rname, 0);
+ }
+ freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if ((AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) && !pi)
+ {
+ int size = AOP_SIZE (result) - 1;
+ while (size--)
+ emitcode ("dec", "%s", rname);
+ }
+ }
+
+ if (ifx && !ifx->generated)
+ {
+ genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
+ }
+
+ /* done */
+ freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+ if (pi)
+ pi->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genPagedPointerGet - emitcode for paged pointer fetch */
+/*-----------------------------------------------------------------*/
+static void
+genPagedPointerGet (operand * left, operand * result, iCode * ic, iCode * pi, iCode * ifx)
+{
+ asmop *aop = NULL;
+ reg_info *preg = NULL;
+ const char *rname;
+ char *ifxCond = "a";
+ sym_link *rtype, *retype;
+
+ D (emitcode (";", "genPagedPointerGet"));
+
+ rtype = operandType (result);
+ retype = getSpec (rtype);
+
+ aopOp (left, ic, FALSE);
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG (AOP (left)))
+ {
+ const char *l;
+ /* otherwise get a free pointer register */
+ aop = newAsmop (0);
+ preg = getFreePtr (ic, aop, FALSE);
+ l = aopGet (left, 0, FALSE, TRUE);
+ if (*l == '@')
+ emitcode ("mov", "a%s,%s", preg->name, l);
+ else
+ emitcode ("mov", "%s,%s", preg->name, l);
+ rname = preg->name;
+ }
+ else
+ {
+ rname = aopGet (left, 0, FALSE, FALSE);
+ }
+
+ aopOp (result, ic, TRUE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITFIELD (retype))
+ {
+ ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
+ }
+ else
+ {
+ /* we can just get the values */
+ int size = AOP_SIZE (result);
+ int offset = 0;
+
+ while (size--)
+ {
+ emitcode ("movx", "a,@%s", rname);
+ if (!ifx)
+ aopPut (result, "a", offset);
+
+ offset++;
+
+ if (size || pi)
+ emitcode ("inc", "%s", rname);
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) /* we had to allocate for this iCode */
+ {
+ if (pi)
+ aopPut (left, rname, 0);
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 1 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if ((AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) && !pi)
+ {
+ int size = AOP_SIZE (result) - 1;
+ while (size--)
+ emitcode ("dec", "%s", rname);
+ }
+ }
+
+ /* done */
+ freeAsmop (result, NULL, ic, TRUE);
+ if (aop)
+ {
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+ freeAsmop (left, NULL, ic, TRUE);
+
+ if (ifx && !ifx->generated)
+ {
+ genIfxJump (ifx, ifxCond, NULL, NULL, NULL, ic->next);
+ }
+
+ if (pi)
+ pi->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerGet - get value from far space */
+/*-----------------------------------------------------------------*/
+static void
+genFarPointerGet (operand * left, operand * result, iCode * ic, iCode * pi, iCode * ifx)
+{
+ int size, offset;
+ char *ifxCond = "a";
+ sym_link *retype = getSpec (operandType (result));
+
+ D (emitcode (";", "genFarPointerGet"));
+
+ aopOp (left, ic, FALSE);
+ loadDptrFromOperand (left, FALSE);
+
+ /* so dptr now contains the address */
+ aopOp (result, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITFIELD (retype))
+ ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ emitcode ("movx", "a,@dptr");
+ if (!ifx)
+ aopPut (result, "a", offset++);
+ if (size || pi)
+ emitcode ("inc", "dptr");
+ }
+ }
+
+ if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
+ {
+ aopPut (left, "dpl", 0);
+ aopPut (left, "dph", 1);
+ pi->generated = 1;
+ }
+
+ if (ifx && !ifx->generated)
+ {
+ genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCodePointerGet - get value from code space */
+/*-----------------------------------------------------------------*/
+static void
+genCodePointerGet (operand * left, operand * result, iCode * ic, iCode * pi, iCode * ifx)
+{
+ int size, offset;
+ char *ifxCond = "a";
+ sym_link *retype = getSpec (operandType (result));
+
+ D (emitcode (";", "genCodePointerGet"));
+
+ aopOp (left, ic, FALSE);
+ loadDptrFromOperand (left, FALSE);
+
+ /* so dptr now contains the address */
+ aopOp (result, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITFIELD (retype))
+ ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ emitcode ("clr", "a");
+ emitcode ("movc", "a,@a+dptr");
+ if (!ifx)
+ aopPut (result, "a", offset++);
+ if (size || pi)
+ emitcode ("inc", "dptr");
+ }
+ }
+
+ if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
+ {
+ aopPut (left, "dpl", 0);
+ aopPut (left, "dph", 1);
+ pi->generated = 1;
+ }
+
+ if (ifx && !ifx->generated)
+ {
+ genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerGet - get value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerGet (operand * left, operand * result, iCode * ic, iCode * pi, iCode * ifx)
+{
+ int size, offset;
+ char *ifxCond = "a";
+ sym_link *retype = getSpec (operandType (result));
+
+ D (emitcode (";", "genGenPointerGet"));
+
+ aopOp (left, ic, FALSE);
+ loadDptrFromOperand (left, TRUE);
+
+ /* so dptr-b now contains the address */
+ aopOp (result, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITFIELD (retype))
+ {
+ ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
+ }
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ emitcode ("lcall", "__gptrget");
+ if (!ifx)
+ aopPut (result, "a", offset++);
+ if (size || pi)
+ emitcode ("inc", "dptr");
+ }
+ }
+
+ if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
+ {
+ aopPut (left, "dpl", 0);
+ aopPut (left, "dph", 1);
+ pi->generated = 1;
+ }
+
+ if (ifx && !ifx->generated)
+ {
+ genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void
+genPointerGet (iCode * ic, iCode * pi, iCode * ifx)
+{
+ operand *left, *result;
+ sym_link *type, *etype;
+ int p_type;
+
+ D (emitcode (";", "genPointerGet"));
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ if (getSize (operandType (result)) > 1)
+ ifx = NULL;
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (left);
+ etype = getSpec (type);
+ /* if left is of type of pointer then it is simple */
+ if (IS_PTR (type) && !IS_FUNC (type->next))
+ {
+ p_type = DCL_TYPE (type);
+ }
+ else
+ {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE (SPEC_OCLS (etype));
+ }
+
+ /* special case when cast remat */
+ while (IS_SYMOP (left) && OP_SYMBOL (left)->remat && IS_CAST_ICODE (OP_SYMBOL (left)->rematiCode))
+ {
+ left = IC_RIGHT (OP_SYMBOL (left)->rematiCode);
+ type = operandType (left);
+ p_type = DCL_TYPE (type);
+ }
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type)
+ {
+ case POINTER:
+ case IPOINTER:
+ genNearPointerGet (left, result, ic, pi, ifx);
+ break;
+
+ case PPOINTER:
+ genPagedPointerGet (left, result, ic, pi, ifx);
+ break;
+
+ case FPOINTER:
+ genFarPointerGet (left, result, ic, pi, ifx);
+ break;
+
+ case CPOINTER:
+ genCodePointerGet (left, result, ic, pi, ifx);
+ break;
+
+ case GPOINTER:
+ genGenPointerGet (left, result, ic, pi, ifx);
+ break;
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genPackBits - generates code for packed bit storage */
+/*-----------------------------------------------------------------*/
+static void
+genPackBits (sym_link * etype, operand * right, const char *rname, int p_type)
+{
+ int offset = 0; /* source byte offset */
+ int rlen = 0; /* remaining bitfield length */
+ unsigned blen; /* bitfield length */
+ unsigned bstr; /* bitfield starting bit within byte */
+ int litval; /* source literal value (if AOP_LIT) */
+ unsigned char mask; /* bitmask within current byte */
+
+ D (emitcode (";", "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) ulFromVal (AOP (right)->aopu.aop_lit);
+ litval <<= bstr;
+ litval &= (~mask) & 0xff;
+ emitPtrByteGet (rname, p_type, FALSE);
+ if ((mask | litval) != 0xff)
+ emitcode ("anl", "a,#!constbyte", mask);
+ if (litval)
+ emitcode ("orl", "a,#!constbyte", litval);
+ }
+ else
+ {
+ if ((blen == 1) && (p_type != GPOINTER))
+ {
+ /* Case with a bitfield length == 1 and no generic pointer
+ */
+ if (AOP_TYPE (right) == AOP_CRY)
+ emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ else
+ {
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ }
+ emitPtrByteGet (rname, p_type, FALSE);
+ emitcode ("mov", "acc.%d,c", bstr);
+ }
+ else
+ {
+ bool pushedB;
+ /* Case with a bitfield length < 8 and arbitrary source
+ */
+ MOVA (aopGet (right, 0, FALSE, FALSE));
+ /* shift and mask source value */
+ AccLsh (bstr);
+ emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
+
+ pushedB = pushB ();
+ /* transfer A to B and get next byte */
+ emitPtrByteGet (rname, p_type, TRUE);
+
+ emitcode ("anl", "a,#!constbyte", mask);
+ emitcode ("orl", "a,b");
+ if (p_type == GPOINTER)
+ emitpop ("b");
+
+ popB (pushedB);
+ }
+ }
+
+ emitPtrByteSet (rname, p_type, "a");
+ 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)
+ {
+ emitPtrByteSet (rname, p_type, aopGet (right, offset++, FALSE, TRUE));
+ if (rlen > 8)
+ emitcode ("inc", "%s", rname);
+ }
+
+ /* 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) ulFromVal (AOP (right)->aopu.aop_lit);
+ litval >>= (blen - rlen);
+ litval &= (~mask) & 0xff;
+ emitPtrByteGet (rname, p_type, FALSE);
+ if ((mask | litval) != 0xff)
+ emitcode ("anl", "a,#!constbyte", mask);
+ if (litval)
+ emitcode ("orl", "a,#!constbyte", litval);
+ }
+ else
+ {
+ bool pushedB;
+ /* Case with partial byte and arbitrary source
+ */
+ MOVA (aopGet (right, offset++, FALSE, FALSE));
+ emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
+
+ pushedB = pushB ();
+ /* transfer A to B and get next byte */
+ emitPtrByteGet (rname, p_type, TRUE);
+
+ emitcode ("anl", "a,#!constbyte", mask);
+ emitcode ("orl", "a,b");
+ if (p_type == GPOINTER)
+ emitpop ("b");
+
+ popB (pushedB);
+ }
+ emitPtrByteSet (rname, p_type, "a");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genLiteralAssign - assignment of literal */
+/*-----------------------------------------------------------------*/
+static void
+genLiteralAssign (operand * result, operand * right, int size, bool (*output_fn) (operand * result, const char *s, int offset))
+{
+ unsigned long long lit = 0LL;
+ int offset;
+ int accumulator_value = -1; /* -1 denotes: not yet set */
+
+ if (!IS_FLOAT (operandType (right)))
+ {
+ lit = ullFromVal (AOP (right)->aopu.aop_lit);
+ }
+ else
+ {
+ union
+ {
+ float f;
+ unsigned char c[4];
+ } fl;
+
+ fl.f = (float) floatFromVal (AOP (right)->aopu.aop_lit);
+#ifdef WORDS_BIGENDIAN
+ lit = (fl.c[3] << 0) | (fl.c[2] << 8) | (fl.c[1] << 16) | (fl.c[0] << 24);
+#else
+ lit = (fl.c[0] << 0) | (fl.c[1] << 8) | (fl.c[2] << 16) | (fl.c[3] << 24);
+#endif
+ }
+
+ offset = 0;
+ while (size)
+ {
+ /* check whether preloading the accumulator pays off:
+
+ mov direct,#something 3 byte, 2 cycle
+ mov direct,a 2 byte, 1 cycle
+
+ mov @r0,#something 2 byte, 1 cycle
+ mov @r0,a 1 byte, 1 cycle
+
+ mov rx,#something 2 byte, 1 cycle
+ mov rx,a 1 byte, 1 cycle
+
+ clr a 1 byte, 1 cycle
+ mov a,#something 2 byte, 1 cycle
+
+ (setting bytes in pdata and xdata need the accumulator anyway)
+ */
+
+ /* clr a needs an extra byte. If two bytes are zero it starts to pay off
+ to preload the accumulator */
+ int clr_num_bytes_saved = -1 + /* size of clr a */
+ (int) ((((lit >> 0) & 0xff) == 0) && (size >= 1)) +
+ (int) ((((lit >> 8) & 0xff) == 0) && (size >= 2)) +
+ (int) ((((lit >> 16) & 0xff) == 0) && (size >= 3)) + (int) ((((lit >> 24) & 0xff) == 0) && (size >= 4));
+
+ /* mov a,#something needs two extra bytes. If three bytes are identical it starts to pay off */
+ int mov_num_bytes_saved = -2 + /* size of mov a,#something */
+ (int) ((lit & 0xff) == ((lit >> 0) & 0xff) && (size >= 1)) + /* true */
+ (int) ((lit & 0xff) == ((lit >> 8) & 0xff) && (size >= 2)) +
+ (int) ((lit & 0xff) == ((lit >> 16) & 0xff) && (size >= 3)) +
+ (int) ((lit & 0xff) == ((lit >> 24) & 0xff) && (size >= 4));
+
+ int num_bytes_to_save_before_using_acc_takes_effect = 1;
+
+ if (optimize.codeSpeed && (AOP_TYPE (result) != AOP_DIR))
+ {
+ /* require an extra byte being saved */
+ num_bytes_to_save_before_using_acc_takes_effect++;
+ }
+
+ /* eventually preload accumulator */
+ if ((clr_num_bytes_saved >= num_bytes_to_save_before_using_acc_takes_effect) &&
+ (clr_num_bytes_saved >= mov_num_bytes_saved) && (lit & 0xff) == 0)
+ {
+ if (0 != accumulator_value)
+ {
+ accumulator_value = 0;
+// emitcode ("clr", "a");
+ MOVA ("#0x00");
+ }
+ }
+ else if ((mov_num_bytes_saved >= num_bytes_to_save_before_using_acc_takes_effect) && (mov_num_bytes_saved > clr_num_bytes_saved)) /* preferrably have 0 in acc */
+ {
+ if ((lit & 0xff) != accumulator_value)
+ {
+ accumulator_value = lit & 0xff;
+// emitcode ("mov", "a,%s", aopGet (right, offset, FALSE, FALSE));
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ }
+ }
+
+ /* write byte */
+ if ((lit & 0xff) == accumulator_value)
+ {
+ /* value in accumulator can be used */
+ output_fn (result, "a", offset);
+ }
+ else
+ {
+ /* otherwise use the normal path that should always work */
+ char *r = Safe_strdup (aopGet (right, offset, FALSE, FALSE));
+ output_fn (result, r, offset);
+ Safe_free (r);
+ }
+
+ /* advance */
+ lit >>= 8;
+ offset++;
+ size--;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* dataPut - puts a string for a aop and indicates if acc is in use */
+/*-----------------------------------------------------------------*/
+static bool
+litPut (operand * result, const char *s, int offset)
+{
+ emitcode ("mov", "(%s + %d),%s", aopGet (result, 0, FALSE, TRUE) + 1, offset, s);
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerSet - remat pointer to data space */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerSet (operand * right, operand * result, iCode * ic)
+{
+ int size, offset;
+
+ D (emitcode (";", "genDataPointerSet"));
+
+ aopOp (right, ic, FALSE);
+
+ size = max (AOP_SIZE (right), AOP_SIZE (result));
+ if ((size > 1) && IS_OP_LITERAL (right))
+ {
+ genLiteralAssign (result, right, size, litPut);
+ }
+ else
+ {
+ //remove #
+ char *l = Safe_strdup (aopGet (result, 0, FALSE, TRUE) + 1); //remove #
+ for (offset = 0; offset < size; offset++)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ if (size > 1)
+ dbuf_printf (&dbuf, "(%s + %d)", l, offset);
+ else
+ dbuf_append_str (&dbuf, l);
+ emitcode ("mov", "%s,%s", dbuf_c_str (&dbuf), aopGet (right, offset, FALSE, FALSE));
+ dbuf_destroy (&dbuf);
+ }
+ Safe_free (l);
+ }
+
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerSet - emitcode for near pointer put */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerSet (operand * right, operand * result, iCode * ic, iCode * pi)
+{
+ asmop *aop = NULL;
+ reg_info *preg = NULL;
+ const char *rname;
+ sym_link *retype, *letype;
+ sym_link *ptype = operandType (result);
+
+ D (emitcode (";", "genNearPointerSet"));
+
+ retype = getSpec (operandType (right));
+ letype = getSpec (ptype);
+
+ aopOp (result, ic, FALSE);
+
+ /* if the result is rematerializable &
+ in data space & not a bit variable */
+ if (AOP_TYPE (result) == AOP_IMMD && DCL_TYPE (ptype) == POINTER && !IS_BITVAR (retype) && !IS_BITVAR (letype))
+ {
+ genDataPointerSet (right, result, ic);
+ return;
+ }
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG (AOP (result)))
+ {
+ if (IS_AOP_PREG (result))
+ {
+ // Aha, it is a pointer, just in disguise.
+ rname = aopGet (result, 0, FALSE, FALSE);
+ if (EQ (rname, "a"))
+ {
+ // It's in pdata or on xstack
+ rname = AOP (result)->aopu.aop_ptr->name;
+ emitcode ("mov", "%s,a", rname);
+ }
+ else if (*rname != '@')
+ {
+ fprintf (stderr, "probable internal error: unexpected rname @ %s:%d\n", __FILE__, __LINE__);
+ }
+ else
+ {
+ // Expected case.
+ emitcode ("mov", "a%s,%s", rname + 1, rname);
+ rname++; // skip the '@'.
+ }
+ }
+ else
+ {
+ /* otherwise get a free pointer register */
+ aop = newAsmop (0);
+ preg = getFreePtr (ic, aop, FALSE);
+ emitcode ("mov", "%s,%s", preg->name, aopGet (result, 0, FALSE, TRUE));
+ rname = preg->name;
+ }
+ }
+ else
+ {
+ rname = aopGet (result, 0, FALSE, FALSE);
+ }
+
+ aopOp (right, ic, FALSE);
+
+ rname = Safe_strdup (rname);
+ /* if bitfield then unpack the bits */
+ if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+ genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
+ else
+ {
+ /* we can just get the values */
+ int size = AOP_SIZE (right);
+ int offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (right, offset, FALSE, TRUE);
+ if ((*l == '@') || (EQ (l, "acc")))
+ {
+ MOVA (l);
+ emitcode ("mov", "@%s,a", rname);
+ }
+ else
+ emitcode ("mov", "@%s,%s", rname, l);
+ if (size || pi)
+ emitcode ("inc", "%s", rname);
+ offset++;
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) /* we had to allocate for this iCode */
+ {
+ if (pi)
+ aopPut (result, rname, 0);
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if ((AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) && !pi)
+ {
+ int size = AOP_SIZE (right) - 1;
+ while (size--)
+ emitcode ("dec", "%s", rname);
+ }
+ }
+ Safe_free ((void *) rname);
+
+ /* done */
+ if (pi)
+ pi->generated = 1;
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPagedPointerSet - emitcode for Paged pointer put */
+/*-----------------------------------------------------------------*/
+static void
+genPagedPointerSet (operand * right, operand * result, iCode * ic, iCode * pi)
+{
+ asmop *aop = NULL;
+ reg_info *preg = NULL;
+ const char *rname;
+ sym_link *retype, *letype;
+
+ D (emitcode (";", "genPagedPointerSet"));
+
+ retype = getSpec (operandType (right));
+ letype = getSpec (operandType (result));
+
+ aopOp (result, ic, FALSE);
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG (AOP (result)))
+ {
+ if (IS_AOP_PREG (result))
+ {
+ // Aha, it is a pointer, just in disguise.
+ rname = aopGet (result, 0, FALSE, FALSE);
+ if (*rname != '@')
+ {
+ fprintf (stderr, "probable internal error: unexpected rname @ %s:%d\n", __FILE__, __LINE__);
+ }
+ else
+ {
+ // Expected case.
+ emitcode ("mov", "a%s,%s", rname + 1, rname);
+ rname++; // skip the '@'.
+ }
+ }
+ else
+ {
+ /* otherwise get a free pointer register */
+ aop = newAsmop (0);
+ preg = getFreePtr (ic, aop, FALSE);
+ emitcode ("mov", "%s,%s", preg->name, aopGet (result, 0, FALSE, TRUE));
+ rname = preg->name;
+ }
+ }
+ else
+ {
+ rname = aopGet (result, 0, FALSE, FALSE);
+ }
+
+ aopOp (right, ic, FALSE);
+
+ rname = Safe_strdup (rname);
+ /* if bitfield then unpack the bits */
+ if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+ genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
+ else
+ {
+ /* we can just get the values */
+ int size = AOP_SIZE (right);
+ int offset = 0;
+
+ while (size--)
+ {
+ MOVA (aopGet (right, offset, FALSE, TRUE));
+ emitcode ("movx", "@%s,a", rname);
+ if (size || pi)
+ emitcode ("inc", "%s", rname);
+ offset++;
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) /* we had to allocate for this iCode */
+ {
+ if (pi)
+ aopPut (result, rname, 0);
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 1 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if (AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) && !pi)
+ {
+ int size = AOP_SIZE (right) - 1;
+ while (size--)
+ emitcode ("dec", "%s", rname);
+ }
+ }
+ Safe_free ((void *) rname);
+
+ /* done */
+ if (pi)
+ pi->generated = 1;
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerSet - set value in far space */
+/*-----------------------------------------------------------------*/
+static void
+genFarPointerSet (operand * right, operand * result, iCode * ic, iCode * pi)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (right));
+ sym_link *letype = getSpec (operandType (result));
+
+ D (emitcode (";", "genFarPointerSet"));
+
+ aopOp (result, ic, FALSE);
+ loadDptrFromOperand (result, FALSE);
+
+ /* so dptr now contains the address */
+ aopOp (right, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+ genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
+ else
+ {
+ size = AOP_SIZE (right);
+ offset = 0;
+
+ while (size--)
+ {
+ MOVA (aopGet (right, offset, FALSE, FALSE));
+ if (offset++ > 0)
+ emitcode ("inc", "dptr");
+ emitcode ("movx", "@dptr,a");
+ }
+ if (pi)
+ emitcode ("inc", "dptr");
+ }
+ if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD)
+ {
+ aopPut (result, "dpl", 0);
+ aopPut (result, "dph", 1);
+ pi->generated = 1;
+ }
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerSet - set value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerSet (operand * right, operand * result, iCode * ic, iCode * pi)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (right));
+ sym_link *letype = getSpec (operandType (result));
+
+ D (emitcode (";", "genGenPointerSet"));
+
+ aopOp (result, ic, FALSE);
+ loadDptrFromOperand (result, TRUE);
+
+ /* so dptr-b now contains the address */
+ aopOp (right, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+ {
+ genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
+ }
+ else
+ {
+ size = AOP_SIZE (right);
+ offset = 0;
+
+ while (size--)
+ {
+ MOVA (aopGet (right, offset++, FALSE, FALSE));
+ emitcode ("lcall", "__gptrput");
+ if (size || pi)
+ emitcode ("inc", "dptr");
+ }
+ }
+
+ if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD)
+ {
+ aopPut (result, "dpl", 0);
+ aopPut (result, "dph", 1);
+ pi->generated = 1;
+ }
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genPointerSet (iCode * ic, iCode * pi)
+{
+ operand *right, *result;
+ sym_link *type, *etype;
+ int p_type;
+
+ D (emitcode (";", "genPointerSet"));
+
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (result);
+ etype = getSpec (type);
+ /* if left is of type of pointer then it is simple */
+ if (IS_PTR (type) && !IS_FUNC (type->next))
+ {
+ p_type = DCL_TYPE (type);
+ }
+ else
+ {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE (SPEC_OCLS (etype));
+ }
+
+ /* special case when cast remat */
+ while (IS_SYMOP (result) && OP_SYMBOL (result)->remat &&
+ IS_CAST_ICODE (OP_SYMBOL (result)->rematiCode) &&
+ !IS_BITFIELD (getSpec (operandType (result))))
+ {
+ result = IC_RIGHT (OP_SYMBOL (result)->rematiCode);
+ type = operandType (result);
+ p_type = DCL_TYPE (type);
+ }
+
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type)
+ {
+ case POINTER:
+ case IPOINTER:
+ genNearPointerSet (right, result, ic, pi);
+ break;
+
+ case PPOINTER:
+ genPagedPointerSet (right, result, ic, pi);
+ break;
+
+ case FPOINTER:
+ genFarPointerSet (right, result, ic, pi);
+ break;
+
+ case GPOINTER:
+ genGenPointerSet (right, result, ic, pi);
+ break;
+
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerSet: illegal pointer type");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfx - generate code for Ifx statement */
+/*-----------------------------------------------------------------*/
+static void
+genIfx (iCode * ic, iCode * popIc)
+{
+ operand *cond = IC_COND (ic);
+ int isbit = 0;
+ char *dup = NULL;
+
+ D (emitcode (";", "genIfx"));
+
+ aopOp (cond, ic, FALSE);
+
+ /* get the value into acc */
+ if (AOP_TYPE (cond) != AOP_CRY)
+ {
+ toBoolean (cond);
+ }
+ else
+ {
+ isbit = 1;
+ if (AOP (cond)->aopu.aop_dir)
+ dup = Safe_strdup (AOP (cond)->aopu.aop_dir);
+ }
+
+ /* the result is now in the accumulator or a directly addressable bit */
+ freeAsmop (cond, NULL, ic, TRUE);
+
+ /* if the condition is a bit variable */
+ if (isbit && dup)
+ genIfxJump (ic, dup, NULL, NULL, NULL, popIc);
+ else if (isbit && IS_OP_ACCUSE (cond))
+ genIfxJump (ic, "c", NULL, NULL, NULL, popIc);
+ else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
+ genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL, popIc);
+ else if (isbit && !IS_ITEMP (cond))
+ genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL, popIc);
+ else
+ genIfxJump (ic, "a", NULL, NULL, NULL, popIc);
+
+ if (dup)
+ Safe_free (dup);
+
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAddrOf - generates code for address of */
+/*-----------------------------------------------------------------*/
+static void
+genAddrOf (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+ int size, offset;
+
+ D (emitcode (";", "genAddrOf"));
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+
+ /* if the operand is on the stack then we
+ need to get the stack offset of this
+ variable */
+ if (sym->onStack)
+ {
+ int stack_offset = stackoffset (sym);
+
+ /* if it has an offset then we need to compute it */
+ if (stack_offset)
+ {
+ if ((abs (stack_offset) == 1) && !AOP_NEEDSACC (IC_RESULT (ic)) && !isOperandVolatile (IC_RESULT (ic), FALSE))
+ {
+ aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
+ if (stack_offset > 0)
+ emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
+ else
+ emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
+ }
+ else
+ {
+ emitcode ("mov", "a,%s", SYM_BP (sym));
+ emitcode ("add", "a,#!constbyte", stack_offset & 0xff);
+ aopPut (IC_RESULT (ic), "a", 0);
+ }
+ }
+ else
+ {
+ /* we can just move _bp */
+ aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
+ }
+ /* fill the result with zero */
+ size = AOP_SIZE (IC_RESULT (ic)) - 1;
+
+ offset = 1;
+ while (size--)
+ {
+ aopPut (IC_RESULT (ic), zero, offset++);
+ }
+ goto release;
+ }
+
+ /* object not on stack then we need the name */
+ size = getDataSize (IC_RESULT (ic));
+ offset = 0;
+
+ while (size--)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ if (offset)
+ {
+ dbuf_printf (&dbuf, "#(%s >> %d)", sym->rname, offset * 8);
+ }
+ else
+ {
+ dbuf_printf (&dbuf, "#%s", sym->rname);
+ }
+ aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), offset++);
+ dbuf_destroy (&dbuf);
+ }
+ if (opIsGptr (IC_RESULT (ic)))
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
+ aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1);
+ dbuf_destroy (&dbuf);
+ }
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarFarAssign - assignment when both are in far space */
+/*-----------------------------------------------------------------*/
+static void
+genFarFarAssign (operand * result, operand * right, iCode * ic)
+{
+ int size = AOP_SIZE (right);
+ int offset = 0;
+
+ D (emitcode (";", "genFarFarAssign"));
+
+ /* first push the right side on to the stack */
+ while (size--)
+ {
+ MOVA (aopGet (right, offset++, FALSE, FALSE));
+ emitpush ("acc");
+ }
+
+ freeAsmop (right, NULL, ic, FALSE);
+ /* now assign DPTR to result */
+ aopOp (result, ic, FALSE);
+ size = AOP_SIZE (result);
+ while (size--)
+ {
+ emitpop ("acc");
+ aopPut (result, "a", --offset);
+ }
+ freeAsmop (result, NULL, ic, FALSE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genAssign - generate code for assignment */
+/*-----------------------------------------------------------------*/
+static void
+genAssign (iCode * ic)
+{
+ operand *result, *right;
+ int size, offset;
+
+ D (emitcode (";", "genAssign"));
+
+ result = IC_RESULT (ic);
+ right = IC_RIGHT (ic);
+
+ /* if they are the same */
+ if (operandsEqu (result, right) && !isOperandVolatile (result, FALSE) && !isOperandVolatile (right, FALSE))
+ return;
+
+ aopOp (right, ic, FALSE);
+
+ /* special case both in far space */
+ if (AOP_TYPE (right) == AOP_DPTR && IS_TRUE_SYMOP (result) && isOperandInFarSpace (result))
+ {
+ genFarFarAssign (result, right, ic);
+ return;
+ }
+
+ aopOp (result, ic, TRUE);
+
+ /* if they are the same registers */
+ if (sameRegs (AOP (right), AOP (result)) && !isOperandVolatile (result, FALSE) && !isOperandVolatile (right, FALSE))
+ goto release;
+
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ assignBit (result, right);
+ goto release;
+ }
+
+ /* bit variables done */
+ /* general case */
+
+ size = getDataSize (result);
+
+ if ((size > 1) && (AOP_TYPE (result) != AOP_REG) && /* for registers too? (regression test passes) */
+ (AOP_TYPE (right) == AOP_LIT) && !aopPutUsesAcc (result, aopGet (right, 0, FALSE, FALSE), 0))
+ {
+ genLiteralAssign (result, right, size, aopPut);
+ }
+ else
+ {
+ offset = 0;
+ while (size--)
+ {
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+ }
+ adjustArithmeticResult (ic);
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genJumpTab - generates code for jump table */
+/*-----------------------------------------------------------------*/
+static void
+genJumpTab (iCode * ic)
+{
+ operand *cond = IC_JTCOND (ic);
+ symbol *jtab, *jtablo, *jtabhi;
+ unsigned int count;
+ const char *l;
+ bool useB = FALSE;
+
+ D (emitcode (";", "genJumpTab"));
+
+ count = elementsInSet (IC_JTLABELS (ic));
+
+ if ((count <= 7) ||
+ (count <= 16 && optimize.codeSpeed) ||
+ options.acall_ajmp)
+ {
+ /* This algorithm needs 9 cycles and 7 + 3*n bytes
+ if the switch argument is in a register.
+ (6 + 2*n bytes when options.acall_ajmp is set) */
+ /* Peephole may not convert ljmp to sjmp or ret
+ labelIsReturnOnly & labelInRange must check
+ currPl->ic->op != JUMPTABLE */
+ aopOp (cond, ic, FALSE);
+ /* get the condition into accumulator */
+ l = aopGet (cond, 0, FALSE, FALSE);
+ MOVA (l);
+ /* multiply by three */
+ if ((AOP_TYPE (cond) == AOP_REG) || (IS_AOP_PREG (cond) && !AOP (cond)->paged && !IS_VOLATILE (operandType (cond))))
+ {
+ emitcode ("add", "a,%s", l);
+ if (options.acall_ajmp == 0)
+ emitcode ("add", "a,%s", l);
+ }
+ else
+ {
+ if (options.acall_ajmp == 0)
+ {
+ MOVB ("#0x03");
+ emitcode ("mul", "ab");
+ }
+ else
+ {
+ emitcode ("add", "a,acc");
+ }
+ }
+ freeAsmop (cond, NULL, ic, TRUE);
+
+ jtab = newiTempLabel (NULL);
+ emitcode ("mov", "dptr,#!tlabel", labelKey2num (jtab->key));
+ emitcode ("jmp", "@a+dptr");
+ emitLabel (jtab);
+ /* now generate the jump labels */
+ for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
+ if (options.acall_ajmp)
+ emitcode ("ajmp", "!tlabel", labelKey2num (jtab->key));
+ else
+ emitcode ("ljmp", "!tlabel", labelKey2num (jtab->key));
+ }
+ else
+ {
+ /* this algorithm needs 14 cycles and 14 + 2*n bytes
+ if the switch argument is in a register.
+ For n>7 this algorithm may be more compact */
+ jtablo = newiTempLabel (NULL);
+ jtabhi = newiTempLabel (NULL);
+
+ /* get the condition into accumulator.
+ Using b as temporary storage, if register push/pop is needed */
+ aopOp (cond, ic, FALSE);
+ l = aopGet (cond, 0, FALSE, FALSE);
+ if ((AOP_TYPE (cond) == AOP_R0 && _G.r0Pushed) ||
+ (AOP_TYPE (cond) == AOP_R1 && _G.r1Pushed) ||
+ EQ (l, "a") || EQ (l, "acc") ||
+ (count > 125 && EQ (l, "dpl")) ||
+ IS_VOLATILE (operandType (cond)))
+ {
+ // (MB) what if B is in use???
+ wassertl (!BINUSE, "B was in use");
+ MOVB (l);
+ l = "b";
+ useB = TRUE;
+ }
+ freeAsmop (cond, NULL, ic, TRUE);
+ MOVA (l);
+ if (count <= 125)
+ {
+ emitcode ("add", "a,#(!tlabel-3-.)", labelKey2num (jtablo->key));
+ emitcode ("movc", "a,@a+pc");
+ if (EQ (l, "dpl"))
+ {
+ emitcode ("xch", "a,dpl");
+ }
+ else
+ {
+ emitcode ("mov", "dpl,a");
+ MOVA (l);
+ }
+ emitcode ("add", "a,#(!tlabel-3-.)", labelKey2num (jtabhi->key));
+ emitcode ("movc", "a,@a+pc");
+ emitcode ("mov", "dph,a");
+ }
+ else
+ {
+ /* this scales up to n<=255, but needs four more bytes
+ and changes dptr */
+ emitcode ("mov", "dptr,#!tlabel", labelKey2num (jtablo->key));
+ emitcode ("movc", "a,@a+dptr");
+ if (useB)
+ {
+ emitcode ("xch", "a,b");
+ }
+ else
+ {
+ emitpush ("acc");
+ MOVA (l);
+ }
+ emitcode ("mov", "dptr,#!tlabel", labelKey2num (jtabhi->key));
+ emitcode ("movc", "a,@a+dptr");
+ emitcode ("mov", "dph,a");
+ if (useB)
+ emitcode ("mov", "dpl,b");
+ else
+ emitpop ("dpl");
+ }
+
+ emitcode ("clr", "a");
+ emitcode ("jmp", "@a+dptr");
+
+ /* now generate jump table, LSB */
+ emitLabel (jtablo);
+ for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
+ emitcode (".db", "!tlabel", labelKey2num (jtab->key));
+
+ /* now generate jump table, MSB */
+ emitLabel (jtabhi);
+ for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
+ emitcode (".db", "!tlabel>>8", labelKey2num (jtab->key));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCast - gen code for casting */
+/*-----------------------------------------------------------------*/
+static void
+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;
+ bool right_boolean;
+
+ D (emitcode (";", "genCast"));
+
+ /* if they are equivalent then do nothing */
+ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
+ return;
+
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ right_boolean = IS_BOOLEAN (rtype) || IS_BITFIELD (rtype) && SPEC_BLEN (getSpec (rtype)) == 1;
+
+ /* if the result is a bit (and not a bitfield) */
+ if (IS_BOOLEAN (OP_SYMBOL (result)->type) && !right_boolean)
+ {
+ assignBit (result, right);
+ goto release;
+ }
+
+ /* if they are the same size : or less */
+ if (AOP_SIZE (result) <= AOP_SIZE (right))
+ {
+ /* if they are in the same place */
+ if (sameRegs (AOP (right), AOP (result)))
+ goto release;
+
+ /* if they are in different places then copy */
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+ goto release;
+ }
+
+ /* if the either is of type pointer */
+ if ((IS_PTR (ctype) || IS_PTR (rtype)) && !IS_INTEGRAL (rtype))
+ {
+ int p_type;
+ sym_link *type = operandType (right);
+ sym_link *etype = getSpec (type);
+
+ /* pointer to generic pointer or long */
+ if (AOP_SIZE (result) >= GPTRSIZE)
+ {
+ if (IS_PTR (type))
+ {
+ p_type = DCL_TYPE (type);
+ }
+ else
+ {
+ if (SPEC_SCLS (etype) == S_REGISTER)
+ {
+ // let's assume it is a generic pointer
+ p_type = GPOINTER;
+ }
+ else
+ {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE (SPEC_OCLS (etype));
+ }
+ }
+
+ /* the first two bytes are known */
+ size = GPTRSIZE - 1;
+ offset = 0;
+ while (size--)
+ {
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+ /* the third byte depending on type */
+ {
+ int gpVal;
+
+ /* If there will be no loss of precision, handle generic */
+ /* pointer as special case to avoid generating warning */
+ if (p_type == GPOINTER && AOP_SIZE (result) >= GPTRSIZE)
+ gpVal = -1;
+ else
+ gpVal = pointerTypeToGPByte (p_type, NULL, NULL);
+
+ if (gpVal == -1)
+ {
+ // pointerTypeToGPByte will have warned, just copy.
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ }
+ else
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "#0x%02x", gpVal);
+ aopPut (result, dbuf_c_str (&dbuf), GPTRSIZE - 1);
+ dbuf_destroy (&dbuf);
+ }
+ }
+
+ /* 8051 uses unsigned address spaces, so no sign extension needed. */
+ /* Pad the remaining bytes of the result (if any) with 0. */
+ size = AOP_SIZE (result) - GPTRSIZE;
+ offset = GPTRSIZE;
+ while (size--)
+ {
+ aopPut (result, zero, offset++);
+ }
+ goto release;
+ }
+
+ /* just copy the pointers */
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+ goto release;
+ }
+
+ /* so we now know that the size of destination is greater
+ than the size of the source */
+ /* we move to result for the size of source */
+ size = AOP_SIZE (right);
+ offset = 0;
+ while (size--)
+ {
+ aopPut (result, aopGet (right, offset, FALSE, FALSE), offset);
+ offset++;
+ }
+
+ /* now depending on the sign of the source && destination */
+ size = AOP_SIZE (result) - AOP_SIZE (right);
+ /* if unsigned or not an integral type */
+ if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
+ {
+ while (size--)
+ {
+ aopPut (result, zero, offset++);
+ }
+ }
+ else
+ {
+ /* we need to extend the sign :{ */
+ MOVA (aopGet (right, AOP_SIZE (right) - 1, FALSE, FALSE));
+ emitcode ("rlc", "a");
+ emitcode ("subb", "a,acc");
+ while (size--)
+ aopPut (result, "a", offset++);
+ }
+
+ /* we are done hurray !!!! */
+
+release:
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDjnz - generate decrement & jump if not zero instruction */
+/*-----------------------------------------------------------------*/
+static int
+genDjnz (iCode * ic, iCode * ifx)
+{
+ symbol *lbl, *lbl1;
+ if (!ifx)
+ return 0;
+
+ /* if the if condition has a false label
+ then we cannot save */
+ if (IC_FALSE (ifx))
+ return 0;
+
+ /* if the minus is not of the form a = a - 1 */
+ if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) || !IS_OP_LITERAL (IC_RIGHT (ic)))
+ return 0;
+
+ if (operandLitValue (IC_RIGHT (ic)) != 1)
+ return 0;
+
+ /* if the size of this greater than one then no saving */
+ if (getSize (operandType (IC_RESULT (ic))) > 1)
+ return 0;
+
+ /* otherwise we can save BIG */
+
+ popForBranch (ic->next, TRUE);
+
+ D (emitcode (";", "genDjnz"));
+
+ lbl = newiTempLabel (NULL);
+ lbl1 = newiTempLabel (NULL);
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+
+ if (AOP_NEEDSACC (IC_RESULT (ic)))
+ {
+ /* If the result is accessed indirectly via
+ * the accumulator, we must explicitly write
+ * it back after the decrement.
+ */
+ const char *rByte = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
+
+ if (!EQ (rByte, "a"))
+ {
+ /* Something is hopelessly wrong */
+ fprintf (stderr, "*** warning: internal error at %s:%d\n", __FILE__, __LINE__);
+ /* We can just give up; the generated code will be inefficient,
+ * but what the hey.
+ */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ return 0;
+ }
+ emitcode ("dec", "%s", rByte);
+ aopPut (IC_RESULT (ic), rByte, 0);
+ emitcode ("jnz", "!tlabel", labelKey2num (lbl->key));
+ }
+ else if (IS_AOP_PREG (IC_RESULT (ic)))
+ {
+ emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
+ MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ ifx->generated = 1;
+ emitcode ("jnz", "!tlabel", labelKey2num (lbl->key));
+ }
+ else
+ {
+ emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, FALSE), labelKey2num (lbl->key));
+ }
+ emitcode ("sjmp", "!tlabel", labelKey2num (lbl1->key));
+ emitLabel (lbl);
+ emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key));
+ emitLabel (lbl1);
+
+ if (!ifx->generated)
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ ifx->generated = 1;
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genReceive - generate code for a receive iCode */
+/*-----------------------------------------------------------------*/
+static void
+genReceive (iCode * ic)
+{
+ int size = getSize (operandType (IC_RESULT (ic)));
+ int offset = 0;
+
+ D (emitcode (";", "genReceive"));
+
+ if (ic->argreg == 1)
+ {
+ /* first parameter */
+ if ((isOperandInFarSpace (IC_RESULT (ic)) ||
+ isOperandInPagedSpace (IC_RESULT (ic))) && (OP_SYMBOL (IC_RESULT (ic))->isspilt || IS_TRUE_SYMOP (IC_RESULT (ic))))
+ {
+ reg_info *tempRegs[8];
+ int receivingA = 0;
+ int roffset = 0;
+
+ for (offset = 0; offset < size; offset++)
+ if (EQ (fReturn[offset], "a"))
+ receivingA = 1;
+
+ if (!receivingA)
+ {
+ if (size == 1 || getTempRegs (tempRegs, size - 1, ic))
+ {
+ for (offset = size - 1; offset > 0; offset--)
+ emitcode ("mov", "%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
+ emitcode ("mov", "a,%s", fReturn[0]);
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+ aopPut (IC_RESULT (ic), "a", offset);
+ for (offset = 1; offset < size; offset++)
+ aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
+ goto release;
+ }
+ }
+ else
+ {
+ if (getTempRegs (tempRegs, size, ic))
+ {
+ for (offset = 0; offset < size; offset++)
+ emitcode ("mov", "%s,%s", tempRegs[offset]->name, fReturn[offset]);
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ for (offset = 0; offset < size; offset++)
+ aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
+ goto release;
+ }
+ }
+
+ offset = fReturnSizeMCS51 - size;
+ while (size--)
+ {
+ emitpush ((!EQ (fReturn[fReturnSizeMCS51 - offset - 1], "a") ? fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
+ offset++;
+ }
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_RESULT (ic));
+ offset = 0;
+ while (size--)
+ {
+ emitpop ("acc");
+ aopPut (IC_RESULT (ic), "a", offset++);
+ }
+ }
+ else
+ {
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+ assignResultValue (IC_RESULT (ic), NULL);
+ }
+ }
+ else if (ic->argreg > 12)
+ {
+ /* bit parameters */
+ reg_info *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
+
+ BitBankUsed = 1;
+ if (!reg || reg->rIdx != ic->argreg - 5)
+ {
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ emitcode ("mov", "c,%s", rb1regs[ic->argreg - 5]);
+ outBitC (IC_RESULT (ic));
+ }
+ }
+ else
+ {
+ /* other parameters */
+ int rb1off;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ rb1off = ic->argreg;
+ while (size--)
+ {
+ aopPut (IC_RESULT (ic), rb1regs[rb1off++ - 5], offset++);
+ }
+ }
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDummyRead - generate code for dummy read of volatiles */
+/*-----------------------------------------------------------------*/
+static void
+genDummyRead (iCode * ic)
+{
+ operand *op;
+ int size, offset;
+
+ D (emitcode (";", "genDummyRead"));
+
+ op = IC_RIGHT (ic);
+ if (op && IS_SYMOP (op))
+ {
+ aopOp (op, ic, FALSE);
+
+ /* if the result is a bit */
+ if (AOP_TYPE (op) == AOP_CRY)
+ emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+ else
+ {
+ /* bit variables done */
+ /* general case */
+ size = AOP_SIZE (op);
+ offset = 0;
+ while (size--)
+ {
+ MOVA (aopGet (op, offset, FALSE, FALSE));
+ offset++;
+ }
+ }
+
+ freeAsmop (op, NULL, ic, TRUE);
+ }
+
+ op = IC_LEFT (ic);
+ if (op && IS_SYMOP (op))
+ {
+ aopOp (op, ic, FALSE);
+
+ /* if the result is a bit */
+ if (AOP_TYPE (op) == AOP_CRY)
+ emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+ else
+ {
+ /* bit variables done */
+ /* general case */
+ size = AOP_SIZE (op);
+ offset = 0;
+ while (size--)
+ {
+ MOVA (aopGet (op, offset, FALSE, FALSE));
+ offset++;
+ }
+ }
+
+ freeAsmop (op, NULL, ic, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode * ic)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ D (emitcode (";", "genCritical"));
+
+ if (IC_RESULT (ic))
+ {
+ aopOp (IC_RESULT (ic), ic, TRUE);
+ aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
+ emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */
+ aopPut (IC_RESULT (ic), zero, 0);
+ emitLabel (tlbl);
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+ else
+ {
+ emitcode ("setb", "c");
+ emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */
+ emitcode ("clr", "c");
+ emitLabel (tlbl);
+ emitpush ("psw"); /* save old ea via c in psw on top of stack */
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode * ic)
+{
+ D (emitcode (";", "genEndCritical"));
+
+ if (IC_RIGHT (ic))
+ {
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+ {
+ emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
+ emitcode ("mov", "ea,c");
+ }
+ else
+ {
+ if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
+ MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
+ emitcode ("rrc", "a");
+ emitcode ("mov", "ea,c");
+ }
+ freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+ }
+ else
+ {
+ emitpop ("psw"); /* restore ea via c in psw on top of stack */
+ emitcode ("mov", "ea,c");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* gen51Code - generate code for 8051 based controllers */
+/*-----------------------------------------------------------------*/
+void
+gen51Code (iCode * lic)
+{
+ iCode *ic;
+ int cln = 0;
+#ifdef _DEBUG
+ int cseq = 0;
+#endif
+
+ _G.currentFunc = NULL;
+
+ /* print the allocation information */
+ if (allocInfo && currFunc)
+ printAllocInfo (currFunc, codeOutBuf);
+ /* if debug information required */
+ if (options.debug && currFunc)
+ {
+ debugFile->writeFunction (currFunc, lic);
+ }
+ /* stack pointer name */
+ if (options.useXstack)
+ spname = "_spx";
+ else
+ spname = "sp";
+
+ for (ic = lic; ic; ic = ic->next)
+ {
+ initGenLineElement ();
+
+ genLine.lineElement.ic = ic;
+
+ if (ic->lineno && cln != ic->lineno)
+ {
+ if (options.debug)
+ {
+ debugFile->writeCLine (ic);
+ }
+ if (!options.noCcodeInAsm)
+ {
+ emitcode (";", "%s:%d: %s", ic->filename, ic->lineno, printCLine (ic->filename, ic->lineno));
+ }
+ cln = ic->lineno;
+ }
+#ifdef _DEBUG
+ if (ic->seqPoint && ic->seqPoint != cseq)
+ {
+ emitcode (";", "sequence point %d", ic->seqPoint);
+ cseq = ic->seqPoint;
+ }
+#endif
+ if (options.iCodeInAsm)
+ {
+ char regsInUse[80];
+ int i;
+ const char *iLine;
+
+#if 0
+ for (i = 0; i < 8; i++)
+ {
+ sprintf (&regsInUse[i], "%c", ic->riu & (1 << i) ? i + '0' : '-'); /* show riu */
+ regsInUse[i] = 0;
+ }
+#else
+ strcpy (regsInUse, "--------");
+ for (i = 0; i < 8; i++)
+ {
+ if (bitVectBitValue (ic->rMask, i))
+ {
+ int offset = regs8051[i].offset;
+ regsInUse[offset] = offset + '0'; /* show rMask */
+ }
+ }
+#endif
+ iLine = printILine (ic);
+ emitcode (";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
+ dbuf_free (iLine);
+ }
+ /* if the result is marked as
+ spilt and rematerializable or code for
+ this has already been generated then
+ do nothing */
+ if (resultRemat (ic) || ic->generated)
+ continue;
+
+ /* depending on the operation */
+ switch (ic->op)
+ {
+ case '!':
+ genNot (ic);
+ break;
+
+ case '~':
+ genCpl (ic);
+ break;
+
+ case UNARYMINUS:
+ genUminus (ic);
+ break;
+
+ case IPUSH:
+ genIpush (ic);
+ break;
+
+ case IPOP:
+ {
+ iCode *ifxIc, *popIc;
+ bool CommonRegs = FALSE;
+
+ /* IPOP happens only when trying to restore a
+ spilt live range, if there is an ifx statement
+ following this pop (or several) then the if statement might
+ be using some of the registers being popped which
+ would destroy the contents of the register so
+ we need to check for this condition and handle it */
+ for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
+ for (popIc = ic; popIc && popIc->op == IPOP; popIc = popIc->next)
+ CommonRegs |= (ifxIc && ifxIc->op == IFX && !ifxIc->generated && regsInCommon (IC_LEFT (popIc), IC_COND (ifxIc)));
+ if (CommonRegs)
+ genIfx (ifxIc, ic);
+ else
+ genIpop (ic);
+ }
+ break;
+
+ case CALL:
+ genCall (ic);
+ break;
+
+ case PCALL:
+ genPcall (ic);
+ break;
+
+ case FUNCTION:
+ genFunction (ic);
+ break;
+
+ case ENDFUNCTION:
+ genEndFunction (ic);
+ break;
+
+ case RETURN:
+ genRet (ic);
+ break;
+
+ case LABEL:
+ genLabel (ic);
+ break;
+
+ case GOTO:
+ genGoto (ic);
+ break;
+
+ case '+':
+ genPlus (ic);
+ break;
+
+ case '-':
+ if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
+ genMinus (ic);
+ break;
+
+ case '*':
+ genMult (ic);
+ break;
+
+ case '/':
+ genDiv (ic);
+ break;
+
+ case '%':
+ genMod (ic);
+ break;
+
+ case '>':
+ genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case '<':
+ genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case LE_OP:
+ case GE_OP:
+ case NE_OP:
+
+ /* note these two are xlated by algebraic equivalence
+ in decorateType() in SDCCast.c */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got '>=' or '<=' shouldn't have come here");
+ break;
+
+ case EQ_OP:
+ genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case AND_OP:
+ genAndOp (ic);
+ break;
+
+ case OR_OP:
+ genOrOp (ic);
+ break;
+
+ case '^':
+ genXor (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case '|':
+ genOr (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case BITWISEAND:
+ genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case INLINEASM:
+ genInline (ic);
+ break;
+
+ case RRC:
+ genRRC (ic);
+ break;
+
+ case RLC:
+ genRLC (ic);
+ break;
+
+ case GETHBIT:
+ assert (0);
+ break;
+
+ case GETABIT:
+ genGetAbit (ic);
+ break;
+
+ case GETBYTE:
+ genGetByte (ic);
+ break;
+
+ case GETWORD:
+ genGetWord (ic);
+ break;
+
+ case LEFT_OP:
+ genLeftShift (ic);
+ break;
+
+ case RIGHT_OP:
+ genRightShift (ic);
+ break;
+
+ case GET_VALUE_AT_ADDRESS:
+ genPointerGet (ic, hasInc (IC_LEFT (ic), ic, getSize (operandType (IC_RESULT (ic)))), ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case '=':
+ if (POINTER_SET (ic))
+ genPointerSet (ic, hasInc (IC_RESULT (ic), ic, getSize (operandType (IC_RIGHT (ic)))));
+ else
+ genAssign (ic);
+ break;
+
+ case IFX:
+ genIfx (ic, NULL);
+ break;
+
+ case ADDRESS_OF:
+ genAddrOf (ic);
+ break;
+
+ case JUMPTABLE:
+ genJumpTab (ic);
+ break;
+
+ case CAST:
+ genCast (ic);
+ break;
+
+ case RECEIVE:
+ genReceive (ic);
+ break;
+
+ case SEND:
+ addSet (&_G.sendSet, ic);
+ break;
+
+ case DUMMY_READ_VOLATILE:
+ genDummyRead (ic);
+ break;
+
+ case CRITICAL:
+ genCritical (ic);
+ break;
+
+ case ENDCRITICAL:
+ genEndCritical (ic);
+ break;
+
+ case SWAP:
+ genSwap (ic);
+ break;
+
+ default:
+ ic = ic;
+ }
+ }
+
+ genLine.lineElement.ic = NULL;
+
+ /* now we are ready to call the
+ peep hole optimizer */
+ if (!options.nopeep)
+ peepHole (&genLine.lineHead);
+
+ /* now do the actual printing */
+ printLine (genLine.lineHead, codeOutBuf);
+
+ /* destroy the line list */
+ destroy_line_list ();
+}
diff --git a/src/mcs51/gen.h b/src/mcs51/gen.h
new file mode 100644
index 0000000..66e3e06
--- /dev/null
+++ b/src/mcs51/gen.h
@@ -0,0 +1,88 @@
+/*-------------------------------------------------------------------------
+ gen.h - header file for code generation for 8051
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#ifndef SDCCGEN51_H
+#define SDCCGEN51_H
+
+enum
+{
+ AOP_LIT = 1,
+ AOP_REG, AOP_DIR,
+ AOP_DPTR, AOP_R0, AOP_R1,
+ AOP_STK, AOP_IMMD, AOP_STR,
+ AOP_CRY, AOP_ACC, AOP_DUMMY
+};
+
+/* type asmop : a homogenised type for
+ all the different spaces an operand can be
+ in */
+typedef struct asmop
+{
+ short type;
+ /* can have values
+ AOP_LIT - operand is a literal value
+ AOP_REG - is in registers
+ AOP_DIR - direct just a name
+ AOP_DPTR - dptr contains address of operand
+ AOP_R0/R1 - r0/r1 contains address of operand
+ AOP_STK - should be pushed on stack this
+ can happen only for the result
+ AOP_IMMD - immediate value for eg. remateriazable
+ AOP_CRY - carry contains the value of this
+ AOP_STR - array of strings
+ AOP_ACC - result is in the acc:b pair
+ AOP_DUMMY - read as 0, discard writes
+ */
+ short coff; /* current offset */
+ short size; /* total size */
+ unsigned code:1; /* is in Code space */
+ unsigned paged:1; /* in paged memory */
+ unsigned short allocated; /* number of times allocated */
+ union
+ {
+ value *aop_lit; /* if literal */
+ reg_info *aop_reg[8]; /* array of registers */
+ char *aop_dir; /* if direct */
+ reg_info *aop_ptr; /* either -> to r0 or r1 */
+ struct
+ {
+ int from_cast_remat; /* cast remat created this : immd2 field used for highest order */
+ char *aop_immd1; /* if immediate others are implied */
+ char *aop_immd2; /* cast remat will generate this */
+ } aop_immd;
+ symbol *aop_sym; /* symbol when AOP_STK */
+ char *aop_str[8]; /* just a string array containing the location */
+ }
+ aopu;
+}
+asmop;
+
+void gen51Code (iCode *);
+void mcs51_emitDebuggerSymbol (const char *);
+
+extern char *fReturn8051[];
+extern unsigned fReturnSizeMCS51;
+//extern char **fReturn;
+
+#endif
diff --git a/src/mcs51/main.c b/src/mcs51/main.c
new file mode 100644
index 0000000..207356c
--- /dev/null
+++ b/src/mcs51/main.c
@@ -0,0 +1,934 @@
+/*-------------------------------------------------------------------------
+ main.c - mcs51 specific general functions
+
+ Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
+ Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com
+ Copyright (C) 2000, Michael Hope
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-------------------------------------------------------------------*/
+/*
+ Note that mlh prepended _mcs51_ on the static functions. Makes
+ it easier to set a breakpoint using the debugger.
+*/
+#include "common.h"
+#include "main.h"
+#include "ralloc.h"
+#include "gen.h"
+#include "peep.h"
+#include "rtrack.h"
+#include "dbuf_string.h"
+#include "../SDCCutil.h"
+
+static char _defaultRules[] =
+{
+#include "peeph.rul"
+};
+
+#define OPTION_SMALL_MODEL "--model-small"
+#define OPTION_MEDIUM_MODEL "--model-medium"
+#define OPTION_LARGE_MODEL "--model-large"
+#define OPTION_HUGE_MODEL "--model-huge"
+#define OPTION_STACK_SIZE "--stack-size"
+
+static OPTION _mcs51_options[] =
+ {
+ { 0, OPTION_SMALL_MODEL, NULL, "internal data space is used (default)"},
+ { 0, OPTION_MEDIUM_MODEL, NULL, "external paged data space is used"},
+ { 0, OPTION_LARGE_MODEL, NULL, "external data space is used"},
+ { 0, OPTION_HUGE_MODEL, NULL, "functions are banked, data in external space"},
+ { 0, OPTION_STACK_SIZE, &options.stack_size, "Tells the linker to allocate this space for stack", CLAT_INTEGER },
+ { 0, "--parms-in-bank1", &options.parms_in_bank1, "use Bank1 for parameter passing"},
+ { 0, "--pack-iram", NULL, "Tells the linker to pack variables in internal ram (default)"},
+ { 0, "--no-pack-iram", &options.no_pack_iram, "Deprecated: Tells the linker not to pack variables in internal ram"},
+ { 0, "--acall-ajmp", &options.acall_ajmp, "Use acall/ajmp instead of lcall/ljmp" },
+ { 0, "--no-ret-without-call", &options.no_ret_without_call, "Do not use ret independent of acall/lcall" },
+ { 0, NULL }
+ };
+
+/* list of key words used by msc51 */
+static char *_mcs51_keywords[] =
+{
+ "at",
+ "banked",
+ "bit",
+ "code",
+ "critical",
+ "data",
+ "far",
+ "generic",
+ "idata",
+ "interrupt",
+ "naked",
+ "near",
+ "nonbanked",
+ "overlay",
+ "pdata",
+ "reentrant",
+ "sbit",
+ "sfr",
+ "sfr16",
+ "sfr32",
+ "using",
+ "xdata",
+ NULL
+};
+
+
+
+void mcs51_assignRegisters (ebbIndex *);
+
+static int regParmFlg = 0; /* determine if we can register a parameter */
+static int regBitParmFlg = 0; /* determine if we can register a bit parameter */
+
+static void
+_mcs51_init (void)
+{
+ asm_addTree (&asm_asxxxx_mapping);
+}
+
+static void
+_mcs51_reset_regparm (struct sym_link *funcType)
+{
+ regParmFlg = 0;
+ regBitParmFlg = 0;
+}
+
+static int
+_mcs51_regparm (sym_link * l, bool reentrant)
+{
+ if (IS_SPEC(l) && (SPEC_NOUN(l) == V_BIT))
+ {
+ /* bit parameters go to b0 thru b7 */
+ if (reentrant && (regBitParmFlg < 8))
+ {
+ regBitParmFlg++;
+ return 12 + regBitParmFlg;
+ }
+ return 0;
+ }
+ if (options.parms_in_bank1 == 0)
+ {
+ /* simple can pass only the first parameter in a register */
+ if (regParmFlg)
+ return 0;
+
+ regParmFlg = 1;
+ return 1;
+ }
+ else
+ {
+ int size = getSize(l);
+ int remain;
+
+ /* first one goes the usual way to DPTR */
+ if (regParmFlg == 0)
+ {
+ regParmFlg += 4 ;
+ return 1;
+ }
+ /* second one onwards goes to RB1_0 thru RB1_7 */
+ remain = regParmFlg - 4;
+ if (size > (8 - remain))
+ {
+ regParmFlg = 12 ;
+ return 0;
+ }
+ regParmFlg += size ;
+ return regParmFlg - size + 1;
+ }
+}
+
+static bool
+_mcs51_parseOptions (int *pargc, char **argv, int *i)
+{
+ /* TODO: allow port-specific command line options to specify
+ * segment names here.
+ */
+ return FALSE;
+}
+
+static void
+_mcs51_finaliseOptions (void)
+{
+ if (options.noXinitOpt)
+ port->genXINIT=0;
+
+ switch (options.model)
+ {
+ case MODEL_SMALL:
+ port->mem.default_local_map = data;
+ port->mem.default_globl_map = data;
+ port->s.ptr_size = 3;
+ break;
+ case MODEL_MEDIUM:
+ port->mem.default_local_map = pdata;
+ port->mem.default_globl_map = pdata;
+ port->s.ptr_size = 3;
+ break;
+ case MODEL_LARGE:
+ case MODEL_HUGE:
+ port->mem.default_local_map = xdata;
+ port->mem.default_globl_map = xdata;
+ port->s.ptr_size = 3;
+ break;
+ default:
+ port->mem.default_local_map = data;
+ port->mem.default_globl_map = data;
+ break;
+ }
+
+ if (options.parms_in_bank1)
+ addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
+
+ /* mcs51 has an assembly coded float library that's almost always reentrant */
+ if (!options.useXstack)
+ options.float_rent = 1;
+
+ if (options.omitFramePtr)
+ port->stack.reent_overhead = 0;
+
+ /* set up external stack location if not explicitly specified */
+ if (!options.xstack_loc)
+ options.xstack_loc = options.xdata_loc;
+}
+
+static void
+_mcs51_setDefaultOptions (void)
+{
+}
+
+static const char *
+_mcs51_getRegName (const struct reg_info *reg)
+{
+ if (reg)
+ return reg->name;
+ return "err";
+}
+
+static void
+_mcs51_genAssemblerPreamble (FILE * of)
+{
+ if (options.parms_in_bank1)
+ {
+ int i;
+ for (i=0; i < 8 ; i++ )
+ fprintf (of, "\tb1_%d = 0x%x \n", i, 8+i);
+ }
+}
+
+/* Generate interrupt vector table. */
+static int
+_mcs51_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts)
+{
+ int i;
+
+ dbuf_printf (oBuf, "\t%cjmp\t__sdcc_gsinit_startup\n", options.acall_ajmp?'a':'l');
+ if((options.acall_ajmp)&&(maxInterrupts)) dbuf_printf (oBuf, "\t.ds\t1\n");
+
+ /* now for the other interrupts */
+ for (i = 0; i < maxInterrupts; i++)
+ {
+ if (interrupts[i])
+ {
+ dbuf_printf (oBuf, "\t%cjmp\t%s\n", options.acall_ajmp?'a':'l', interrupts[i]->rname);
+ if ( i != maxInterrupts - 1 )
+ dbuf_printf (oBuf, "\t.ds\t%d\n", options.acall_ajmp?6:5);
+ }
+ else
+ {
+ dbuf_printf (oBuf, "\treti\n");
+ if ( i != maxInterrupts - 1 )
+ dbuf_printf (oBuf, "\t.ds\t7\n");
+ }
+ }
+ return TRUE;
+}
+
+static void
+_mcs51_genExtraAreas(FILE *of, bool hasMain)
+{
+ tfprintf (of, "\t!area\n", HOME_NAME);
+ tfprintf (of, "\t!area\n", "GSINIT0 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT1 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT2 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT3 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT4 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT5 (CODE)");
+ tfprintf (of, "\t!area\n", STATIC_NAME);
+ tfprintf (of, "\t!area\n", port->mem.post_static_name);
+ tfprintf (of, "\t!area\n", CODE_NAME);
+}
+
+static void
+_mcs51_genInitStartup (FILE *of)
+{
+ tfprintf (of, "\t!global\n", "__sdcc_gsinit_startup");
+ tfprintf (of, "\t!global\n", "__sdcc_program_startup");
+ tfprintf (of, "\t!global\n", "__start__stack");
+
+ if (options.useXstack)
+ {
+ tfprintf (of, "\t!global\n", "__sdcc_init_xstack");
+ tfprintf (of, "\t!global\n", "__start__xstack");
+ }
+
+ // if the port can copy the XINIT segment to XISEG
+ if (port->genXINIT)
+ {
+ port->genXINIT(of);
+ }
+
+ if (!getenv("SDCC_NOGENRAMCLEAR"))
+ tfprintf (of, "\t!global\n", "__mcs51_genRAMCLEAR");
+}
+
+
+/* Generate code to copy XINIT to XISEG */
+static void _mcs51_genXINIT (FILE * of)
+{
+ tfprintf (of, "\t!global\n", "__mcs51_genXINIT");
+
+ if (!getenv("SDCC_NOGENRAMCLEAR"))
+ tfprintf (of, "\t!global\n", "__mcs51_genXRAMCLEAR");
+}
+
+
+/* Do CSE estimation */
+static bool cseCostEstimation (iCode *ic, iCode *pdic)
+{
+ operand *result = IC_RESULT(ic);
+ sym_link *result_type = operandType(result);
+
+ /* if it is a pointer then return ok for now */
+ if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
+
+ /* if bitwise | add & subtract then no since mcs51 is pretty good at it
+ so we will cse only if they are local (i.e. both ic & pdic belong to
+ the same basic block */
+ if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-')
+ {
+ /* then if they are the same Basic block then ok */
+ if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
+ else return 0;
+ }
+
+ /* for others it is cheaper to do the cse */
+ return 1;
+}
+
+/* Indicate which extended bit operations this port supports */
+static bool
+hasExtBitOp (int op, int size)
+{
+ if (op == RRC
+ || op == RLC
+ || op == GETABIT
+ || op == GETBYTE
+ || op == GETWORD
+ || (op == SWAP && size <= 2)
+ )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Indicate the expense of an access to an output storage class */
+static int
+oclsExpense (struct memmap *oclass)
+{
+ if (IN_FARSPACE(oclass))
+ return 1;
+
+ return 0;
+}
+
+static bool
+_hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
+{
+ return getSize (left) == 1 && getSize (right) == 1;
+}
+
+static int
+instructionSize(char *inst, char *op1, char *op2)
+{
+ #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
+ #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
+ #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
+ #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
+ #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
+
+ /* Based on the current (2003-08-22) code generation for the
+ small library, the top instruction probability is:
+
+ 57% mov/movx/movc
+ 6% push
+ 6% pop
+ 4% inc
+ 4% lcall
+ 4% add
+ 3% clr
+ 2% subb
+ */
+ /* mov, push, & pop are the 69% of the cases. Check them first! */
+ if (ISINST ("mov"))
+ {
+ if (*(inst+3)=='x') return 1; /* movx */
+ if (*(inst+3)=='c') return 1; /* movc */
+ if (IS_C (op1) || IS_C (op2)) return 2;
+ if (IS_A (op1))
+ {
+ if (IS_Rn (op2) || IS_atRi (op2)) return 1;
+ return 2;
+ }
+ if (IS_Rn(op1) || IS_atRi(op1))
+ {
+ if (IS_A(op2)) return 1;
+ return 2;
+ }
+ if (strcmp (op1, "dptr") == 0) return 3;
+ if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2;
+ return 3;
+ }
+
+ if (ISINST ("push")) return 2;
+ if (ISINST ("pop")) return 2;
+
+ if (ISINST ("lcall")) return 3;
+ if (ISINST ("ret")) return 1;
+ if (ISINST ("ljmp")) return 3;
+ if (ISINST ("sjmp")) return 2;
+ if (ISINST ("rlc")) return 1;
+ if (ISINST ("rrc")) return 1;
+ if (ISINST ("rl")) return 1;
+ if (ISINST ("rr")) return 1;
+ if (ISINST ("swap")) return 1;
+ if (ISINST ("jc")) return 2;
+ if (ISINST ("jnc")) return 2;
+ if (ISINST ("jb")) return 3;
+ if (ISINST ("jnb")) return 3;
+ if (ISINST ("jbc")) return 3;
+ if (ISINST ("jmp")) return 1; // always jmp @a+dptr
+ if (ISINST ("jz")) return 2;
+ if (ISINST ("jnz")) return 2;
+ if (ISINST ("cjne")) return 3;
+ if (ISINST ("mul")) return 1;
+ if (ISINST ("div")) return 1;
+ if (ISINST ("da")) return 1;
+ if (ISINST ("xchd")) return 1;
+ if (ISINST ("reti")) return 1;
+ if (ISINST ("nop")) return 1;
+ if (ISINST ("acall")) return 2;
+ if (ISINST ("ajmp")) return 2;
+
+
+ if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch"))
+ {
+ if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+ return 2;
+ }
+ if (ISINST ("inc") || ISINST ("dec"))
+ {
+ if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
+ if (strcmp(op1, "dptr") == 0) return 1;
+ return 2;
+ }
+ if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl"))
+ {
+ if (IS_C(op1)) return 2;
+ if (IS_A(op1))
+ {
+ if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+ return 2;
+ }
+ else
+ {
+ if (IS_A(op2)) return 2;
+ return 3;
+ }
+ }
+ if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl"))
+ {
+ if (IS_A(op1) || IS_C(op1)) return 1;
+ return 2;
+ }
+ if (ISINST ("djnz"))
+ {
+ if (IS_Rn(op1)) return 2;
+ return 3;
+ }
+
+ /* If the instruction is unrecognized, we shouldn't try to optimize. */
+ /* Return a large value to discourage optimization. */
+ return 999;
+}
+
+static asmLineNode *
+newAsmLineNode (void)
+{
+ asmLineNode *aln;
+
+ aln = Safe_alloc ( sizeof (asmLineNode));
+ aln->size = 0;
+ aln->regsRead = NULL;
+ aln->regsWritten = NULL;
+
+ return aln;
+}
+
+
+typedef struct mcs51operanddata
+ {
+ char name[6];
+ int regIdx1;
+ int regIdx2;
+ }
+mcs51operanddata;
+
+static mcs51operanddata mcs51operandDataTable[] =
+ {
+ {"a", A_IDX, -1},
+ {"ab", A_IDX, B_IDX},
+ {"ac", CND_IDX, -1},
+ {"acc", A_IDX, -1},
+ {"ar0", R0_IDX, -1},
+ {"ar1", R1_IDX, -1},
+ {"ar2", R2_IDX, -1},
+ {"ar3", R3_IDX, -1},
+ {"ar4", R4_IDX, -1},
+ {"ar5", R5_IDX, -1},
+ {"ar6", R6_IDX, -1},
+ {"ar7", R7_IDX, -1},
+ {"b", B_IDX, -1},
+ {"c", CND_IDX, -1},
+ {"cy", CND_IDX, -1},
+ {"dph", DPH_IDX, -1},
+ {"dpl", DPL_IDX, -1},
+ {"dptr", DPL_IDX, DPH_IDX},
+ {"f0", CND_IDX, -1},
+ {"f1", CND_IDX, -1},
+ {"ov", CND_IDX, -1},
+ {"p", CND_IDX, -1},
+ {"psw", CND_IDX, -1},
+ {"r0", R0_IDX, -1},
+ {"r1", R1_IDX, -1},
+ {"r2", R2_IDX, -1},
+ {"r3", R3_IDX, -1},
+ {"r4", R4_IDX, -1},
+ {"r5", R5_IDX, -1},
+ {"r6", R6_IDX, -1},
+ {"r7", R7_IDX, -1},
+ };
+
+static int
+mcs51operandCompare (const void *key, const void *member)
+{
+ return strcmp((const char *)key, ((mcs51operanddata *)member)->name);
+}
+
+static void
+updateOpRW (asmLineNode *aln, char *op, char *optype)
+{
+ mcs51operanddata *opdat;
+ char *dot;
+
+ dot = strchr(op, '.');
+ if (dot)
+ *dot = '\0';
+
+ opdat = bsearch (op, mcs51operandDataTable,
+ sizeof(mcs51operandDataTable)/sizeof(mcs51operanddata),
+ sizeof(mcs51operanddata), mcs51operandCompare);
+
+ if (opdat && strchr(optype,'r'))
+ {
+ if (opdat->regIdx1 >= 0)
+ aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx1);
+ if (opdat->regIdx2 >= 0)
+ aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx2);
+ }
+ if (opdat && strchr(optype,'w'))
+ {
+ if (opdat->regIdx1 >= 0)
+ aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx1);
+ if (opdat->regIdx2 >= 0)
+ aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx2);
+ }
+ if (op[0] == '@')
+ {
+ if (!strcmp(op, "@r0"))
+ aln->regsRead = bitVectSetBit (aln->regsRead, R0_IDX);
+ if (!strcmp(op, "@r1"))
+ aln->regsRead = bitVectSetBit (aln->regsRead, R1_IDX);
+ if (strstr(op, "dptr"))
+ {
+ aln->regsRead = bitVectSetBit (aln->regsRead, DPL_IDX);
+ aln->regsRead = bitVectSetBit (aln->regsRead, DPH_IDX);
+ }
+ if (strstr(op, "a+"))
+ aln->regsRead = bitVectSetBit (aln->regsRead, A_IDX);
+ }
+}
+
+typedef struct mcs51opcodedata
+ {
+ char name[6];
+ char class[3];
+ char pswtype[3];
+ char op1type[3];
+ char op2type[3];
+ }
+mcs51opcodedata;
+
+static mcs51opcodedata mcs51opcodeDataTable[] =
+ {
+ {"acall","j", "", "", ""},
+ {"add", "", "w", "rw", "r"},
+ {"addc", "", "rw", "rw", "r"},
+ {"ajmp", "j", "", "", ""},
+ {"anl", "", "", "rw", "r"},
+ {"cjne", "j", "w", "r", "r"},
+ {"clr", "", "", "w", ""},
+ {"cpl", "", "", "rw", ""},
+ {"da", "", "rw", "rw", ""},
+ {"dec", "", "", "rw", ""},
+ {"div", "", "w", "rw", ""},
+ {"djnz", "j", "", "rw", ""},
+ {"inc", "", "", "rw", ""},
+ {"jb", "j", "", "r", ""},
+ {"jbc", "j", "", "rw", ""},
+ {"jc", "j", "", "", ""},
+ {"jmp", "j", "", "", ""},
+ {"jnb", "j", "", "r", ""},
+ {"jnc", "j", "", "", ""},
+ {"jnz", "j", "", "", ""},
+ {"jz", "j", "", "", ""},
+ {"lcall","j", "", "", ""},
+ {"ljmp", "j", "", "", ""},
+ {"mov", "", "", "w", "r"},
+ {"movc", "", "", "w", "r"},
+ {"movx", "", "", "w", "r"},
+ {"mul", "", "w", "rw", ""},
+ {"nop", "", "", "", ""},
+ {"orl", "", "", "rw", "r"},
+ {"pop", "", "", "w", ""},
+ {"push", "", "", "r", ""},
+ {"ret", "j", "", "", ""},
+ {"reti", "j", "", "", ""},
+ {"rl", "", "", "rw", ""},
+ {"rlc", "", "rw", "rw", ""},
+ {"rr", "", "", "rw", ""},
+ {"rrc", "", "rw", "rw", ""},
+ {"setb", "", "", "w", ""},
+ {"sjmp", "j", "", "", ""},
+ {"subb", "", "rw", "rw", "r"},
+ {"swap", "", "", "rw", ""},
+ {"xch", "", "", "rw", "rw"},
+ {"xchd", "", "", "rw", "rw"},
+ {"xrl", "", "", "rw", "r"},
+ };
+
+static int
+mcs51opcodeCompare (const void *key, const void *member)
+{
+ return strcmp((const char *)key, ((mcs51opcodedata *)member)->name);
+}
+
+static asmLineNode *
+asmLineNodeFromLineNode (lineNode *ln)
+{
+ asmLineNode *aln = newAsmLineNode();
+ char *op, op1[256], op2[256];
+ int opsize;
+ const char *p;
+ char inst[8];
+ mcs51opcodedata *opdat;
+
+ p = ln->line;
+
+ while (*p && isspace(*p)) p++;
+ for (op = inst, opsize=1; *p; p++)
+ {
+ if (isspace(*p) || *p == ';' || *p == ':' || *p == '=')
+ break;
+ else
+ if (opsize < sizeof(inst))
+ *op++ = tolower(*p), opsize++;
+ }
+ *op = '\0';
+
+ if (*p == ';' || *p == ':' || *p == '=')
+ return aln;
+
+ while (*p && isspace(*p)) p++;
+ if (*p == '=')
+ return aln;
+
+ for (op = op1, opsize=1; *p && *p != ','; p++)
+ {
+ if (!isspace(*p) && opsize < sizeof(op1))
+ *op++ = tolower(*p), opsize++;
+ }
+ *op = '\0';
+
+ if (*p == ',') p++;
+ for (op = op2, opsize=1; *p && *p != ','; p++)
+ {
+ if (!isspace(*p) && opsize < sizeof(op2))
+ *op++ = tolower(*p), opsize++;
+ }
+ *op = '\0';
+
+ aln->size = instructionSize(inst, op1, op2);
+
+ aln->regsRead = newBitVect (END_IDX);
+ aln->regsWritten = newBitVect (END_IDX);
+
+ opdat = bsearch (inst, mcs51opcodeDataTable,
+ sizeof(mcs51opcodeDataTable)/sizeof(mcs51opcodedata),
+ sizeof(mcs51opcodedata), mcs51opcodeCompare);
+
+ if (opdat)
+ {
+ updateOpRW (aln, op1, opdat->op1type);
+ updateOpRW (aln, op2, opdat->op2type);
+ if (strchr(opdat->pswtype,'r'))
+ aln->regsRead = bitVectSetBit (aln->regsRead, CND_IDX);
+ if (strchr(opdat->pswtype,'w'))
+ aln->regsWritten = bitVectSetBit (aln->regsWritten, CND_IDX);
+ }
+
+ return aln;
+}
+
+static int
+getInstructionSize (lineNode *line)
+{
+ if (!line->aln)
+ line->aln = (asmLineNodeBase *) asmLineNodeFromLineNode (line);
+
+ return line->aln->size;
+}
+
+static bitVect *
+getRegsRead (lineNode *line)
+{
+ if (!line->aln)
+ line->aln = (asmLineNodeBase *) asmLineNodeFromLineNode (line);
+
+ return line->aln->regsRead;
+}
+
+static bitVect *
+getRegsWritten (lineNode *line)
+{
+ if (!line->aln)
+ line->aln = (asmLineNodeBase *) asmLineNodeFromLineNode (line);
+
+ return line->aln->regsWritten;
+}
+
+static const char * models[] =
+{
+ "small", "small-xstack", "small-stack-auto", "small-xstack-auto",
+ "medium", "medium-xstack", "medium-stack-auto", "medium-xstack-auto",
+ "large", "large-xstack", "large-stack-auto", "large-xstack-auto",
+ "huge", "huge-xstack", "huge-stack-auto", "huge-xstack-auto",
+};
+
+static const char *
+get_model (void)
+{
+ int index;
+
+ switch (options.model)
+ {
+ case MODEL_SMALL:
+ index = 0;
+ break;
+ case MODEL_MEDIUM:
+ index = 4;
+ break;
+ case MODEL_LARGE:
+ index = 8;
+ break;
+ case MODEL_HUGE:
+ index = 12;
+ break;
+ default:
+ werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+ return "unknown";
+ }
+ if (options.stackAuto)
+ index += 2;
+ if (options.useXstack)
+ index += 1;
+ return models[index];
+}
+
+/** $1 is always the basename.
+ $2 is always the output file.
+ $3 varies
+ $l is the list of extra options that should be there somewhere...
+ MUST be terminated with a NULL.
+*/
+static const char *_linkCmd[] =
+{
+ "sdld", "-nf", "$1", NULL
+};
+
+/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */
+static const char *_asmCmd[] =
+{
+ "sdas8051", "$l", "$3", "$2", "$1.asm", NULL
+};
+
+static const char * const _libs[] = { "mcs51", STD_LIB, STD_INT_LIB, STD_LONG_LIB, STD_FP_LIB, NULL, };
+
+/* Globals */
+PORT mcs51_port =
+{
+ TARGET_ID_MCS51,
+ "mcs51",
+ "MCU 8051", /* Target name */
+ NULL, /* Processor name */
+ {
+ glue,
+ TRUE, /* glue_up_main: Emit glue around main */
+ MODEL_SMALL | MODEL_MEDIUM | MODEL_LARGE | MODEL_HUGE,
+ MODEL_SMALL,
+ get_model,
+ },
+ { /* Assembler */
+ _asmCmd,
+ NULL,
+ "-plosgffwy", /* Options with debug */
+ "-plosgffw", /* Options without debug */
+ 0,
+ ".asm",
+ NULL /* no do_assemble function */
+ },
+ { /* Linker */
+ _linkCmd,
+ NULL,
+ NULL,
+ ".rel",
+ 1,
+ NULL, /* crt */
+ _libs, /* libs */
+ },
+ { /* Peephole optimizer */
+ _defaultRules,
+ getInstructionSize,
+ getRegsRead,
+ getRegsWritten,
+ mcs51DeadMove,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ },
+ /* Sizes: char, short, int, long, long long, near ptr, far ptr, gptr, func ptr, banked func ptr, bit, float */
+ { 1, 2, 2, 4, 8, 1, 2, 3, 2, 3, 1, 4 },
+ /* tags for generic pointers */
+ { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
+ {
+ "XSTK (PAG,XDATA)", // xstack_name
+ "STACK (DATA)", // istack_name
+ "CSEG (CODE)", // code_name
+ "DSEG (DATA)", // data_name
+ "ISEG (DATA)", // idata_name
+ "PSEG (PAG,XDATA)", // pdata_name
+ "XSEG (XDATA)", // xdata_name
+ "BSEG (BIT)", // bit_name
+ "RSEG (ABS,DATA)", // reg_name
+ "GSINIT (CODE)", // static_name
+ "OSEG (OVR,DATA)", // overlay_name
+ "GSFINAL (CODE)", // post_static_name
+ "HOME (CODE)", // home_name
+ "XISEG (XDATA)", // xidata_name - initialized xdata
+ "XINIT (CODE)", // xinit_name - a code copy of xiseg
+ "CONST (CODE)", // const_name - const data (code or not)
+ "CABS (ABS,CODE)", // cabs_name - const absolute data (code or not)
+ "XABS (ABS,XDATA)", // xabs_name - absolute xdata/pdata
+ "IABS (ABS,DATA)", // iabs_name - absolute idata/data
+ NULL, // name of segment for initialized variables
+ NULL, // name of segment for copies of initialized variables in code space
+ NULL,
+ NULL,
+ 1,
+ 1 // No fancy alignments supported.
+ },
+ { _mcs51_genExtraAreas, NULL },
+ {
+ +1, /* direction (+1 = stack grows up) */
+ 0, /* bank_overhead (switch between register banks) */
+ 4, /* isr_overhead */
+ 1, /* call_overhead (2 for return address - 1 for pre-incrementing push */
+ 1, /* reent_overhead */
+ 1, /* banked_overhead (switch between code banks) */
+ 0 /* sp points directly at last item pushed */
+ },
+ { -1, FALSE },
+ { mcs51_emitDebuggerSymbol },
+ {
+ 256, /* maxCount */
+ 2, /* sizeofElement */
+ {6,9,15}, /* sizeofMatchJump[] */
+ {9,18,36}, /* sizeofRangeCompare[] */
+ 4, /* sizeofSubtract */
+ 6, /* sizeofDispatch */
+ },
+ "_",
+ _mcs51_init,
+ _mcs51_parseOptions,
+ _mcs51_options,
+ NULL,
+ _mcs51_finaliseOptions,
+ _mcs51_setDefaultOptions,
+ mcs51_assignRegisters,
+ _mcs51_getRegName,
+ 0,
+ _mcs51_rtrackUpdate,
+ _mcs51_keywords,
+ _mcs51_genAssemblerPreamble,
+ NULL, /* no genAssemblerEnd */
+ _mcs51_genIVT,
+ _mcs51_genXINIT,
+ _mcs51_genInitStartup,
+ _mcs51_reset_regparm,
+ _mcs51_regparm,
+ NULL, /* process_pragma */
+ NULL, /* getMangledFunctionName */
+ _hasNativeMulFor, /* hasNativeMulFor */
+ hasExtBitOp, /* hasExtBitOp */
+ oclsExpense, /* oclsExpense */
+ FALSE, /* use_dw_for_init */
+ TRUE, /* little_endian */
+ 0, /* leave lt */
+ 0, /* leave gt */
+ 1, /* transform <= to ! > */
+ 1, /* transform >= to ! < */
+ 1, /* transform != to !(a == b) */
+ 0, /* leave == */
+ FALSE, /* No array initializer support. */
+ cseCostEstimation,
+ NULL, /* no builtin functions */
+ GPOINTER, /* treat unqualified pointers as "generic" pointers */
+ 1, /* reset labelKey to 1 */
+ 1, /* globals & local statics allowed */
+ 0, /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */
+ PORT_MAGIC
+};
diff --git a/src/mcs51/main.h b/src/mcs51/main.h
new file mode 100644
index 0000000..e34fc20
--- /dev/null
+++ b/src/mcs51/main.h
@@ -0,0 +1,45 @@
+/*-------------------------------------------------------------------------
+ main.c - mcs51 specific general header file
+
+ Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
+ Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com
+ Copyright (C) 2000, Michael Hope
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-------------------------------------------------------------------*/
+
+#ifndef MAIN_INCLUDE
+#define MAIN_INCLUDE
+
+#include "SDCCgen.h"
+
+typedef struct asmLineNode
+ {
+#ifdef UNNAMED_STRUCT_TAG
+ struct asmLineNodeBase;
+#else
+ /* exactly the same members as of struct asmLineNodeBase from SDCCgen.h */
+ int size;
+ bitVect *regsRead;
+ bitVect *regsWritten;
+#endif
+ }
+asmLineNode;
+
+bool x_parseOptions (char **argv, int *pargc);
+void x_setDefaultOptions (void);
+void x_finaliseOptions (void);
+
+#endif
diff --git a/src/mcs51/mcs51.vcxproj b/src/mcs51/mcs51.vcxproj
new file mode 100644
index 0000000..fa9833a
--- /dev/null
+++ b/src/mcs51/mcs51.vcxproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9FACDB81-BE66-42D0-95F5-EA2FA3B09065}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">port</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">port</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\Release/mcs51.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release/mcs51.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/mcs51.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/mcs51.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="gen.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="peep.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="rtrack.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="gen.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="peep.h" />
+ <ClInclude Include="ralloc.h" />
+ <ClInclude Include="..\..\sdcc_vc.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\config.vcxproj">
+ <Project>{2f87ba6f-8ee1-48d0-9817-6ba30bddb3c1}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) &gt;peeph.rul</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) &gt;peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ </CustomBuild>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/mcs51/mcs51.vcxproj.filters b/src/mcs51/mcs51.vcxproj.filters
new file mode 100644
index 0000000..aa1f754
--- /dev/null
+++ b/src/mcs51/mcs51.vcxproj.filters
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{bf0fcc72-c97b-453e-9ddb-0df03c205510}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{11a5d289-5894-4486-bee0-4d6dce084246}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Custom Build">
+ <UniqueIdentifier>{fa0a3371-90ba-4525-8964-2e8712494a31}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="gen.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="peep.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rtrack.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="gen.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="peep.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ralloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\sdcc_vc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Filter>Custom Build</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/mcs51/peep.c b/src/mcs51/peep.c
new file mode 100644
index 0000000..0a8db59
--- /dev/null
+++ b/src/mcs51/peep.c
@@ -0,0 +1,773 @@
+/*-------------------------------------------------------------------------
+ peep.c - source file for peephole optimizer helper functions
+
+ Written By - Bernhard Held
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include <ctype.h>
+#include "common.h"
+#include "ralloc.h"
+#include "gen.h"
+
+#define D(x) x
+#define DEADMOVEERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in deadmove");} while(0)
+
+typedef enum
+{
+ S4O_FOUNDOPCODE,
+ S4O_PUSHPOP,
+ S4O_CONDJMP,
+ S4O_WR_OP,
+ S4O_RD_OP,
+ S4O_TERM,
+ S4O_VISITED,
+ S4O_ABORT,
+ S4O_CONTINUE
+} S4O_RET;
+
+static struct
+{
+ lineNode *head;
+} _G;
+
+/*-----------------------------------------------------------------*/
+/* univisitLines - clear "visited" flag in all lines */
+/*-----------------------------------------------------------------*/
+static void
+unvisitLines (lineNode *pl)
+{
+ for (; pl; pl = pl->next)
+ pl->visited = FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* cleanLabelRef - clear label jump-counter and pass-flag */
+/*-----------------------------------------------------------------*/
+static void
+cleanLabelRef (void)
+{
+ int key;
+ labelHashEntry *entry;
+
+ if (!labelHash)
+ return;
+ for (entry = (labelHashEntry *) hTabFirstItem (labelHash, &key);
+ entry;
+ entry = (labelHashEntry *) hTabNextItem (labelHash, &key))
+ {
+ entry->passedLabel = FALSE;
+ entry->jmpToCount = 0;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* checkLabelRef - check all entries in labelHash */
+/* The path from 'pop' to 'push' must be the only possible path. */
+/* There must not be any paths in or out of this path. */
+/* This is checked by counting the label references. */
+/*-----------------------------------------------------------------*/
+static bool
+checkLabelRef (void)
+{
+ int key;
+ labelHashEntry *entry;
+
+ if (!labelHash)
+ {
+ /* no labels at all: no problems ;-) */
+ return TRUE;
+ }
+
+ for (entry = (labelHashEntry *) hTabFirstItem (labelHash, &key);
+ entry;
+ entry = (labelHashEntry *) hTabNextItem (labelHash, &key))
+ {
+
+ /* In our path we passed a label,
+ but we didn't meet all references (jumps) to this label.
+ This means that the code jumps from outside into this path. */
+ if (entry->passedLabel &&
+ entry->jmpToCount != entry->refCount)
+ {
+ return FALSE;
+ }
+
+ /* In our path we jumped to (referenced) a label,
+ but we we didn't pass it.
+ This means that there's a code path into our path. */
+ if (!entry->passedLabel &&
+ entry->jmpToCount != 0)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* setLabelRefPassedLabel - set flag "passedLabel" in entry */
+/* of the list labelHash */
+/*-----------------------------------------------------------------*/
+static bool
+setLabelRefPassedLabel (const char *label)
+{
+ labelHashEntry *entry;
+
+ entry = getLabelRef (label, _G.head);
+ if (!entry)
+ return FALSE;
+ entry->passedLabel = TRUE;
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* incLabelJmpToCount - increment counter "jmpToCount" in entry */
+/* of the list labelHash */
+/*-----------------------------------------------------------------*/
+static bool
+incLabelJmpToCount (const char *label)
+{
+ labelHashEntry *entry;
+
+ entry = getLabelRef (label, _G.head);
+ if (!entry)
+ return FALSE;
+ entry->jmpToCount++;
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* findLabel - */
+/* 1. extracts label in the opcode pl */
+/* 2. increment "label jump-to count" in labelHash */
+/* 3. search lineNode with label definition and return it */
+/*-----------------------------------------------------------------*/
+static lineNode *
+findLabel (const lineNode *pl)
+{
+ char *p;
+ lineNode *cpl;
+
+ /* 1. extract label in opcode */
+
+ /* In each mcs51 jumping opcode the label is at the end of the opcode */
+ p = strlen (pl->line) - 1 + pl->line;
+
+ /* scan backward until ',' or '\t' */
+ for (; p > pl->line; p--)
+ if (*p == ',' || *p == '\t')
+ break;
+
+ /* sanity check */
+ if (p == pl->line)
+ {
+ DEADMOVEERROR();
+ return NULL;
+ }
+
+ /* skip ',' resp. '\t' */
+ ++p;
+
+ /* 2. increment "label jump-to count" */
+ if (!incLabelJmpToCount (p))
+ return NULL;
+
+ /* 3. search lineNode with label definition and return it */
+ for (cpl = _G.head; cpl; cpl = cpl->next)
+ {
+ if (cpl->isLabel
+ && strncmp (p, cpl->line, strlen(p)) == 0)
+ {
+ return cpl;
+ }
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* isFunc - returns TRUE if it's a CALL or PCALL (not _gptrget()) */
+/*-----------------------------------------------------------------*/
+static bool
+isFunc (const lineNode *pl)
+{
+ if (pl && pl->ic)
+ {
+ if ( pl->ic->op == CALL
+ || pl->ic->op == PCALL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* termScanAtFunc - returns S4O_TERM if it's a 'normal' function */
+/* call and it's a 'caller save'. returns S4O_CONTINUE if it's */
+/* 'callee save' or 'naked'. returns S4O_ABORT if it's 'banked' */
+/* and uses the register for the destination. */
+/*-----------------------------------------------------------------*/
+static S4O_RET
+termScanAtFunc (const lineNode *pl, int rIdx)
+{
+ sym_link *ftype;
+ bool banked_reg = (rIdx == R0_IDX) || (rIdx == R1_IDX) || (rIdx == R2_IDX);
+
+ if (!isFunc (pl))
+ return S4O_CONTINUE;
+ // let's assume calls to literally given locations use the default
+ // most notably : (*(void (*)()) 0) (); see bug 1749275
+ if (IS_VALOP (IC_LEFT (pl->ic)))
+ return (options.model == MODEL_HUGE) && banked_reg ? S4O_ABORT : options.all_callee_saves ? S4O_CONTINUE : S4O_TERM;
+ ftype = OP_SYM_TYPE(IC_LEFT(pl->ic));
+ if (IS_FUNCPTR (ftype))
+ ftype = ftype->next;
+ if (IFFUNC_ISBANKEDCALL(ftype) && banked_reg)
+ return S4O_ABORT;
+ if (FUNC_ARGS (ftype) && getSize (FUNC_ARGS (ftype)->type) > 4)
+ return S4O_ABORT;
+ if (FUNC_CALLEESAVES(ftype))
+ return S4O_CONTINUE;
+ if (FUNC_ISNAKED(ftype))
+ return S4O_CONTINUE;
+ return S4O_TERM;
+}
+
+/*-----------------------------------------------------------------*/
+/* scan4op - "executes" and examines the assembler opcodes, */
+/* follows conditional and un-conditional jumps. */
+/* Moreover it registers all passed labels. */
+/* */
+/* Parameter: */
+/* lineNode **pl */
+/* scanning starts from pl; */
+/* pl also returns the last scanned line */
+/* const char *pReg */
+/* points to a register (e.g. "ar0"). scan4op() tests for */
+/* read or write operations with this register */
+/* const char *untilOp */
+/* points to NULL or an opcode (e.g. "push"). */
+/* scan4op() returns if it hits this opcode. */
+/* lineNode **plCond */
+/* If a conditional branch is met plCond points to the */
+/* lineNode of the conditional branch */
+/* */
+/* Returns: */
+/* S4O_ABORT */
+/* on error */
+/* S4O_VISITED */
+/* hit lineNode with "visited" flag set: scan4op() already */
+/* scanned this opcode. */
+/* S4O_FOUNDOPCODE */
+/* found opcode and operand, to which untilOp and pReg are */
+/* pointing to. */
+/* S4O_RD_OP, S4O_WR_OP */
+/* hit an opcode reading or writing from pReg */
+/* S4O_PUSHPOP */
+/* hit a "push" or "pop" opcode */
+/* S4O_CONDJMP */
+/* hit a conditional jump opcode. pl and plCond return the */
+/* two possible branches. */
+/* S4O_TERM */
+/* acall, lcall, ret and reti "terminate" a scan. */
+/*-----------------------------------------------------------------*/
+static S4O_RET
+scan4op (lineNode **pl, const char *pReg, const char *untilOp,
+ lineNode **plCond)
+{
+ char *p;
+ int len;
+ bool isConditionalJump;
+ int rIdx;
+ S4O_RET ret;
+ bool findPushPop;
+
+ findPushPop = untilOp && (strcmp (untilOp, "push") == 0 || strcmp (untilOp, "pop") == 0);
+
+ /* pReg points to e.g. "ar0"..."ar7" */
+ len = strlen (pReg);
+
+ /* get index into pReg table */
+ for (rIdx = 0; rIdx < mcs51_nRegs; ++rIdx)
+ if (strcmp (regs8051[rIdx].name, pReg + 1) == 0)
+ break;
+
+ /* sanity check */
+ if (rIdx >= mcs51_nRegs)
+ {
+ DEADMOVEERROR();
+ return S4O_ABORT;
+ }
+
+ for (; *pl; *pl = (*pl)->next)
+ {
+ if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment)
+ continue;
+
+ /* don't optimize across inline assembler,
+ e.g. isLabel doesn't work there */
+ if ((*pl)->isInline)
+ return S4O_ABORT;
+
+ if ((*pl)->visited)
+ return S4O_VISITED;
+ (*pl)->visited = TRUE;
+
+ /* found untilOp? */
+ if (untilOp && strncmp ((*pl)->line, untilOp, strlen (untilOp)) == 0)
+ {
+ p = (*pl)->line + strlen (untilOp);
+ if (*p == '\t' && strncmp (p + 1, pReg, len) == 0)
+ return S4O_FOUNDOPCODE;
+ else
+ {
+ /* found untilOp but without our pReg */
+ return S4O_ABORT;
+ }
+ }
+
+ /* found pReg? */
+ p = strchr ((*pl)->line, '\t');
+ if (p)
+ {
+ /* skip '\t' */
+ p++;
+
+ /* when looking for push or pop and we find a direct access of sp: abort */
+ if (findPushPop && strstr (p, "sp"))
+ return S4O_ABORT;
+
+ /* course search */
+ if (strstr (p, pReg + 1))
+ {
+ /* ok, let's have a closer look */
+
+ /* does opcode read from pReg? */
+ if (bitVectBitValue (port->peep.getRegsRead ((*pl)), rIdx))
+ return S4O_RD_OP;
+ /* does opcode write to pReg? */
+ if (bitVectBitValue (port->peep.getRegsWritten ((*pl)), rIdx))
+ return S4O_WR_OP;
+
+ /* we can get here, if the register name is
+ part of a variable name: ignore it */
+ }
+ }
+
+ /* found label? */
+ if ((*pl)->isLabel)
+ {
+ const char *start;
+ char label[SDCC_NAME_MAX + 1];
+ int len;
+
+ if (!isLabelDefinition ((*pl)->line, &start, &len, FALSE))
+ return S4O_ABORT;
+ memcpy (label, start, len);
+ label[len] = '\0';
+ /* register passing this label */
+ if (!setLabelRefPassedLabel (label))
+ {
+ DEADMOVEERROR();
+ return S4O_ABORT;
+ }
+ continue;
+ }
+
+ /* branch or terminate? */
+ isConditionalJump = FALSE;
+ switch ((*pl)->line[0])
+ {
+ case 'a':
+ if (strncmp ("acall", (*pl)->line, 5) == 0)
+ {
+ /* for comments see 'lcall' */
+ ret = termScanAtFunc (*pl, rIdx);
+ if (ret != S4O_CONTINUE)
+ return ret;
+ break;
+ }
+ if (strncmp ("ajmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ case 'c':
+ if (strncmp ("cjne", (*pl)->line, 4) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'd':
+ if (strncmp ("djnz", (*pl)->line, 4) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'j':
+ if (strncmp ("jmp", (*pl)->line, 3) == 0)
+ /* "jmp @a+dptr": no chance to trace execution */
+ return S4O_ABORT;
+ if (strncmp ("jc", (*pl)->line, 2) == 0 ||
+ strncmp ("jnc", (*pl)->line, 3) == 0 ||
+ strncmp ("jz", (*pl)->line, 2) == 0 ||
+ strncmp ("jnz", (*pl)->line, 3) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ if (strncmp ("jbc", (*pl)->line, 3) == 0 ||
+ strncmp ("jb", (*pl)->line, 2) == 0 ||
+ strncmp ("jnb", (*pl)->line, 3) == 0)
+ {
+ isConditionalJump = TRUE;
+ break;
+ }
+ break;
+ case 'l':
+ if (strncmp ("lcall", (*pl)->line, 5) == 0)
+ {
+ const char *p = (*pl)->line+5;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ while (isdigit (*p))
+ p++;
+ if (isdigit(p[-1]) && *p == '$') /* at least one digit */
+ {
+ /* this is a temp label for a pcall */
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ break;
+ }
+
+ ret = termScanAtFunc (*pl, rIdx);
+ /* If it's a 'normal' 'caller save' function call, all
+ registers have been saved until the 'lcall'. The
+ 'life range' of all registers end at the lcall,
+ and we can terminate our search.
+ * If the function is 'banked', the registers r0, r1 and r2
+ are used to tell the trampoline the destination. After
+ that their 'life range' ends just like the other registers.
+ * If it's a 'callee save' function call, registers are saved
+ by the callee. We've got no information, if the register
+ might live beyond the lcall. Therefore we've to continue
+ the search.
+ */
+ if (ret != S4O_CONTINUE)
+ return ret;
+ break;
+ }
+ if (strncmp ("ljmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ case 'p':
+ if (strncmp ("pop", (*pl)->line, 3) == 0 ||
+ strncmp ("push", (*pl)->line, 4) == 0)
+ return S4O_PUSHPOP;
+ break;
+ case 'r':
+ if (strncmp ("reti", (*pl)->line, 4) == 0)
+ return S4O_TERM;
+
+ if (strncmp ("ret", (*pl)->line, 3) == 0)
+ {
+ /* pcall uses 'ret' */
+ if (isFunc (*pl))
+ {
+ /* for comments see 'lcall' */
+ ret = termScanAtFunc (*pl, rIdx);
+ if (ret != S4O_CONTINUE)
+ return ret;
+ break;
+ }
+
+ /* it's a normal function return */
+ if (!((*pl)->ic))
+ return S4O_ABORT; /* but no ic? */
+ if (!currFunc->type)
+ return S4O_ABORT; /* not a function? */
+ if (FUNC_CALLEESAVES (currFunc->type))
+ return S4O_ABORT; /* returning from callee saves function */
+ if (getSize(currFunc->etype) > 4)
+ {
+ for (unsigned i = 0; i < getSize(currFunc->etype); i++)
+ if (strstr (pReg, fReturn8051[i]))
+ return S4O_ABORT; /* return value is partially in r4-r7 */
+ }
+ return S4O_TERM;
+ }
+ break;
+ case 's':
+ if (strncmp ("sjmp", (*pl)->line, 4) == 0)
+ {
+ *pl = findLabel (*pl);
+ if (!*pl)
+ return S4O_ABORT;
+ }
+ break;
+ default:
+ break;
+ } /* switch ((*pl)->line[0]) */
+
+ if (isConditionalJump)
+ {
+ *plCond = findLabel (*pl);
+ if (!*plCond)
+ return S4O_ABORT;
+ return S4O_CONDJMP;
+ }
+ } /* for (; *pl; *pl = (*pl)->next) */
+ return S4O_ABORT;
+}
+
+/*-----------------------------------------------------------------*/
+/* doPushScan - scan through area 1. This small wrapper handles: */
+/* - action required on different return values */
+/* - recursion in case of conditional branches */
+/*-----------------------------------------------------------------*/
+static bool
+doPushScan (lineNode **pl, const char *pReg)
+{
+ lineNode *plConditional, *pushPl = NULL;
+
+ for (;; *pl = (*pl)->next)
+ {
+ switch (scan4op (pl, pReg, "push", &plConditional))
+ {
+ case S4O_FOUNDOPCODE:
+ /* this is what we're looking for */
+ return TRUE;
+ case S4O_VISITED:
+#if 0
+ if (!pushPl)
+ {
+ DEADMOVEERROR();
+ return FALSE;
+ }
+ *pl = pushPl;
+ /* already checked */
+ return TRUE;
+#else
+ return FALSE;
+#endif
+ case S4O_CONDJMP:
+#if 0
+ /* two possible destinations: recurse */
+ {
+ lineNode *pushPl2 = plConditional;
+
+ if (!doPushScan (&pushPl2, pReg))
+ return FALSE;
+ pushPl = pushPl2;
+ }
+ continue;
+#else
+ /* two possible destinations: give up */
+ return FALSE;
+#endif
+ default:
+ return FALSE;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* doTermScan - scan through area 2. This small wrapper handles: */
+/* - action required on different return values */
+/* - recursion in case of conditional branches */
+/*-----------------------------------------------------------------*/
+static bool
+doTermScan (lineNode **pl, const char *pReg)
+{
+ lineNode *plConditional;
+
+ for (;; *pl = (*pl)->next)
+ {
+ switch (scan4op (pl, pReg, NULL, &plConditional))
+ {
+ case S4O_TERM:
+ case S4O_VISITED:
+ case S4O_WR_OP:
+ /* all these are terminating conditions */
+ return TRUE;
+ case S4O_PUSHPOP:
+ /* don't care, go on */
+ continue;
+ case S4O_CONDJMP:
+ /* two possible destinations: recurse */
+ {
+ lineNode *pl2 = plConditional;
+
+ if (!doTermScan (&pl2, pReg))
+ return FALSE;
+ }
+ continue;
+ case S4O_RD_OP:
+ default:
+ /* no go */
+ return FALSE;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* removeDeadPopPush - remove pop/push pair if possible */
+/*-----------------------------------------------------------------*/
+static bool
+removeDeadPopPush (const char *pReg, lineNode *currPl, lineNode *head)
+{
+ lineNode *pushPl, *pl;
+
+ /* A pop/push pair can be removed, if these criteria are met
+ (ar0 is just an example here, ar0...ar7 are possible):
+
+ pop ar0
+
+ ; area 1
+
+ ; There must not be in area 1:
+ ; - read or write access of ar0
+ ; - "acall", "lcall", "pop", "ret", "reti" or "jmp @a+dptr" opcodes
+ ; - "push" opcode, which doesn't push ar0
+ ; - inline assembly
+ ; - a jump in or out of area 1 (see checkLabelRef())
+
+ ; area 1 must be terminated by a:
+ push ar0
+
+ ; area 2
+
+ ; There must not be:
+ ; - read access of ar0
+ ; - "jmp @a+dptr" opcode
+ ; - inline assembly
+ ; - a jump in or out of area 2 (see checkLabelRef())
+
+ ; An "acall", "lcall" (not callee save), "ret" (not PCALL with
+ ; callee save), "reti" or write access of r0 terminate
+ ; the search, and the "pop/push ar0" can safely be removed.
+ */
+
+ /* area 1 */
+ pushPl = currPl->next;
+ if (!doPushScan (&pushPl, pReg))
+ return FALSE;
+
+ if (!checkLabelRef())
+ return FALSE;
+
+ /* area 2 */
+ pl = pushPl->next;
+ if (!doTermScan (&pl, pReg))
+ return FALSE;
+ if (!checkLabelRef())
+ return FALSE;
+
+ /* Success! */
+ if (options.noPeepComments)
+ {
+ /* remove pushPl from list */
+ pushPl->prev->next = pushPl->next;
+ pushPl->next->prev = pushPl->prev;
+ }
+ else
+ {
+ /* replace 'push ar0' by comment */
+ #define STR ";\tPeephole\tpush %s removed"
+ int size = sizeof(STR) + 2;
+
+ pushPl->line = Safe_alloc (size);
+ SNPRINTF (pushPl->line, size, STR, pReg);
+ pushPl->isComment = TRUE;
+ }
+
+ /* 'pop ar0' will be removed by peephole framework after returning TRUE */
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* removeDeadMove - remove superflous 'mov r%1,%2' */
+/*-----------------------------------------------------------------*/
+static bool
+removeDeadMove (const char *pReg, lineNode *currPl)
+{
+ lineNode *pl;
+
+ /* "mov r0,a" can be removed, if these criteria are met
+ (r0 is just an example here, r0...r7 are possible):
+
+ ; There must not be:
+ ; - read access of r0
+ ; - "jmp @a+dptr" opcode
+ ; - inline assembly
+ ; - a jump in or out of this area (see checkLabelRef())
+
+ ; An "acall", "lcall" (not callee save), "ret" (not PCALL with
+ ; callee save), "reti" or write access of r0 terminate
+ ; the search, and the "mov r0,a" can safely be removed.
+ */
+ pl = currPl->next;
+ if (!doTermScan (&pl, pReg))
+ return FALSE;
+
+ if (!checkLabelRef())
+ return FALSE;
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* mcs51DeadMove - dispatch condition deadmove between */
+/* - remove pop/push */
+/* - remove mov r%1,%2 */
+/*-----------------------------------------------------------------*/
+bool
+mcs51DeadMove (const char *reg, lineNode *currPl, lineNode *head)
+{
+ char pReg[5] = "ar";
+
+ _G.head = head;
+ strcat (pReg, reg);
+
+ unvisitLines (_G.head);
+ cleanLabelRef();
+
+ if (strncmp (currPl->line, "pop", 3) == 0)
+ return removeDeadPopPush (pReg, currPl, head);
+ else if ( strncmp (currPl->line, "mov", 3) == 0
+ && (currPl->line[3] == ' ' || currPl->line[3] == '\t'))
+ return removeDeadMove (pReg, currPl);
+ else
+ {
+ fprintf (stderr, "Error: "
+ "peephole rule with condition deadMove "
+ "used with unknown opocde:\n"
+ "\t%s\n", currPl->line);
+ return FALSE;
+ }
+}
diff --git a/src/mcs51/peep.h b/src/mcs51/peep.h
new file mode 100644
index 0000000..fec1dd8
--- /dev/null
+++ b/src/mcs51/peep.h
@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------
+ peep.h - header file for peephole optimizer helper functions
+
+ Written By - Bernhard Held
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+bool mcs51DeadMove (const char *reg, lineNode *currPl, lineNode *head);
diff --git a/src/mcs51/peeph.def b/src/mcs51/peeph.def
new file mode 100644
index 0000000..67d46d0
--- /dev/null
+++ b/src/mcs51/peeph.def
@@ -0,0 +1,5092 @@
+// added by Jean Louis VERN for
+// his shift stuff
+replace {
+ xch a,%1
+ xch a,%1
+} by {
+ ; Peephole 2.a removed redundant xch xch
+}
+
+replace {
+// saving 2 byte
+ mov %1,#0x00
+ mov a,#0x00
+} by {
+ ; Peephole 3.a changed mov to clr
+ clr a
+ mov %1,a
+}
+
+replace restart {
+// saving 1 byte
+ mov %1,#0x00
+ clr a
+} by {
+ ; Peephole 3.b changed mov to clr
+ clr a
+ mov %1,a
+}
+
+replace restart {
+// saving 1 byte, loosing 1 cycle but maybe allowing peephole 3.b to start
+ mov %1,#0x00
+ mov %2,#0x00
+ mov a,%3
+} by {
+ ; Peephole 3.c changed mov to clr
+ clr a
+ mov %1,a
+ mov %2,a
+ mov a,%3
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ clr a
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ ; Peephole 3.d removed redundant clr
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ clr a
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ ; Peephole 3.e removed redundant clr
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ clr a
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ ; Peephole 3.f removed redundant clr
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ mov %5,a
+ clr a
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ mov %5,a
+ ; Peephole 3.g removed redundant clr
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,#0x00
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ ; Peephole 3.h changed mov %3,#0x00 to ...,a
+ mov %3,a
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,#0x00
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ ; Peephole 3.i changed mov %4,#0x00 to ...,a
+ mov %4,a
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ mov %5,#0x00
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ ; Peephole 3.j changed mov %5,#0x00 to ...,a
+ mov %5,a
+}
+
+replace {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ mov %5,a
+ mov %6,#0x00
+} by {
+ clr a
+ mov %1,a
+ mov %2,a
+ mov %3,a
+ mov %4,a
+ mov %5,a
+ ; Peephole 3.k changed mov %6,#0x00 to ...,a
+ mov %6,a
+}
+
+replace {
+ mov %1,a
+ mov dptr,#%2
+ mov a,%1
+ movx @dptr,a
+} by {
+ mov %1,a
+ mov dptr,#%2
+ ; Peephole 100 removed redundant mov
+ movx @dptr,a
+} if notVolatile %1
+
+// applies to f.e. lib/src/time.c (--model-large)
+replace {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+} by {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ ; Peephole 101.a removed redundant moves
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+} if notVolatile %1
+
+// applies to f.e. support/regression/tests/literalop.c (--model-large)
+replace {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+} by {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ ; Peephole 101.b removed redundant moves
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+} if notVolatile %1
+
+// applies to f.e. support/regression/tests/onebyte.c (--model-large)
+replace {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ mov a,%1
+ movx @dptr,a
+} by {
+ mov a,%1
+ movx @dptr,a
+ inc dptr
+ ; Peephole 101.c removed redundant mov
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov %1,%2
+ ljmp %3
+%4:
+ mov %1,%5
+%3:
+ mov dpl,%1
+%7:
+ mov sp,_bp
+ pop _bp
+} by {
+ ; Peephole 102 removed redundant mov to %1
+ mov dpl,%2
+ ljmp %3
+%4:
+ mov dpl,%5
+%3:
+%7:
+ mov sp,_bp
+ pop _bp
+} if notVolatile(%1), labelRefCount(%3 1)
+
+replace {
+ mov %1,%2
+ ljmp %3
+%4:
+ mov a%1,%5
+%3:
+ mov dpl,%1
+%7:
+ mov sp,_bp
+ pop _bp
+} by {
+ ; Peephole 103 removed redundant mov to %1
+ mov dpl,%2
+ ljmp %3
+%4:
+ mov dpl,%5
+%3:
+%7:
+ mov sp,_bp
+ pop _bp
+} if labelRefCount(%3 1)
+
+// Does not seem to be triggered anymore
+//replace {
+// mov a,_bp
+// clr c
+// add a,#0x01
+// mov r%1,a
+//} by {
+// ; Peephole 104 optimized increment (acc not set to r%1, flags undefined)
+// mov r%1,_bp
+// inc r%1
+//}
+
+replace {
+ mov %1,a
+ mov a,%1
+} by {
+ mov %1,a
+ ; Peephole 105.a removed redundant mov
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+} by {
+ mov dptr,#%1
+ movx @dptr,a
+ ; Peephole 105.b removed redundant movx
+} if notVolatile %1
+
+
+replace {
+ mov %1,a
+ clr c
+ mov a,%1
+} by {
+ mov %1,a
+ clr c
+ ; Peephole 106 removed redundant mov
+} if notVolatile %1
+
+replace {
+ ljmp %1
+%1:
+} by {
+ ; Peephole 107 removed redundant ljmp
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jc %1
+ ljmp %5
+%1:
+} by {
+ ; Peephole 108.a removed ljmp by inverse jump logic
+ jnc %5
+%1:
+} if labelInRange(%5), labelRefCountChange(%1 -1)
+
+replace {
+ jz %1
+ ljmp %5
+%1:
+} by {
+ ; Peephole 108.b removed ljmp by inverse jump logic
+ jnz %5
+%1:
+} if labelInRange(%5), labelRefCountChange(%1 -1)
+
+replace {
+ jnz %1
+ ljmp %5
+%1:
+} by {
+ ; Peephole 108.c removed ljmp by inverse jump logic
+ jz %5
+%1:
+} if labelInRange(%5), labelRefCountChange(%1 -1)
+
+replace {
+ jb %1,%2
+ ljmp %5
+%2:
+} by {
+ ; Peephole 108.d removed ljmp by inverse jump logic
+ jnb %1,%5
+%2:
+} if labelInRange(%5), labelRefCountChange(%2 -1)
+
+replace {
+ jnb %1,%2
+ ljmp %5
+%2:
+} by {
+ ; Peephole 108.e removed ljmp by inverse jump logic
+ jb %1,%5
+%2:
+} if labelInRange(%5), labelRefCountChange(%2 -1)
+
+replace {
+ ljmp %5
+%1:
+} by {
+ ; Peephole 112.b changed ljmp to sjmp
+ sjmp %5
+%1:
+} if labelInRange(%5)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cpl a
+%3:
+ rrc a
+ mov %4,c
+} by {
+ ; Peephole 113.a optimized misc sequence
+ clr %4
+ cjne %1,%2,%3
+ setb %4
+%3:
+} if labelRefCount %3 1
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cpl a
+%3:
+ rrc a
+ mov %4,c
+} by {
+ ; Peephole 113.b optimized misc sequence
+ clr %4
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ setb %4
+%3:
+} if labelRefCount %3 2
+
+// parameter passing for model-large and model-huge
+replace {
+ mov r%2,dph
+ mov a,dpl
+ mov dptr,#%1
+ movx @dptr,a
+ inc dptr
+ mov a,r%2
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ mov r%2,a
+ inc dptr
+ movx a,@dptr
+} by {
+ mov r%2,dph
+ mov a,dpl
+ mov dptr,#%1
+ movx @dptr,a
+ inc dptr
+ ; Peephole 114.a optimized 16-bit parameter passing
+ xch a,r%2
+ movx @dptr,a
+} if notVolatile(%1)
+
+replace {
+ mov r%2,dpl
+ mov r%3,dph
+ mov r%4,b
+ mov r%5,a
+ mov dptr,#%1
+ mov a,r%2
+ movx @dptr,a
+ inc dptr
+ mov a,r%3
+ movx @dptr,a
+ inc dptr
+ mov a,r%4
+ movx @dptr,a
+ inc dptr
+ mov a,r%5
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ mov r%2,a
+ inc dptr
+ movx a,@dptr
+ mov r%3,a
+ inc dptr
+ movx a,@dptr
+ mov r%4,a
+ inc dptr
+ movx a,@dptr
+ mov r%5,a
+} by {
+ mov r%2,dpl
+ mov r%3,dph
+ mov r%4,b
+ mov r%5,a
+ mov dptr,#%1
+ mov a,r%2
+ movx @dptr,a
+ inc dptr
+ mov a,r%3
+ movx @dptr,a
+ inc dptr
+ mov a,r%4
+ movx @dptr,a
+ inc dptr
+ mov a,r%5
+ movx @dptr,a
+; Peephole 114.b optimized 32-bit parameter passing
+} if notVolatile(%1)
+
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cpl a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.a jump optimization (acc not set)
+ cjne %1,%2,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 1
+
+replace {
+ mov %1,a
+ cjne %1,#0x00,%2
+ sjmp %3
+%2:
+} by {
+ mov %1,a
+ ; Peephole 115.b jump optimization
+ jz %3
+%2:
+} if labelRefCountChange(%2 -1)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cpl a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.c jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 2
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ cpl a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.d jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 3
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ cjne %13,%14,%3
+ cpl a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.e jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ cjne %13,%14,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 4
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ clr a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.f jump optimization (acc not set)
+ cjne %1,%2,%4
+%3:
+} if labelRefCount(%3 1), labelRefCountChange(%3 -1)
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ clr a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.g jump optimization (acc not set)
+ cjne %1,%2,%4
+ cjne %10,%11,%4
+%3:
+} if labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%4 1)
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ clr a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.h jump optimization (acc not set)
+ cjne %1,%2,%4
+ cjne %10,%11,%4
+ cjne %12,%13,%4
+%3:
+} if labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%4 2)
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ cjne %14,%15,%3
+ clr a
+%3:
+ jnz %4
+} by {
+ ; Peephole 115.i jump optimization (acc not set)
+ cjne %1,%2,%4
+ cjne %10,%11,%4
+ cjne %12,%13,%4
+ cjne %14,%15,%4
+%3:
+} if labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%4 3)
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ clr a
+%3:
+ jz %4
+} by {
+ ; Peephole 115.j jump optimization (acc not set)
+ cjne %1,%2,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 1
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ clr a
+%3:
+ jz %4
+} by {
+ ; Peephole 115.k jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 2
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ clr a
+%3:
+ jz %4
+} by {
+ ; Peephole 115.l jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 3
+
+replace {
+ mov a,#0x01
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ cjne %14,%15,%3
+ clr a
+%3:
+ jz %4
+} by {
+ ; Peephole 115.m jump optimization (acc not set)
+ cjne %1,%2,%3
+ cjne %10,%11,%3
+ cjne %12,%13,%3
+ cjne %14,%15,%3
+ sjmp %4
+%3:
+} if labelRefCount %3 4
+
+replace {
+ push psw
+ mov psw,%1
+ push _bp
+ mov _bp,%2
+%3:
+ mov %2,_bp
+ pop _bp
+ pop psw
+ ret
+} by {
+ ; Peephole 127 removed misc sequence
+ ret
+} if labelRefCount %3 0
+
+replace {
+ clr a
+ rlc a
+ jz %1
+} by {
+ ; Peephole 128 jump optimization
+ jnc %1
+}
+
+// applies to: bug-524691.c --model-large: while (uRight - uLeft > 1)
+replace {
+ clr a
+ rlc a
+ jnz %0
+} by {
+ ; Peephole 129.a jump optimization
+ jc %0
+}
+
+// applies to: _fsdiv.c --xstack: if (mant1 < mant2)
+replace {
+ clr a
+ rlc a
+ pop %1
+ jnz %0
+} by {
+ ; Peephole 129.b optimized condition
+ pop %1
+ jc %0
+} if notVolatile %1
+
+// applies to: time.c --xstack: while((days += (LEAP_YEAR(year) ? 366 : 365)) <= epoch)
+replace {
+ clr a
+ rlc a
+ pop %1
+ pop %2
+ jnz %0
+} by {
+ ; Peephole 129.c optimized condition
+ pop %1
+ pop %2
+ jc %0
+} if notVolatile %1 %2
+
+// applies to: _memmove.c --xstack: if (((int)src < (int)dst) && ((((int)src)+acount) > (int)dst))
+replace {
+ clr a
+ rlc a
+ pop %1
+ pop %2
+ pop %3
+ jnz %0
+} by {
+ ; Peephole 129.d optimized condition
+ pop %1
+ pop %2
+ pop %3
+ jc %0
+} if notVolatile %1 %2 %3
+
+replace {
+ mov r%1,@r%2
+} by {
+ ; Peephole 130 changed target address mode r%1 to ar%1
+ mov ar%1,@r%2
+}
+
+replace {
+ mov a,%1
+ subb a,#0x01
+ mov %2,a
+ mov %1,%2
+} by {
+ ; Peephole 131 optimized decrement (not caring for c)
+ dec %1
+ mov %2,%1
+}
+
+// ideally the optimizations of rules 132.x should be done in genCmpXX
+replace {
+ clr c
+ mov a,#%1
+ subb a,%2
+ mov %3,c
+} by {
+ ; Peephole 132.a optimized genCmpGt by inverse logic (acc differs)
+ mov a,%2
+ add a,#0xff - %1
+ mov %3,c
+} if operandsLiteral(%1)
+
+replace {
+ clr c
+ mov a,#%1
+ subb a,%2
+ jnc %5
+} by {
+ ; Peephole 132.b optimized genCmpGt by inverse logic (acc differs)
+ mov a,%2
+ add a,#0xff - %1
+ jnc %5
+} if operandsLiteral(%1)
+
+replace {
+ clr c
+ mov a,#%1
+ subb a,%2
+ jc %5
+} by {
+ ; Peephole 132.c optimized genCmpGt by inverse logic (acc differs)
+ mov a,%2
+ add a,#0xff - %1
+ jc %5
+} if operandsLiteral(%1)
+
+// disabled. See bug1734654.c
+//replace {
+// clr c
+// mov a,%1
+// subb a,#%2
+// mov %3,c
+//} by {
+// ; Peephole 132.d optimized genCmpGt by inverse logic
+// mov a,#0x100 - %2
+// add a,%1
+// mov %3,c
+//} if operandsNotRelated('0x00' %2), operandsLiteral(%2)
+
+replace {
+ clr c
+ mov a,%1
+ subb a,#%2
+ jnc %5
+} by {
+ ; Peephole 132.e optimized genCmpLt by inverse logic (carry differs)
+ mov a,#0x100 - %2
+ add a,%1
+ jc %5
+} if operandsNotRelated('0x00' %2), operandsLiteral(%2)
+
+replace {
+ clr c
+ mov a,%1
+ subb a,#%2
+ jc %5
+} by {
+ ; Peephole 132.f optimized genCmpLt by inverse logic (carry differs)
+ mov a,#0x100 - %2
+ add a,%1
+ jnc %5
+} if operandsNotRelated('0x00' %2), operandsLiteral(%2)
+
+
+replace {
+ mov r%1,%2
+ mov ar%3,@r%1
+ inc r%3
+ mov r%4,%2
+ mov @r%4,ar%3
+} by {
+ mov r%1,%2
+ ; Peephole 133 removed redundant moves
+ inc @r%1
+ mov ar%3,@r%1
+} if notVolatile
+
+replace {
+ mov r%1,%2
+ mov ar%3,@r%1
+ dec r%3
+ mov r%4,%2
+ mov @r%4,ar%3
+} by {
+ mov r%1,%2
+ ; Peephole 134 removed redundant moves
+ dec @r%1
+ mov ar%3,@r%1
+} if notVolatile
+
+replace {
+ mov r%1,a
+ mov a,r%2
+ orl a,r%1
+} by {
+ mov r%1,a
+ ; Peephole 135 removed redundant mov
+ orl a,r%2
+}
+
+replace {
+ mov %1,a
+ mov dpl,%2
+ mov dph,%3
+ mov a,%1
+} by {
+ mov %1,a
+ mov dpl,%2
+ mov dph,%3
+ ; Peephole 136 removed redundant mov
+} if notVolatile %1
+
+// WTF? Doesn't look sensible to me...
+//replace {
+// mov b,#0x00
+// mov a,%1
+// cjne %2,%3,%4
+// mov b,#0x01
+//%4:
+// mov a,b
+// jz %5
+//} by {
+// ; Peephole 137 optimized misc jump sequence
+// mov a,%1
+// cjne %2,%3,%5
+//%4:
+//} if labelRefCount %4 1
+//
+//replace {
+// mov b,#0x00
+// mov a,%1
+// cjne %2,%3,%4
+// mov b,#0x01
+//%4:
+// mov a,b
+// jnz %5
+//} by {
+// ; Peephole 138 optimized misc jump sequence
+// mov a,%1
+// cjne %2,%3,%4
+// sjmp %5
+//%4:
+//} if labelRefCount %4 1
+
+replace {
+ mov r%1,a
+ anl ar%1,%2
+ mov a,r%1
+} by {
+ ; Peephole 139.a removed redundant mov
+ anl a,%2
+ mov r%1,a
+}
+
+replace {
+ mov r%1,a
+ orl ar%1,%2
+ mov a,r%1
+} by {
+ ; Peephole 139.b removed redundant mov
+ orl a,%2
+ mov r%1,a
+}
+
+replace {
+ mov r%1,a
+ xrl ar%1,%2
+ mov a,r%1
+} by {
+ ; Peephole 139.c removed redundant mov
+ xrl a,%2
+ mov r%1,a
+}
+
+// applies to genlshOne
+replace {
+ mov ar%1,@%2
+ mov a,r%1
+ add a,acc
+ mov r%1,a
+} by {
+ ; Peephole 140 removed redundant mov
+ mov a,@%2
+ add a,@%2
+ mov r%1,a
+}
+
+replace {
+ mov r%1,a
+ mov r%2,ar%1
+ mov ar%1,@r%2
+} by {
+ ; Peephole 142 removed redundant mov
+ mov r%2,a
+ mov ar%1,@r%2
+}
+
+replace {
+ rlc a
+ mov acc.0,c
+} by {
+ ; Peephole 143.a converted rlc to rl
+ rl a
+}
+
+replace {
+ rrc a
+ mov acc.7,c
+} by {
+ ; Peephole 143.b converted rrc to rc
+ rr a
+}
+
+replace {
+ clr c
+ addc a,%1
+} by {
+ ; Peephole 145.a changed to add without carry
+ add a,%1
+}
+
+replace {
+ clr c
+ mov a,%1
+ addc a,%2
+} by {
+ ; Peephole 145.b changed to add without carry
+ mov a,%1
+ add a,%2
+}
+
+// 147: Fix compiler output to comply with 8051 instruction set.
+replace {
+ orl r%1,a
+} by {
+ ; Peephole 147.a changed target address mode r%1 to ar%1
+ orl ar%1,a
+}
+
+replace {
+ anl r%1,a
+} by {
+ ; Peephole 147.b changed target address mode r%1 to ar%1
+ anl ar%1,a
+}
+
+replace {
+ xrl r%1,a
+} by {
+ ; Peephole 147.c changed target address mode r%1 to ar%1
+ xrl ar%1,a
+}
+
+replace {
+ mov r%1,dpl
+ mov dpl,r%1
+%9:
+ ret
+} by {
+ ; Peephole 150.a removed misc moves via dpl before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov dpl,r%1
+ mov dph,r%2
+%9:
+ ret
+} by {
+ ; Peephole 150.b removed misc moves via dph, dpl before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov dpl,r%1
+%9:
+ ret
+} by {
+ ; Peephole 150.c removed misc moves via dph, dpl before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov dpl,r%1
+ mov dph,r%2
+ mov b,r%3
+%9:
+ ret
+} by {
+ ; Peephole 150.d removed misc moves via dph, dpl, b before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov dpl,r%1
+%9:
+ ret
+} by {
+ ; Peephole 150.e removed misc moves via dph, dpl, b before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov dpl,r%1
+ mov dph,r%2
+%9:
+ ret
+} by {
+ ; Peephole 150.f removed misc moves via dph, dpl, b before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov r%4,a
+ mov dpl,r%1
+ mov dph,r%2
+ mov b,r%3
+ mov a,r%4
+%9:
+ ret
+} by {
+ ; Peephole 150.g removed misc moves via dph, dpl, b, a before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov r%4,a
+ mov dpl,r%1
+ mov dph,r%2
+%9:
+ ret
+} by {
+ ; Peephole 150.h removed misc moves via dph, dpl, b, a before return
+%9:
+ ret
+}
+
+replace {
+ mov r%1,dpl
+ mov r%2,dph
+ mov r%3,b
+ mov r%4,a
+ mov dpl,r%1
+%9:
+ ret
+} by {
+ ; Peephole 150.i removed misc moves via dph, dpl, b, a before return
+%9:
+ ret
+}
+
+// peephole 213.a might revert this
+replace {
+ mov %1,#%2
+ xrl %1,#0x80
+} by {
+ ; Peephole 159 avoided xrl during execution
+ mov %1,#(%2 ^ 0x80)
+}
+
+replace {
+ jnc %1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.a removed sjmp by inverse jump logic
+ jc %2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jc %1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.b removed sjmp by inverse jump logic
+ jnc %2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jnz %1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.c removed sjmp by inverse jump logic
+ jz %2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jz %1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.d removed sjmp by inverse jump logic
+ jnz %2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jnb %3,%1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.e removed sjmp by inverse jump logic
+ jb %3,%2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ jb %3,%1
+ sjmp %2
+%1:
+} by {
+ ; Peephole 160.f removed sjmp by inverse jump logic
+ jnb %3,%2
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ mov %1,%2
+ mov %3,%1
+ mov %2,%1
+} by {
+ mov %1,%2
+ mov %3,%1
+ ; Peephole 166 removed redundant mov
+} if notVolatile %1 %2
+
+replace {
+ mov c,%1
+ cpl c
+ mov %1,c
+} by {
+ ; Peephole 167 removed redundant bit moves (c not set to %1)
+ cpl %1
+}
+
+replace {
+ jnb %1,%2
+ sjmp %3
+%2:
+} by {
+ ; Peephole 168 jump optimization
+ jb %1,%3
+%2:
+} if labelRefCountChange(%2 -1)
+
+replace {
+ jb %1,%2
+ sjmp %3
+%2:
+} by {
+ ; Peephole 169 jump optimization
+ jnb %1,%3
+%2:
+} if labelRefCountChange(%2 -1)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cpl a
+%3:
+ jz %4
+} by {
+ ; Peephole 170 jump optimization
+ cjne %1,%2,%4
+%3:
+} if labelRefCount(%3 1), labelRefCountChange(%3 -1)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cpl a
+%3:
+ jz %4
+} by {
+ ; Peephole 171 jump optimization
+ cjne %1,%2,%4
+ cjne %9,%10,%4
+%3:
+} if labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%4 1)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ cpl a
+%3:
+ jz %4
+} by {
+ ; Peephole 172 jump optimization
+ cjne %1,%2,%4
+ cjne %9,%10,%4
+ cjne %11,%12,%4
+%3:
+} if labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%4 2)
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ cjne %9,%10,%3
+ cjne %11,%12,%3
+ cjne %13,%14,%3
+ cpl a
+%3:
+ jz %4
+} by {
+ ; Peephole 173 jump optimization
+ cjne %1,%2,%4
+ cjne %9,%10,%4
+ cjne %11,%12,%4
+ cjne %13,%14,%4
+%3:
+} if labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%4 3)
+
+replace {
+ mov r%1,%2
+ clr c
+ mov a,r%1
+ subb a,#0x01
+ mov %2,a
+} by {
+ mov r%1,%2
+ ; Peephole 174.a optimized decrement (acc not set to %2, flags undefined)
+ dec %2
+}
+
+replace {
+ mov r%1,%2
+ mov a,r%1
+ add a,#0x01
+ mov %2,a
+} by {
+ mov r%1,%2
+ ; Peephole 174.b optimized increment (acc not set to %2, flags undefined)
+ inc %2
+}
+
+replace {
+ mov %1,@r%2
+ inc %1
+ mov @r%2,%1
+} by {
+ ; Peephole 174.c optimized increment, removed redundant mov
+ inc @r%2
+ mov %1,@r%2
+} if notVolatile
+
+// this one will screw assignes to volatile/sfr's
+replace {
+ mov %1,%2
+ mov %2,%1
+} by {
+ mov %1,%2
+ ; Peephole 177.a removed redundant mov
+} if notVolatile %1 %2
+
+// applies to f.e. scott-add.asm (--model-large)
+replace {
+ mov r%1,a
+ mov a,ar%1
+} by {
+ mov r%1,a
+ ; Peephole 177.b removed redundant mov
+}
+
+// applies to f.e. bug-408972.c
+replace {
+ mov %1,%2
+ mov %1,%3
+} by {
+ ; Peephole 177.c removed redundant mov
+ mov %1,%3
+} if notVolatile(%1 %2),operandsNotRelated(%1 %3)
+
+// applies to f.e. bug-408972.c
+// not before peephole 177.c
+replace restart {
+ mov %1,%2
+ mov %3,%4
+ mov %2,%1
+} by {
+ mov %1,%2
+ mov %3,%4
+ ; Peephole 177.d removed redundant mov
+} if notVolatile(%1 %2),operandsNotRelated(%1 %2 %3)
+
+// applies to f.e. bug-607243.c
+replace {
+ mov %1,%2
+ mov a%1,%3
+} by {
+ ; peephole 177.e removed redundant mov %1,%2
+ mov a%1,%3
+} if notVolatile(%2), operandsNotRelated(%1 %3)
+
+replace {
+ mov ar%1,%2
+ mov r%1,%3
+} by {
+ ; peephole 177.f removed redundant mov
+ mov r%1,%3
+} if notVolatile %2
+
+replace {
+ mov %1,%2
+ mov a,%1
+} by {
+ ; peephole 177.g optimized mov sequence
+ mov a,%2
+ mov %1,a
+} if notVolatile %1
+
+replace {
+ mov %1,%2
+ mov a,%2
+} by {
+ ; peephole 177.h optimized mov sequence
+ mov a,%2
+ mov %1,a
+} if notVolatile(%2), notSame(%1 'dptr'), operandsNotRelated(%1 %2)
+
+// applies to f.e. testfwk.c
+replace {
+ mov r%1,a
+ mov ar%2,r%1
+} by {
+ mov r%1,a
+ ; peephole 177.i optimized mov sequence
+ mov r%2,a
+}
+
+replace {
+ mov r%1,%2
+ mov ar%3,r%1
+ mov r%1,%4
+} by {
+ ; peephole 177.j optimized mov sequence
+ mov r%3,%2
+ mov r%1,%4
+}
+
+replace {
+ mov a,%1
+ mov b,a
+ mov a,%2
+} by {
+ ; Peephole 178 removed redundant mov
+ mov b,%1
+ mov a,%2
+}
+
+// rules 179-182 provided by : Frieder <fe@lake.iup.uni-heidelberg.de>
+// saving 2 byte, 1 cycle
+replace {
+ mov b,#0x00
+ mov a,#0x00
+} by {
+ ; Peephole 179 changed mov to clr
+ clr a
+ mov b,a
+}
+
+// applies to:
+// volatile xdata char t; t=0x01; t=0x03;
+replace {
+ mov dptr,%1
+ mov a,%2
+ movx @dptr,a
+ mov dptr,%1
+} by {
+ mov dptr,%1
+ mov a,%2
+ movx @dptr,a
+ ; Peephole 180.a removed redundant mov to dptr
+}
+
+// volatile xdata char t; t=0x01; t=0x03; t=0x01;
+replace {
+ mov dptr,%1
+ mov a,%2
+ movx @dptr,a
+ mov a,%3
+ movx @dptr,a
+ mov dptr,%1
+} by {
+ mov dptr,%1
+ mov a,%2
+ movx @dptr,a
+ mov a,%3
+ movx @dptr,a
+ ; Peephole 180.b removed redundant mov to dptr
+}
+
+// saving 1 byte, 0 cycles
+replace {
+ mov a,#0x00
+} by {
+ ; Peephole 181 changed mov to clr
+ clr a
+}
+
+// saving 3 bytes, 2 cycles
+// provided by Bernhard Held <bernhard.held@de.westinghouse.com>
+replace {
+ mov dpl,#%1
+ mov dph,#(%1 >> 8)
+} by {
+ ; Peephole 182.a used 16 bit load of DPTR
+ mov dptr,#%1
+}
+
+// saving 3 byte, 2 cycles, return(NULL) profits here
+replace {
+ mov dpl,#0x%1
+ mov dph,#0x%2
+} by {
+ ; Peephole 182.b used 16 bit load of dptr
+ mov dptr,#0x%2%1
+}
+
+// saving 3 byte, 2 cycles. Probably obsoleted by 182.b
+replace {
+ mov dpl,#%1
+ mov dph,#%2
+} by {
+ ; Peephole 182.c used 16 bit load of dptr
+ mov dptr,#(((%2)<<8) + %1)
+}
+
+// applies to return 0.0; in f.e. sincosf.c
+replace {
+ mov dpl,#%1
+ clr a
+ mov dph,a
+} by {
+ ; Peephole 182.d used 16 bit load of dptr
+ mov dptr,#(%1&0x00ff)
+ clr a
+}
+
+replace {
+ anl %1,#%2
+ anl %1,#%3
+} by {
+ ; Peephole 183.a avoided anl during execution
+ anl %1,#(%2&%3)
+} if notVolatile %1
+
+replace {
+ orl %1,#%2
+ orl %1,#%3
+} by {
+ ; Peephole 183.b avoided orl during execution
+ orl %1,#(%2|%3)
+} if notVolatile %1
+
+replace {
+ mov %1,a
+ cpl a
+ mov %1,a
+} by {
+ ; Peephole 184 removed redundant mov
+ cpl a
+ mov %1,a
+} if notVolatile %1
+
+//replace {
+// acc being incremented might cause problems with register tracking
+// mov %1,a
+// inc %1
+//} by {
+// ; Peephole 185 changed order of increment (acc incremented also!)
+// inc a
+// mov %1,a
+//} if notVolatile %1
+
+// char indexed access to: long code table[] = {4,3,2,1};
+replace restart {
+ add a,#%1
+ mov dpl,a
+ clr a
+ addc a,#(%1 >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov %2,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+ mov %3,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+ mov %4,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+} by {
+ ; Peephole 186.a optimized movc sequence
+ mov b,a
+ mov dptr,#%1
+ movc a,@a+dptr
+ mov %2,a
+ inc dptr
+ mov a,b
+ movc a,@a+dptr
+ mov %3,a
+ inc dptr
+ mov a,b
+ movc a,@a+dptr
+ mov %4,a
+ inc dptr
+ mov a,b
+ movc a,@a+dptr
+}
+
+// char indexed access to: void* code table[] = {4,3,2,1};
+replace restart {
+ add a,#%1
+ mov dpl,a
+ clr a
+ addc a,#(%1 >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov %2,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+ mov %3,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+} by {
+ ; Peephole 186.b optimized movc sequence
+ mov b,a
+ mov dptr,#%1
+ movc a,@a+dptr
+ mov %2,a
+ inc dptr
+ mov a,b
+ movc a,@a+dptr
+ mov %3,a
+ inc dptr
+ mov a,b
+ movc a,@a+dptr
+}
+
+// char indexed access to: int code table[] = {4,3,2,1};
+replace restart {
+ add a,#%1
+ mov dpl,a
+ clr a
+ addc a,#(%1 >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov %2,a
+ inc dptr
+ clr a
+ movc a,@a+dptr
+} by {
+ ; Peephole 186.c optimized movc sequence
+ mov %2,a
+ mov dptr,#%1
+ movc a,@a+dptr
+ xch a,%2
+ inc dptr
+ movc a,@a+dptr
+}
+
+// char indexed access to: char code table[] = {4,3,2,1};
+replace {
+ add a,#%1
+ mov dpl,a
+ clr a
+ addc a,#(%1 >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+} by {
+ ; Peephole 186.d optimized movc sequence
+ mov dptr,#%1
+ movc a,@a+dptr
+}
+
+// char indexed access to: int code table[] = {4,3,2,1};
+replace {
+ mov b,#0x02
+ mul ab
+ add a,#%2
+ mov dpl,a
+ mov a,#(%2 >> 8)
+ addc a,b
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov %3,a
+ mov a,#0x01
+ movc a,@a+dptr
+} by {
+ ; Peephole 186.e optimized movc sequence (b, dptr differ)
+ add a,acc
+ mov b,a
+ mov dptr,#%2
+ jnc .+3
+ inc dph
+ movc a,@a+dptr
+ mov %3,a
+ mov a,b
+ inc a
+ movc a,@a+dptr
+}
+
+replace {
+ mov r%1,%2
+ anl ar%1,#%3
+ mov a,r%1
+} by {
+ ; Peephole 187 used a instead of ar%1 for anl
+ mov a,%2
+ anl a,#%3
+ mov r%1,a
+}
+
+replace {
+ mov %1,a
+ mov dptr,%2
+ movc a,@a+dptr
+ mov %1,a
+} by {
+ ; Peephole 188 removed redundant mov
+ mov dptr,%2
+ movc a,@a+dptr
+ mov %1,a
+} if notVolatile %1
+
+replace {
+ anl a,#0x0f
+ mov %1,a
+ mov a,#0x0f
+ anl a,%1
+} by {
+ anl a,#0x0f
+ mov %1,a
+ ; Peephole 189 removed redundant mov and anl
+} if notVolatile %1
+
+// rules 190 & 191 need to be in order
+replace {
+ mov a,%1
+ lcall __gptrput
+ mov a,%1
+} by {
+ mov a,%1
+ lcall __gptrput
+ ; Peephole 190 removed redundant mov
+} if notVolatile %1
+
+replace {
+ mov %1,a
+ mov dpl,%2
+ mov dph,%3
+ mov b,%4
+ mov a,%1
+} by {
+ mov %1,a
+ mov dpl,%2
+ mov dph,%3
+ mov b,%4
+ ; Peephole 191 removed redundant mov
+} if notVolatile %1
+
+// applies to f.e. regression/ports/mcs51/support.c
+replace {
+ mov r%1,a
+ mov @r%2,ar%1
+} by {
+ mov r%1,a
+ ; Peephole 192.a used a instead of ar%1 as source
+ mov @r%2,a
+}
+
+// applies to f.e. printf_large.c
+replace {
+ mov ar%1,@r%2
+ mov a,r%1
+} by {
+ ; Peephole 192.b used a instead of ar%1 as destination
+ mov a,@r%2
+ mov r%1,a
+}
+
+replace {
+ jnz %3
+ mov a,%4
+ jnz %3
+ mov a,%9
+ jnz %3
+ mov a,%12
+ cjne %13,%14,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 193.a optimized misc jump sequence
+ jnz %8
+ mov a,%4
+ jnz %8
+ mov a,%9
+ jnz %8
+ mov a,%12
+ cjne %13,%14,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%8 3)
+
+replace {
+ cjne %1,%2,%3
+ mov a,%4
+ cjne %5,%6,%3
+ mov a,%9
+ cjne %10,%11,%3
+ mov a,%12
+ cjne %13,%14,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 193.b optimized misc jump sequence
+ cjne %1,%2,%8
+ mov a,%4
+ cjne %5,%6,%8
+ mov a,%9
+ cjne %10,%11,%8
+ mov a,%12
+ cjne %13,%14,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%8 3)
+
+replace {
+ cjne @%1,%2,%3
+ inc %1
+ cjne @%1,%6,%3
+ inc %1
+ cjne @%1,%11,%3
+ inc %1
+ cjne @%1,%14,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 193.c optimized misc jump sequence
+ cjne @%1,%2,%8
+ inc %1
+ cjne @%1,%6,%8
+ inc %1
+ cjne @%1,%11,%8
+ inc %1
+ cjne @%1,%14,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%8 3)
+
+replace {
+ cjne %1,%2,%3
+ cjne %5,%6,%3
+ cjne %10,%11,%3
+ cjne %13,%14,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 194 optimized misc jump sequence
+ cjne %1,%2,%8
+ cjne %5,%6,%8
+ cjne %10,%11,%8
+ cjne %13,%14,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 4), labelRefCountChange(%3 -4), labelRefCountChange(%8 3)
+
+replace {
+ jnz %3
+ mov a,%4
+ jnz %3
+ mov a,%9
+ cjne %10,%11,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 195.a optimized misc jump sequence
+ jnz %8
+ mov a,%4
+ jnz %8
+ mov a,%9
+ cjne %10,%11,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%8 2)
+
+replace {
+ cjne %1,%2,%3
+ mov a,%4
+ cjne %5,%6,%3
+ mov a,%9
+ cjne %10,%11,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 195.b optimized misc jump sequence
+ cjne %1,%2,%8
+ mov a,%4
+ cjne %5,%6,%8
+ mov a,%9
+ cjne %10,%11,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%8 2)
+
+replace {
+ cjne @%1,%2,%3
+ inc %1
+ cjne @%1,%6,%3
+ inc %1
+ cjne @%1,%11,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 195.c optimized misc jump sequence
+ cjne @%1,%2,%8
+ inc %1
+ cjne @%1,%6,%8
+ inc %1
+ cjne @%1,%11,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%8 2)
+
+replace {
+ cjne %1,%2,%3
+ cjne %5,%6,%3
+ cjne %10,%11,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 196 optimized misc jump sequence
+ cjne %1,%2,%8
+ cjne %5,%6,%8
+ cjne %10,%11,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 3), labelRefCountChange(%3 -3), labelRefCountChange(%8 2)
+
+replace {
+ jnz %3
+ mov a,%4
+ cjne %5,%6,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 197.a optimized misc jump sequence
+ jnz %8
+ mov a,%4
+ cjne %5,%6,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%8 1)
+
+replace {
+ cjne %1,%2,%3
+ mov a,%4
+ cjne %5,%6,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 197.b optimized misc jump sequence
+ cjne %1,%2,%8
+ mov a,%4
+ cjne %5,%6,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%8 1)
+
+replace {
+ cjne @%1,%2,%3
+ inc %1
+ cjne @%1,%6,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 197.c optimized misc jump sequence
+ cjne @%1,%2,%8
+ inc %1
+ cjne @%1,%6,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%8 1)
+
+replace {
+ cjne %1,%2,%3
+ cjne %5,%6,%3
+ sjmp %7
+%3:
+ sjmp %8
+} by {
+ ; Peephole 198.a optimized misc jump sequence
+ cjne %1,%2,%8
+ cjne %5,%6,%8
+ sjmp %7
+%3:
+} if labelInRange(%8), labelRefCount(%3 2), labelRefCountChange(%3 -2), labelRefCountChange(%8 1)
+
+replace {
+ cjne %1,%2,%3
+ sjmp %4
+%3:
+ sjmp %5
+} by {
+ ; Peephole 198.b optimized misc jump sequence
+ cjne %1,%2,%5
+ sjmp %4
+%3:
+} if labelInRange(%5), labelRefCount(%3 1), labelRefCountChange(%3 -1)
+
+replace {
+ sjmp %1
+%1:
+} by {
+ ; Peephole 200.a removed redundant sjmp
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ sjmp %1
+%2:
+%1:
+} by {
+ ; Peephole 200.b removed redundant sjmp
+%2:
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace {
+ push acc
+ mov dptr,%1
+ pop acc
+} by {
+ ; Peephole 202 removed redundant push pop
+ mov dptr,%1
+}
+
+replace {
+ mov r%1,_spx
+ lcall %2
+ mov r%1,_spx
+} by {
+ ; Peephole 203 removed mov r%1,_spx
+ lcall %2
+}
+
+replace {
+ mov %1,a
+ add a,acc
+ mov %1,a
+} by {
+ ; Peephole 204 removed redundant mov
+ add a,acc
+ mov %1,a
+} if notVolatile %1
+
+replace {
+ djnz %1,%2
+ sjmp %3
+%2:
+ sjmp %4
+%3:
+} by {
+ ; Peephole 205 optimized misc jump sequence
+ djnz %1,%4
+%2:
+%3:
+} if labelRefCount(%2 1), labelRefCountChange(%2 -1), labelRefCountChange(%3 -1)
+
+replace {
+ mov %1,%1
+} by {
+ ; Peephole 206 removed redundant mov %1,%1
+} if notVolatile %1
+
+// Does not seem to be triggered anymore
+//replace {
+// mov a,_bp
+// add a,#0x00
+// mov %1,a
+//} by {
+// ; Peephole 207 removed zero add (acc not set to %1, flags undefined)
+// mov %1,_bp
+//}
+
+replace {
+ push acc
+ mov r%1,_bp
+ pop acc
+} by {
+ ; Peephole 208 removed redundant push pop
+ mov r%1,_bp
+}
+
+// Does not seem to be triggered anymore
+//replace {
+// mov a,_bp
+// add a,#0x00
+// inc a
+// mov %1,a
+//} by {
+// ; Peephole 209 optimized increment (acc not set to %1, flags undefined)
+// mov %1,_bp
+// inc %1
+//}
+
+replace {
+ mov dptr,#((((%1 >> 8)) <<8) + %1)
+} by {
+ ; Peephole 210 simplified expression
+ mov dptr,#%1
+}
+
+replace {
+ push %1
+ pop %1
+} by {
+ ; Peephole 211 removed redundant push %1 pop %1
+}
+
+// Does not seem to be triggered anymore
+//replace {
+// mov a,_bp
+// add a,#0x01
+// mov r%1,a
+//} by {
+// ; Peephole 212 reduced add sequence to inc
+// mov r%1,_bp
+// inc r%1
+//}
+
+// reverts peephole 159? asx8051 cannot handle, too complex?
+replace {
+ mov %1,#(( %2 >> 8 ) ^ 0x80)
+} by {
+ ; Peephole 213.a inserted fix
+ mov %1,#(%2 >> 8)
+ xrl %1,#0x80
+}
+
+replace {
+ mov %1,#(( %2 + %3 >> 8 ) ^ 0x80)
+} by {
+ ; Peephole 213.b inserted fix
+ mov %1,#((%2 + %3) >> 8)
+ xrl %1,#0x80
+}
+
+
+replace {
+ mov %1,a
+ mov a,%2
+ add a,%1
+} by {
+ mov %1,a
+ ; Peephole 214.a removed redundant mov
+ add a,%2
+} if notSame(%1 %2)
+
+replace {
+ mov %1,a
+ add a,%2
+ mov %1,a
+} by {
+ ; Peephole 214.b removed redundant mov
+ add a,%2
+ mov %1,a
+} if notSame(%1 %2)
+
+replace {
+ mov r%1,%2
+ clr a
+ inc r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+} by {
+ mov r%1,%2
+ clr a
+ ; Peephole 216.a simplified clear (2 bytes)
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+}
+
+replace {
+ mov r%1,%2
+ clr a
+ inc r%1
+ inc r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+} by {
+ mov r%1,%2
+ clr a
+ ; Peephole 216.b simplified clear (3 bytes)
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+}
+
+replace {
+ mov r%1,%2
+ clr a
+ inc r%1
+ inc r%1
+ inc r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+ dec r%1
+ mov @r%1,a
+} by {
+ mov r%1,%2
+ clr a
+ ; Peephole 216.c simplified clear (4 bytes)
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+ inc r%1
+ mov @r%1,a
+}
+
+replace {
+ clr a
+ movx @dptr,a
+ mov dptr,%1
+ clr a
+ movx @dptr,a
+} by {
+ ; Peephole 219.a removed redundant clear
+ clr a
+ movx @dptr,a
+ mov dptr,%1
+ movx @dptr,a
+}
+
+replace {
+ clr a
+ movx @dptr,a
+ mov dptr,%1
+ movx @dptr,a
+ mov dptr,%2
+ clr a
+ movx @dptr,a
+} by {
+ clr a
+ movx @dptr,a
+ mov dptr,%1
+ movx @dptr,a
+ mov dptr,%2
+ ; Peephole 219.b removed redundant clear
+ movx @dptr,a
+}
+
+replace {
+ mov dps,#0x00
+ mov dps,#0x01
+} by {
+ ; Peephole 220.a removed bogus DPS set
+ mov dps,#0x01
+}
+
+replace {
+ mov dps,#0x01
+ mov dps,#0x00
+} by {
+ ; Peephole 220.b removed bogus DPS set
+ mov dps,#0x00
+}
+
+replace {
+ mov %1 + %2,(%2 + %1)
+} by {
+ ; Peephole 221.a remove redundant mov
+} if notVolatile
+
+replace {
+ mov (%1 + %2 + %3),((%2 + %1) + %3)
+} by {
+ ; Peephole 221.b remove redundant mov
+} if notVolatile
+
+replace {
+ dec r%1
+ inc r%1
+} by {
+ ; Peephole 222 removed dec/inc pair
+}
+
+replace {
+ mov %1,dpl
+ mov %2,dph
+ mov dpl,%1
+ mov dph,%2
+} by {
+ mov %1,dpl
+ mov %2,dph
+ ; Peephole 223.a removed redundant dph/dpl moves
+} if notVolatile %1 %2
+
+replace {
+ mov %1,dpl
+ mov (%1 + 1),dph
+ mov dpl,%1
+ mov dph,(%1 + 1)
+} by {
+ mov %1,dpl
+ mov (%1 + 1),dph
+ ; Peephole 223.b removed redundant dph/dpl moves
+} if notVolatile %1
+
+replace {
+ mov a,%1
+ movx @dptr,a
+ mov dpl,%2
+ mov dph,%3
+ mov b,%4
+ mov a,%1
+} by {
+ mov a,%1
+ movx @dptr,a
+ mov dpl,%2
+ mov dph,%3
+ mov b,%4
+ ; Peephole 225 removed redundant move to acc
+} if notVolatile %1
+
+replace {
+ clr a
+ movx @%1,a
+ inc %1
+ clr a
+} by {
+ clr a
+ movx @%1,a
+ inc %1
+ ; Peephole 226.a removed unnecessary clr
+}
+
+replace {
+ clr a
+ movx @%1,a
+ inc %1
+ movx @%1,a
+ inc %1
+ clr a
+} by {
+ clr a
+ movx @%1,a
+ inc %1
+ movx @%1,a
+ inc %1
+ ; Peephole 226.b removed unnecessary clr
+}
+
+replace {
+ mov dptr,#%1
+ clr a
+ inc dptr
+ inc dptr
+ inc dptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ clr a
+ ; Peephole 227.a replaced inefficient 32 bit clear
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ mov dptr,#%1
+}
+
+replace {
+ mov dptr,#%1
+ clr a
+ inc dptr
+ inc dptr
+ inc dptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+ lcall __decdptr
+ mov a,#%2
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ ; Peephole 227.b replaced inefficient 32 constant
+ mov a,#%2
+ movx @dptr,a
+ inc dptr
+ clr a
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ mov dptr,#%1
+}
+
+replace {
+ mov dptr,#%1
+ clr a
+ inc dptr
+ movx @dptr,a
+ lcall __decdptr
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ clr a
+ ; Peephole 227.c replaced inefficient 16 bit clear
+ movx @dptr,a
+ inc dptr
+ movx @dptr,a
+ mov dptr,#%1
+}
+
+replace {
+ mov dptr,#%1
+ clr a
+ inc dptr
+ movx @dptr,a
+ lcall __decdptr
+ mov a,#%2
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ ; Peephole 227.d replaced inefficient 16 bit constant
+ mov a,#%2
+ movx @dptr,a
+ inc dptr
+ clr a
+ movx @dptr,a
+ mov dptr,#%1
+}
+
+// this last peephole often removes the last mov from 227.a - 227.d
+replace {
+ mov dptr,#%1
+ mov dptr,#%2
+} by {
+ ; Peephole 227.e removed redundant mov to dptr
+ mov dptr,#%2
+}
+
+replace {
+ movx a,@dptr
+} by {
+ ; Peephole 232 using movc to read xdata (--xram-movc)
+ clr a
+ movc a,@a+dptr
+} if xramMovcOption
+
+replace {
+ lcall _gptrget
+} by {
+ ; Peephole 233 using _gptrgetc instead of _gptrget (--xram-movc)
+ lcall _gptrgetc
+} if xramMovcOption
+
+replace {
+ mov r%1,a
+ mov dpl,r%1
+%2:
+ ret
+} by {
+ ; Peephole 234.a loading dpl directly from a(ccumulator), r%1 not set
+ mov dpl,a
+%2:
+ ret
+}
+
+replace {
+ mov r%1,a
+ mov dpl,r%2
+ mov dph,r%1
+%3:
+ ret
+} by {
+ ; Peephole 234.b loading dph directly from a(ccumulator), r%1 not set
+ mov dpl,r%2
+ mov dph,a
+%3:
+ ret
+}
+
+// 14 rules by Fiorenzo D. Ramaglia <fd.ramaglia@tin.it>
+
+replace {
+ add a,ar%1
+} by {
+ ; Peephole 236.a used r%1 instead of ar%1
+ add a,r%1
+}
+
+replace {
+ addc a,ar%1
+} by {
+ ; Peephole 236.b used r%1 instead of ar%1
+ addc a,r%1
+}
+
+replace {
+ anl a,ar%1
+} by {
+ ; Peephole 236.c used r%1 instead of ar%1
+ anl a,r%1
+}
+
+replace {
+ dec ar%1
+} by {
+ ; Peephole 236.d used r%1 instead of ar%1
+ dec r%1
+}
+
+replace {
+ djnz ar%1,%2
+} by {
+ ; Peephole 236.e used r%1 instead of ar%1
+ djnz r%1,%2
+}
+
+replace {
+ inc ar%1
+} by {
+ ; Peephole 236.f used r%1 instead of ar%1
+ inc r%1
+}
+
+replace {
+ mov a,ar%1
+} by {
+ ; Peephole 236.g used r%1 instead of ar%1
+ mov a,r%1
+}
+
+replace {
+ mov ar%1,#%2
+} by {
+ ; Peephole 236.h used r%1 instead of ar%1
+ mov r%1,#%2
+}
+
+replace {
+ mov ar%1,a
+} by {
+ ; Peephole 236.i used r%1 instead of ar%1
+ mov r%1,a
+}
+
+replace {
+ mov ar%1,ar%2
+} by {
+ ; Peephole 236.j used r%1 instead of ar%1
+ mov r%1,ar%2
+}
+
+replace {
+ orl a,ar%1
+} by {
+ ; Peephole 236.k used r%1 instead of ar%1
+ orl a,r%1
+}
+
+replace {
+ subb a,ar%1
+} by {
+ ; Peephole 236.l used r%1 instead of ar%1
+ subb a,r%1
+}
+
+replace {
+ xch a,ar%1
+} by {
+ ; Peephole 236.m used r%1 instead of ar%1
+ xch a,r%1
+}
+
+replace {
+ xrl a,ar%1
+} by {
+ ; Peephole 236.n used r%1 instead of ar%1
+ xrl a,r%1
+}
+
+// obsoleted by 251.b
+//replace {
+// sjmp %1
+//%2:
+// mov %3,%4
+//%1:
+// ret
+//} by {
+// ; Peephole 237.a removed sjmp to ret
+// ret
+//%2:
+// mov %3,%4
+//%1:
+// ret
+//} if labelRefCountChange(%1 -1)
+
+// obsoleted by 251.b
+//replace {
+// sjmp %1
+//%2:
+// mov %3,%4
+// mov dpl,%5
+// mov dph,%6
+//%1:
+// ret
+//} by {
+// ; Peephole 237.b removed sjmp to ret
+// ret
+//%2:
+// mov %3,%4
+// mov dpl,%5
+// mov dph,%6
+//%1:
+// ret
+//} if labelRefCountChange(%1 -1)
+
+// applies to f.e. device/lib/log10f.c
+replace {
+ mov %1,%9
+ mov %2,%10
+ mov %3,%11
+ mov %4,%12
+
+ mov %5,%13
+ mov %6,%14
+ mov %7,%15
+ mov %8,%16
+
+ mov %9,%1
+ mov %10,%2
+ mov %11,%3
+ mov %12,%4
+} by {
+ mov %1,%9
+ mov %2,%10
+ mov %3,%11
+ mov %4,%12
+
+ mov %5,%13
+ mov %6,%14
+ mov %7,%15
+ mov %8,%16
+ ; Peephole 238.a removed 4 redundant moves
+} if notSame(%1 %2 %3 %4 %5 %6 %7 %8), notVolatile(%1 %2 %3 %4 %9 %10 %11 %12)
+
+// applies to device/lib/log10f.c
+replace {
+ mov %1,%5
+ mov %2,%6
+ mov %3,%7
+ mov %4,%8
+
+ mov %5,%1
+ mov %6,%2
+ mov %7,%3
+} by {
+ mov %1,%5
+ mov %2,%6
+ mov %3,%7
+ mov %4,%8
+ ; Peephole 238.b removed 3 redundant moves
+} if notSame(%1 %2 %3 %4 %5 %6 %7), notVolatile(%1 %2 %3 %5 %6 %7)
+
+// applies to f.e. device/lib/time.c
+replace {
+ mov %1,%5
+ mov %2,%6
+
+ mov %3,%7
+ mov %4,%8
+
+ mov %5,%1
+ mov %6,%2
+} by {
+ mov %1,%5
+ mov %2,%6
+
+ mov %3,%7
+ mov %4,%8
+ ; Peephole 238.c removed 2 redundant moves
+} if notSame(%1 %2 %3 %4), notVolatile(%1 %2 %5 %6)
+
+// applies to f.e. support/regression/tests/bug-524209.c
+replace {
+ mov %1,%4
+ mov %2,%5
+ mov %3,%6
+
+ mov %4,%1
+ mov %5,%2
+ mov %6,%3
+} by {
+ mov %1,%4
+ mov %2,%5
+ mov %3,%6
+ ; Peephole 238.d removed 3 redundant moves
+} if notSame(%1 %2 %3 %4 %5 %6), notVolatile(%1 %2 %3 %4 %5 %6)
+
+// applies to f.e. ser_ir.asm
+replace {
+ mov r%1,acc
+} by {
+ ; Peephole 239 used a instead of acc
+ mov r%1,a
+}
+
+replace restart {
+ mov a,%1
+ addc a,#0x00
+} by {
+ ; Peephole 240 use clr instead of addc a,#0
+ clr a
+ addc a,%1
+}
+
+// peepholes 241.a0 to 241.d and 241.e0 to 241.h need to be in order
+replace {
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ cjne r%8,#%9,%0
+ cjne r%10,#%11,%0
+ cjne r%12,#%13,%0
+ cjne r%14,#%15,%0
+ cjne r%16,#%17,%0
+ mov a,#0x01
+ sjmp %1
+%0:
+ clr a
+%1:
+} by {
+ ; Peephole 241.a0 optimized compare
+ clr a
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ cjne r%8,#%9,%0
+ cjne r%10,#%11,%0
+ cjne r%12,#%13,%0
+ cjne r%14,#%15,%0
+ cjne r%16,#%17,%0
+ inc a
+%0:
+%1:
+} if labelRefCount(%0 8), labelRefCountChange(%1 -1)
+
+replace {
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ cjne r%8,#%9,%0
+ mov a,#0x01
+ sjmp %1
+%0:
+ clr a
+%1:
+} by {
+ ; Peephole 241.a optimized compare
+ clr a
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ cjne r%8,#%9,%0
+ inc a
+%0:
+%1:
+} if labelRefCount(%0 4), labelRefCountChange(%1 -1)
+
+// applies to generic pointer compare
+replace {
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ mov a,#0x01
+ sjmp %1
+%0:
+ clr a
+%1:
+} by {
+ ; Peephole 241.b optimized compare
+ clr a
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ cjne r%6,#%7,%0
+ inc a
+%0:
+%1:
+} if labelRefCount(%0 3), labelRefCountChange(%1 -1)
+
+// applies to f.e. time.c
+replace {
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ mov a,#0x01
+ sjmp %1
+%0:
+ clr a
+%1:
+} by {
+ ; Peephole 241.c optimized compare
+ clr a
+ cjne r%2,#%3,%0
+ cjne r%4,#%5,%0
+ inc a
+%0:
+%1:
+} if labelRefCount(%0 2), labelRefCountChange(%1 -1)
+
+// applies to f.e. malloc.c
+replace {
+ cjne r%2,#%3,%0
+ mov a,#0x01
+ sjmp %1
+%0:
+ clr a
+%1:
+} by {
+ ; Peephole 241.d optimized compare
+ clr a
+ cjne r%2,#%3,%0
+ inc a
+%0:
+%1:
+} if labelRefCount(%0 1), labelRefCountChange(%1 -1)
+
+// applies to f.e. j = (k!=0x1000);
+// with volatile idata long long k;
+replace {
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ inc r%0
+ cjne @r%0,#%6,%1
+ inc r%0
+ cjne @r%0,#%7,%1
+ inc r%0
+ cjne @r%0,#%8,%1
+ inc r%0
+ cjne @r%0,#%9,%1
+ inc r%0
+ cjne @r%0,#%10,%1
+ mov a,#0x01
+ sjmp %2
+%1:
+ clr a
+%2:
+} by {
+ ; Peephole 241.e0 optimized compare
+ clr a
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ inc r%0
+ cjne @r%0,#%6,%1
+ inc r%0
+ cjne @r%0,#%7,%1
+ inc r%0
+ cjne @r%0,#%8,%1
+ inc r%0
+ cjne @r%0,#%9,%1
+ inc r%0
+ cjne @r%0,#%10,%1
+ inc a
+%1:
+%2:
+} if labelRefCount(%1 8), labelRefCountChange(%2 -1)
+
+// applies to f.e. j = (k!=0x1000);
+// with volatile idata long k;
+replace {
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ inc r%0
+ cjne @r%0,#%6,%1
+ mov a,#0x01
+ sjmp %2
+%1:
+ clr a
+%2:
+} by {
+ ; Peephole 241.e optimized compare
+ clr a
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ inc r%0
+ cjne @r%0,#%6,%1
+ inc a
+%1:
+%2:
+} if labelRefCount(%1 4), labelRefCountChange(%2 -1)
+
+// applies to f.e. j = (p!=NULL);
+// with volatile idata char *p;
+replace {
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ mov a,#0x01
+ sjmp %2
+%1:
+ clr a
+%2:
+} by {
+ ; Peephole 241.f optimized compare
+ clr a
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc r%0
+ cjne @r%0,#%5,%1
+ inc a
+%1:
+%2:
+} if labelRefCount(%1 3), labelRefCountChange(%2 -1)
+
+// applies to f.e. j = (k!=0x1000);
+// with volatile idata int k;
+replace {
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ mov a,#0x01
+ sjmp %2
+%1:
+ clr a
+%2:
+} by {
+ ; Peephole 241.g optimized compare
+ clr a
+ cjne @r%0,#%3,%1
+ inc r%0
+ cjne @r%0,#%4,%1
+ inc a
+%1:
+%2:
+} if labelRefCount(%1 2), labelRefCountChange(%2 -1)
+
+// applies to f.e. vprintf.asm (--stack-auto)
+replace {
+ cjne @r%0,#%3,%1
+ mov a,#0x01
+ sjmp %2
+%1:
+ clr a
+%2:
+} by {
+ ; Peephole 241.h optimized compare
+ clr a
+ cjne @r%0,#%3,%1
+ inc a
+%1:
+%2:
+} if labelRefCount(%1 1), labelRefCountChange(%2 -1)
+
+// applies to f.e. scott-bool1.c
+replace {
+ jnz %1
+ mov %2,%3
+%1:
+ jz %4
+} by {
+ jnz %1
+ mov %2,%3
+ ; Peephole 242.a avoided branch jnz to jz
+ jz %4
+%1:
+} if labelRefCount %1 1
+
+// applies to f.e. scott-bool1.c
+replace {
+ jnz %1
+ mov %2,%3
+ orl a,%5
+%1:
+ jz %4
+} by {
+ jnz %1
+ mov %2,%3
+ orl a,%5
+ ; Peephole 242.b avoided branch jnz to jz
+ jz %4
+%1:
+} if labelRefCount %1 1
+
+// applies to f.e. logic.c
+replace {
+ jnz %1
+ mov %2,%3
+ orl a,%5
+ orl a,%6
+ orl a,%7
+%1:
+ jz %4
+} by {
+ jnz %1
+ mov %2,%3
+ orl a,%5
+ orl a,%6
+ orl a,%7
+ ; Peephole 242.c avoided branch jnz to jz
+ jz %4
+%1:
+} if labelRefCount %1 1
+
+// applies to f.e. vprintf.c
+// this is a rare case, usually the "tail increment" is noticed earlier
+replace {
+ cjne %1,%2,%3
+ inc %4
+%3:
+ sjmp %5
+} by {
+ ; Peephole 243 avoided branch to sjmp
+ cjne %1,%2,%5
+ inc %4
+%3:
+ sjmp %5
+} if labelInRange(%5), labelRefCountChange(%3 -1), labelRefCountChange(%5 1)
+
+// applies to f.e. simplefloat.c (saving 1 cycle)
+replace {
+ mov r%1,dpl
+ mov a,r%1
+} by {
+ ; Peephole 244.a moving first to a instead of r%1
+ mov a,dpl
+ mov r%1,a
+}
+
+// applies to f.e. _itoa.c (saving 1 cycle)
+replace {
+ mov r%1,dph
+ mov a,r%1
+} by {
+ ; Peephole 244.b moving first to a instead of r%1
+ mov a,dph
+ mov r%1,a
+}
+
+
+// applies to f.e. bug-460010.c (saving 1 cycle)
+replace {
+ mov r%1,a
+ mov dpl,r%1
+} by {
+ mov r%1,a
+ ; Peephole 244.c loading dpl from a instead of r%1
+ mov dpl,a
+}
+
+replace {
+ mov r%1,a
+ mov dph,r%1
+} by {
+ mov r%1,a
+ ; Peephole 244.d loading dph from a instead of r%1
+ mov dph,a
+}
+
+// this one is safe but disables 245.a 245.b
+// please remove 245 if 245.a 245.b are found to be safe
+// applies to f.e. scott-compare.c
+replace {
+ clr a
+ rlc a
+ mov r%1,a
+ cjne a,#0x01,%2
+%2:
+ clr a
+ rlc a
+ mov r%1,a
+} by {
+ ; Peephole 245 optimized complement (r%1 and acc set needed?)
+ cpl c
+ clr a
+ rlc a
+ mov r%1,a
+} if labelRefCount(%2 1), labelRefCountChange(%2 -1)
+
+// this one will not be triggered if 245 is present
+// please remove 245 if 245.a 245.b are found to be safe
+// applies to f.e. vprintf.c
+replace {
+ clr a
+ rlc a
+ mov r%1,a
+ cjne a,#0x01,%2
+%2:
+ clr a
+ rlc a
+ mov r%1,a
+ jz %3
+} by {
+ ; Peephole 245.a optimized conditional jump (r%1 and acc not set!)
+ jc %3
+} if labelRefCount(%2 1), labelRefCountChange(%2 -1)
+
+// this one will not be triggered if 245 is present
+// please remove 245 if 245.a 245.b are found to be safe
+// applies to f.e. scott-compare.c
+replace {
+ clr a
+ rlc a
+ mov r%1,a
+ cjne a,#0x01,%2
+%2:
+ clr a
+ rlc a
+ mov r%1,a
+ jnz %3
+} by {
+ ; Peephole 245.b optimized conditional jump (r%1 and acc not set!)
+ jnc %3
+} if labelRefCount(%2 1), labelRefCountChange(%2 -1)
+
+
+// rules 246.x apply to f.e. bitfields.c
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%3
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ ; Peephole 246.a combined clr/clr
+ anl a,#%2&%3
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%3
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ ; Peephole 246.b combined set/set
+ orl a,#%2|%3
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%3
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ ; Peephole 246.c combined set/clr
+ anl a,#%3
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%3
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ ; Peephole 246.d combined clr/set
+ orl a,#%3
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ anl a,#%3
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%4
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ ; Peephole 246.e combined set/clr/clr
+ anl a,#%3&%4
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ anl a,#%3
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%4
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%2
+ anl a,#%3
+ ; Peephole 246.f combined set/clr/set
+ orl a,#%4
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ orl a,#%3
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%4
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ orl a,#%3
+ ; Peephole 246.g combined clr/set/clr
+ anl a,#%4
+ movx @dptr,a
+} if notVolatile %1
+
+replace {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ orl a,#%3
+ movx @dptr,a
+ mov dptr,#%1
+ movx a,@dptr
+ orl a,#%4
+ movx @dptr,a
+} by {
+ mov dptr,#%1
+ movx a,@dptr
+ anl a,#%2
+ ; Peephole 246.h combined clr/set/set
+ orl a,#%3|%4
+ movx @dptr,a
+} if notVolatile %1
+
+
+// rules 247.x apply to f.e. bitfields.c
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%3
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ ; Peephole 247.a combined clr/clr
+ anl a,#%2&%3
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%3
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ ; Peephole 247.b combined set/set
+ orl a,#%2|%3
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%3
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ ; Peephole 247.c combined set/clr
+ anl a,#%3
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%3
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ ; Peephole 247.d combined clr/set
+ orl a,#%3
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ anl a,#%3
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%4
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ ; Peephole 247.e combined set/clr/clr
+ anl a,#%3&%4
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ anl a,#%3
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%4
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ orl a,#%2
+ anl a,#%3
+ ; Peephole 247.f combined set/clr/set
+ orl a,#%4
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ orl a,#%3
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%4
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ orl a,#%3
+ ; Peephole 247.g combined clr/set/clr
+ anl a,#%4
+ mov @r%5,a
+} if notVolatile %1
+
+replace {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ orl a,#%3
+ mov @r%5,a
+ mov r%5,#%1
+ mov a,@r%4
+ orl a,#%4
+ mov @r%5,a
+} by {
+ mov r%5,#%1
+ mov a,@r%5
+ anl a,#%2
+ ; Peephole 247.h combined clr/set/set
+ orl a,#%3|%4
+ mov @r%5,a
+} if notVolatile %1
+
+
+// Peepholes 248.x have to be compatible with the keyword volatile.
+// They optimize typical accesses to memory mapped I/O devices:
+// volatile xdata char t; t|=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ mov dptr,%1
+ mov a,%3
+ orl a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ ; Peephole 248.a optimized or to xdata
+ orl a,%3
+ movx @dptr,a
+}
+
+// volatile xdata char t; t&=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ mov dptr,%1
+ mov a,%3
+ anl a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ ; Peephole 248.b optimized and to xdata
+ anl a,%3
+ movx @dptr,a
+}
+
+// volatile xdata char t; t^=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ mov dptr,%1
+ mov a,%3
+ xrl a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ ; Peephole 248.c optimized xor to xdata
+ xrl a,%3
+ movx @dptr,a
+}
+
+// volatile xdata char t; t|=0x01; t&=~0x01; t|=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl a,%4
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl a,%5
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.d optimized or/and/or to volatile xdata
+ orl a,%3
+ movx @dptr,a
+ movx a,@dptr
+ anl a,%4
+ movx @dptr,a
+ movx a,@dptr
+ mov r%2,a
+ orl a,%5
+ movx @dptr,a
+}
+
+// volatile xdata char t; t&=~0x01; t|=0x01; t&=~0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl a,%4
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl a,%5
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.e optimized and/or/and to volatile xdata
+ anl a,%3
+ movx @dptr,a
+ movx a,@dptr
+ orl a,%4
+ movx @dptr,a
+ movx a,@dptr
+ mov r%2,a
+ anl a,%5
+ movx @dptr,a
+}
+
+// volatile xdata char t; t|=0x01; t&=~0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.f optimized or/and to volatile xdata
+ orl a,%3
+ movx @dptr,a
+ movx a,@dptr
+ mov r%2,a
+ anl a,%4
+ movx @dptr,a
+}
+
+// volatile xdata char t; t&=~0x01; t|=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.g optimized and/or to volatile xdata
+ anl a,%3
+ movx @dptr,a
+ movx a,@dptr
+ mov r%2,a
+ orl a,%4
+ movx @dptr,a
+}
+
+// volatile xdata char t; t^=0x01; t^=0x01;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ xrl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ xrl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.h optimized xor/xor to volatile xdata
+ xrl a,%3
+ movx @dptr,a
+ movx a,@dptr
+ mov r%2,a
+ xrl a,%4
+ movx @dptr,a
+}
+
+// Peeepholes 248.i to 248.m are like 248.d to 248.h except they apply to bitfields:
+// xdata struct { unsigned b0:1; unsigned b1:1; unsigned b2:1; } xport;
+// xport.b0=1; xport.b0=0; xport.b0=1;
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%4
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%5
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%3
+ movx @dptr,a
+ ; Peephole 248.i optimized or/and/or to xdata bitfield
+ movx a,@dptr
+ anl a,%4
+ movx @dptr,a
+ movx a,@dptr
+ orl a,%5
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%4
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%5
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%3
+ movx @dptr,a
+ ; Peephole 248.j optimized and/or/and to xdata bitfield
+ movx a,@dptr
+ orl a,%4
+ movx @dptr,a
+ movx a,@dptr
+ anl a,%5
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%3
+ movx @dptr,a
+ ; Peephole 248.k optimized or/and to xdata bitfield
+ movx a,@dptr
+ anl a,%4
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ orl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ anl a,%3
+ movx @dptr,a
+ ; Peephole 248.l optimized and/or to xdata bitfield
+ movx a,@dptr
+ orl a,%4
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ xrl a,%3
+ movx @dptr,a
+
+ mov dptr,%1
+ movx a,@dptr
+ xrl a,%4
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ xrl a,%3
+ movx @dptr,a
+ ; Peephole 248.m optimized xor/xor to xdata bitfield
+ movx a,@dptr
+ xrl a,%4
+ movx @dptr,a
+}
+
+// Peeepholes 248.n to 248.p are like previous peepholes but apply to arrays
+// applies to f.e. bug2686159.c
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ orl ar%2,%3
+ mov dptr,%1
+ mov a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.n optimized or to xdata array
+ orl a,%3
+ mov r%2,a
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ anl ar%2,%3
+ mov dptr,%1
+ mov a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.o optimized and to xdata array
+ anl a,%3
+ mov r%2,a
+ movx @dptr,a
+}
+
+replace {
+ mov dptr,%1
+ movx a,@dptr
+ mov r%2,a
+ xrl ar%2,%3
+ mov dptr,%1
+ mov a,r%2
+ movx @dptr,a
+} by {
+ mov dptr,%1
+ movx a,@dptr
+ ; Peephole 248.p optimized xor to xdata array
+ xrl a,%3
+ mov r%2,a
+ movx @dptr,a
+}
+
+replace {
+ jnz %1
+%1:
+} by {
+ ; Peephole 249.a jump optimization
+} if labelRefCount(%1 1), labelRefCountChange(%1 -1)
+
+replace {
+ jz %1
+%1:
+} by {
+ ; Peephole 249.b jump optimization
+} if labelRefCount(%1 1), labelRefCountChange(%1 -1)
+
+
+// This allows non-interrupt and interrupt code to safely compete
+// for a resource without the non-interrupt code having to disable
+// interrupts:
+// volatile bit resource_is_free;
+// if( resource_is_free ) {
+// resource_is_free=0; do_something; resource_is_free=1;
+// }
+replace {
+ jnb %1,%2
+%3:
+ clr %1
+} by {
+ ; Peephole 250.a using atomic test and clear
+ jbc %1,%3
+ sjmp %2
+%3:
+} if labelRefCount(%3 0), labelRefCountChange(%3 1)
+
+replace {
+ jb %1,%2
+ ljmp %3
+%2:
+ clr %1
+} by {
+ ; Peephole 250.b using atomic test and clear
+ jbc %1,%2
+ ljmp %3
+%2:
+} if labelRefCount %2 1
+
+
+// not before peephole 250.b
+replace {
+ ljmp %5
+} by {
+ ; Peephole 251.a replaced ljmp %5 to ret with ret
+ ret
+} if optimizeReturn(), labelIsReturnOnly(%5), labelRefCountChange(%5 -1)
+
+// not before peephole 250.b
+replace {
+ sjmp %5
+} by {
+ ; Peephole 251.b replaced sjmp %5 to ret with ret
+ ret
+} if optimizeReturn(), labelIsReturnOnly(%5), labelRefCountChange(%5 -1)
+
+// applies to shifts.c and when accessing arrays with an unsigned integer index
+// saving 1 byte, 2 cycles
+replace {
+ mov r%1,%2
+ mov a,(%2 + 1)
+ xch a,r%1
+ add a,acc
+ xch a,r%1
+ rlc a
+ mov r%3,a
+} by {
+ ; Peephole 252 optimized left shift
+ mov a,%2
+ add a,acc
+ mov r%1,a
+ mov a,(%2 + 1)
+ rlc a
+ mov r%3,a
+}
+
+// unsigned char i=8; do{ } while(--i != 0);
+// this applies if i is kept in a register
+replace {
+ dec %1
+ cjne %1,#0x00,%2
+} by {
+ ; Peephole 253.a optimized decrement with compare
+ djnz %1,%2
+} if notVolatile(%1)
+
+// unsigned char i=8; do{ } while(--i != 0);
+// this applies if i is kept in data memory
+// must come before 256, see bug 1721024
+replace {
+ dec %1
+ mov a,%1
+ jnz %2
+} by {
+ ; Peephole 253.b optimized decrement with compare
+ djnz %1,%2
+} if notVolatile(%1), operandsNotRelated(%1 '@r0' '@r1')
+
+
+// applies to f.e. funptrs.c
+// saves one byte if %1 is a register or @register
+replace {
+ mov a,%1
+ add a,acc
+} by {
+ mov a,%1
+ ; Peephole 254 optimized left shift
+ add a,%1
+} if notVolatile %1
+
+// applies to f.e. switch.c
+replace {
+ clr c
+ mov a,#%1
+ subb a,%2
+ jc %3
+%4:
+ mov a,%2
+ add a,%2
+ add a,%2
+ mov dptr,%5
+ jmp @a+dptr
+} by {
+ ; Peephole 255 optimized jump table index calculation
+ mov a,%2
+ cjne a,#(%1+0x01),.+1
+ jnc %3
+%4:
+ add a,%2
+ add a,%2
+ mov dptr,%5
+ jmp @a+dptr
+}
+
+// applies to f.e. jump tables and scott-bool1.c.
+// similar peepholes can be constructed for other instructions
+// after which a flag or a register is known (like: djnz, cjne, jnc)
+replace {
+ jc %1
+%2:
+ clr c
+} by {
+ jc %1
+%2:
+ ; Peephole 256.a removed redundant clr c
+} if labelRefCount %2 0
+
+// applies to f.e. logf.c
+replace {
+ jnz %1
+%2:
+ clr a
+} by {
+ jnz %1
+%2:
+ ; Peephole 256.b removed redundant clr a
+} if labelRefCount %2 0
+
+// applies to f.e. bug-905492.c
+replace {
+ jnz %1
+%2:
+ mov %3,#0x00
+} by {
+ jnz %1
+%2:
+ ; Peephole 256.c loading %3 with zero from a
+ mov %3,a
+} if labelRefCount %2 0
+
+// applies to f.e. malloc.c
+replace {
+ jnz %1
+%2:
+ mov %4,%5
+ mov %3,#0x00
+} by {
+ jnz %1
+%2:
+ mov %4,%5
+ ; Peephole 256.d loading %3 with zero from a
+ mov %3,a
+} if labelRefCount(%2 0),operandsNotRelated('a' %4)
+
+replace {
+ jnz %1
+%2:
+ mov %4,%5
+ mov %6,%7
+ mov %3,#0x00
+} by {
+ jnz %1
+%2:
+ mov %4,%5
+ mov %6,%7
+ ; Peephole 256.e loading %3 with zero from a
+ mov %3,a
+} if labelRefCount(%2 0),operandsNotRelated('a' %4 %6)
+
+replace {
+ jnz %1
+%2:
+ mov %4,%5
+ mov %6,%7
+ mov %8,%9
+ mov %3,#0x00
+} by {
+ jnz %1
+%2:
+ mov %4,%5
+ mov %6,%7
+ mov %8,%9
+ ; Peephole 256.f loading %2 with zero from a
+ mov %3,a
+} if labelRefCount(%2 0),operandsNotRelated('a' %4 %6 %8)
+
+
+replace restart {
+ ljmp %5
+} by {
+ ljmp %6
+ ; peephole 257.a jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ sjmp %5
+} by {
+ sjmp %6
+ ; peephole 257.b jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jz %5
+} by {
+ jz %6
+ ; peephole 257.c jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jnz %5
+} by {
+ jnz %6
+ ; peephole 257.d jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jc %5
+} by {
+ jc %6
+ ; peephole 257.e jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jnc %5
+} by {
+ jnc %6
+ ; peephole 257.f jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jb %1,%5
+} by {
+ jb %1,%6
+ ; peephole 257.g jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jnb %1,%5
+} by {
+ jnb %1,%6
+ ; peephole 257.h jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jbc %1,%5
+} by {
+ jbc %1,%6
+ ; peephole 257.i jumped to %6 directly instead of via %5.
+} if labelIsUncondJump(), labelInRange(%6), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+
+// in_byte<<=1; if(in_bit) in_byte|=1;
+// helps f.e. reading data on a 3-wire (SPI) bus
+replace {
+ mov a,%1
+ add a,%1
+ mov %1,a
+ jnb %2,%3
+%4:
+ orl %1,#0x01
+%3:
+} by {
+ mov a,%1
+ ; Peephole 258.a optimized bitbanging
+ mov c,%2
+ addc a,%1
+ mov %1,a
+%4:
+%3:
+} if notVolatile(%1), labelRefCountChange(%3 -1)
+
+// in_byte<<=1; if(in_bit) in_byte|=1;
+replace {
+ mov a,r%1
+ add a,r%1
+ mov r%1,a
+ jnb %2,%3
+%4:
+ orl ar%1,#0x01
+%3:
+} by {
+ mov a,r%1
+ ; Peephole 258.b optimized bitbanging
+ mov c,%2
+ addc a,r%1
+ mov r%1,a
+%4:
+%3:
+} if labelRefCountChange(%3 -1)
+
+// in_byte>>=1; if(in_bit) in_byte|=0x80;
+replace {
+ mov a,%1
+ clr c
+ rrc a
+ mov %1,a
+ jnb %2,%3
+%4:
+ orl %1,#0x80
+%3:
+} by {
+ mov a,%1
+ ; Peephole 258.c optimized bitbanging
+ mov c,%2
+ rrc a
+ mov %1,a
+%4:
+%3:
+} if notVolatile(%1), labelRefCountChange(%3 -1)
+
+// in_byte>>=1; if(in_bit) in_byte|=0x80;
+replace {
+ mov a,r%1
+ clr c
+ rrc a
+ mov r%1,a
+ jnb %2,%3
+%4:
+ orl ar%1,#0x80
+%3:
+} by {
+ mov a,r%1
+ ; Peephole 258.d optimized bitbanging
+ mov c,%2
+ rrc a
+ mov r%1,a
+%4:
+%3:
+} if labelRefCountChange(%3 -1)
+
+// out_bit=out_byte&0x80; out_byte<<=1;
+// helps f.e. writing data on a 3-wire (SPI) bus
+replace {
+ mov a,%1
+ rlc a
+ mov %2,c
+ mov a,%1
+ add a,%1
+ mov %1,a
+} by {
+ mov a,%1
+ ; Peephole 258.e optimized bitbanging
+ add a,%1
+ mov %2,c
+ mov %1,a
+} if notVolatile %1
+
+// out_bit=out_byte&0x01; out_byte>>=1;
+replace {
+ mov a,%1
+ rrc a
+ mov %2,c
+ mov a,%1
+ clr c
+ rrc a
+ mov %1,a
+} by {
+ mov a,%1
+ ; Peephole 258.f optimized bitbanging
+ clr c
+ rrc a
+ mov %2,c
+ mov %1,a
+} if notVolatile %1
+
+// Peepholes 259.x rely on the correct labelRefCount. Otherwise they are
+// not compatible with peepholes 250.x
+// Peepholes 250.x add jumps to a previously unused label. If the
+// labelRefCount is not increased, peepholes 259.x are (mistakenly) applied.
+// (Mail on sdcc-devel 2004-10-25)
+//
+// applies to f.e. vprintf.c
+replace {
+ sjmp %1
+%2:
+ ret
+} by {
+ sjmp %1
+ ; Peephole 259.a removed redundant label %2 and ret
+} if optimizeReturn(), labelRefCount(%2 0)
+
+// applies to f.e. gets.c
+replace {
+ ljmp %1
+%2:
+ ret
+} by {
+ ljmp %1
+ ; Peephole 259.b removed redundant label %2 and ret
+} if optimizeReturn(), labelRefCount(%2 0)
+
+replace {
+ sjmp %1
+%2:
+ sjmp %3
+} by {
+ sjmp %1
+ ; Peephole 259.c removed redundant label %2 and sjmp %3
+} if labelRefCount(%2 0)
+
+replace {
+ ljmp %1
+%2:
+ sjmp %3
+} by {
+ ljmp %1
+ ; Peephole 259.d removed redundant label %2 and sjmp %3
+} if labelRefCount(%2 0)
+
+replace {
+ sjmp %1
+%2:
+ ljmp %3
+} by {
+ sjmp %1
+ ; Peephole 259.e removed redundant label %2 and ljmp %3
+} if labelRefCount(%2 0)
+
+replace {
+ ljmp %1
+%2:
+ ljmp %3
+} by {
+ ljmp %1
+ ; Peephole 259.f removed redundant label %2 and ljmp %3
+} if labelRefCount(%2 0)
+
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+%3:
+} by {
+ ; Peephole 260.a used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+%3:
+} by {
+ ; Peephole 260.b used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+%3:
+} by {
+ ; Peephole 260.c used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+%3:
+} by {
+ ; Peephole 260.d used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+%3:
+} by {
+ ; Peephole 260.e used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+%3:
+} by {
+ ; Peephole 260.f used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+%3:
+} by {
+ ; Peephole 260.g used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+%3:
+} by {
+ ; Peephole 260.h used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+ ljmp %16
+%3:
+} by {
+ ; Peephole 260.i used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+ sjmp %16
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+ ljmp %16
+ ljmp %17
+%3:
+} by {
+ ; Peephole 260.j used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+ sjmp %16
+ sjmp %17
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+ ljmp %16
+ ljmp %17
+ ljmp %18
+%3:
+} by {
+ ; Peephole 260.k used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+ sjmp %16
+ sjmp %17
+ sjmp %18
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+ ljmp %16
+ ljmp %17
+ ljmp %18
+ ljmp %19
+%3:
+} by {
+ ; Peephole 260.l used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+ sjmp %16
+ sjmp %17
+ sjmp %18
+ sjmp %19
+%3:
+} if labelJTInRange
+
+// optimizing jumptables
+replace {
+ add a,%1
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ ljmp %5
+ ljmp %6
+ ljmp %7
+ ljmp %8
+ ljmp %9
+ ljmp %10
+ ljmp %11
+ ljmp %12
+ ljmp %13
+ ljmp %14
+ ljmp %15
+ ljmp %16
+ ljmp %17
+ ljmp %18
+ ljmp %19
+ ljmp %20
+%3:
+} by {
+ ; Peephole 260.m used sjmp in jumptable
+ mov dptr,#%2
+ jmp @a+dptr
+%2:
+ sjmp %5
+ sjmp %6
+ sjmp %7
+ sjmp %8
+ sjmp %9
+ sjmp %10
+ sjmp %11
+ sjmp %12
+ sjmp %13
+ sjmp %14
+ sjmp %15
+ sjmp %16
+ sjmp %17
+ sjmp %18
+ sjmp %19
+ sjmp %20
+%3:
+} if labelJTInRange
+
+// applies to: a = (a << 1) | (a >> 15);
+replace {
+ mov a,%1
+ rlc a
+ mov %1,a
+ mov a,%2
+ rlc a
+ mov %2,a
+ mov a,%1
+ mov acc.0,c
+ mov %1,a
+} by {
+ mov a,%1
+ rlc a
+ ; Peephole 261.a optimized left rol
+ xch a,%2
+ rlc a
+ xch a,%2
+ mov acc.0,c
+ mov %1,a
+}
+
+// applies to: a = (a << 15) | (a >> 1);
+replace {
+ mov a,%1
+ rrc a
+ mov %1,a
+ mov a,%2
+ rrc a
+ mov %2,a
+ mov a,%1
+ mov acc.7,c
+ mov %1,a
+} by {
+ mov a,%1
+ rrc a
+ ; Peephole 261.b optimized right rol
+ xch a,%2
+ rrc a
+ xch a,%2
+ mov acc.7,c
+ mov %1,a
+}
+
+replace {
+ cpl c
+ cpl c
+} by {
+ ; Peephole 262 removed redundant cpl c
+}
+
+replace {
+ mov %1,#%2
+ inc %1
+ inc %1
+ inc %1
+} by {
+ ; Peephole 263.a optimized loading const
+ mov %1,#(%2 + 3)
+} if notVolatile(%1)
+
+replace {
+ mov %1,#%2
+ inc %1
+ inc %1
+} by {
+ ; Peephole 263.b optimized loading const
+ mov %1,#(%2 + 2)
+} if notVolatile(%1)
+
+replace {
+ mov %1,#%2
+ inc %1
+} by {
+ ; Peephole 263.c optimized loading const
+ mov %1,#(%2 + 1)
+} if notVolatile(%1)
+
+
+replace {
+ clr a
+ cjne %1,%2,%3
+ inc a
+%3:
+ jz %4
+} by {
+ ; Peephole 264 jump optimization (acc not set)
+ cjne %1,%2,%4
+%3:
+} if labelRefCount(%3 1), labelRefCountChange(%3 -1)
+
+
+replace {
+ mov %1,c
+ cpl %1
+} by {
+ ; Peephole 265 optimized mov/cpl sequence (carry differs)
+ cpl c
+ mov %1,c
+} if notVolatile(%1)
+
+replace {
+ mov %1,c
+ jb %1,%2
+} by {
+ ; Peephole 266.a optimized mov/jump sequence
+ mov %1,c
+ jc %2
+} if notVolatile(%1)
+
+replace {
+ mov %1,c
+ jnb %1,%2
+} by {
+ ; Peephole 266.b optimized mov/jump sequence
+ mov %1,c
+ jnc %2
+} if notVolatile(%1)
+
+replace {
+ jnc %1
+ setb %2
+ sjmp %3
+%1:
+ clr %2
+%3:
+} by {
+ ; Peephole 267.a optimized mov bit sequence
+ mov %2,c
+%1:
+%3:
+} if labelRefCount(%1 1), labelRefCountChange(%1 -1), labelRefCountChange(%3 -1)
+
+replace {
+ jc %1
+ clr %2
+ sjmp %3
+%1:
+ setb %2
+%3:
+} by {
+ ; Peephole 267.b optimized mov bit sequence
+ mov %2,c
+%1:
+%3:
+} if labelRefCount(%1 1), labelRefCountChange(%1 -1), labelRefCountChange(%3 -1)
+
+replace {
+ mov %1,c
+ mov %1,c
+} by {
+ ; Peephole 268 removed redundant mov
+ mov %1,c
+} if notVolatile(%1)
+
+replace {
+ mov %1,c
+ mov c,%1
+} by {
+ ; Peephole 269 removed redundant mov
+ mov %1,c
+} if notVolatile(%1)
+
+//accessing struct/array on stack
+//replace {
+// add a,#%1
+// add a,#%2
+//} by {
+// ; Peephole 270 removed redundant add (carry might differ, bug 2736282)
+// add a,#%1+%2
+//}
+
+replace {
+ jz %1
+ mov %2,%4
+ sjmp %3
+%1:
+ mov %2,#0x00
+%3:
+} by {
+ jz %1
+ ; Peephole 271 optimized ternary operation (acc different)
+ mov a,%4
+%1:
+ mov %2,a
+%3:
+} if operandsNotRelated('a' 'dptr' %2), labelRefCount(%1 1), labelRefCountChange(%3 -1)
+
+
+// left-shifting 8 bit to 16 bit result
+// http://sourceforge.net/projects/sdcc/forums/forum/1864/topic/3536144
+replace {
+ clr a
+ swap a
+} by {
+ clr a
+ ; Peephole 272.a removed swap operation on zero
+}
+
+replace {
+ clr a
+ anl a,%1
+} by {
+ clr a
+ ; Peephole 272.b removed anl operation on zero
+} if notVolatile(%1)
+
+replace {
+ clr a
+ mov c,acc.0
+} by {
+ clr a
+ ; Peephole 272.c clearing carry directly
+ clr c
+}
+
+
+replace restart {
+ pop ar%1
+} by {
+ ; Peephole 300 pop ar%1 removed
+} if deadMove(%1)
+
+replace {
+ mov r%1,%2
+} by {
+ ; Peephole 301 mov r%1,%2 removed
+} if notVolatile(%2), deadMove(%1)
+
+
+// applies to: void test( char c ) { if( c ) func1(); else func2(); }
+replace {
+ lcall %1
+ ret
+} by {
+ ; Peephole 400.a replaced lcall/ret with ljmp
+ ljmp %1
+} if optimizeReturn(), notSame(%1 '_longjmp')
+
+// applies to: void test( char c ) { if( c ) func1(); else func2(); }
+replace {
+ lcall %1
+%2:
+ ret
+} by {
+ ; Peephole 400.b replaced lcall/ret with ljmp
+ ljmp %1
+ ;
+} if optimizeReturn(), notSame(%1 '_longjmp'), labelRefCount(%2 0)
+
+// applies to f.e. scott-bool1.c
+replace {
+ lcall %1
+%2:
+ ret
+} by {
+ ; Peephole 400.c replaced lcall with ljmp
+ ljmp %1
+%2:
+ ret
+} if optimizeReturn(), notSame(%1 '_longjmp')
+
+// for programs less than 2k
+replace {
+ lcall %1
+} by {
+ ; Peephole 401.a replaced lcall with acall
+ acall %1
+} if useAcallAjmp
+
+// for programs less than 2k
+replace {
+ ljmp %1
+} by {
+ ; Peephole 401.b replaced ljmp with ajmp
+ ajmp %1
+} if useAcallAjmp
+
+
+// should be one of the last peepholes
+replace{
+%1:
+} by {
+ ; Peephole 500 removed redundant label %1
+} if labelRefCount(%1 0)
diff --git a/src/mcs51/ralloc.c b/src/mcs51/ralloc.c
new file mode 100644
index 0000000..1d900ee
--- /dev/null
+++ b/src/mcs51/ralloc.c
@@ -0,0 +1,3466 @@
+/*------------------------------------------------------------------------
+
+ SDCCralloc.c - source file for register allocation. (8051) specific
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "common.h"
+#include "ralloc.h"
+#include "gen.h"
+#include "dbuf_string.h"
+
+/*-----------------------------------------------------------------*/
+/* At this point we start getting processor specific although */
+/* some routines are non-processor specific & can be reused when */
+/* targetting other processors. The decision for this will have */
+/* to be made on a routine by routine basis */
+/* routines used to pack registers are most definitely not reusable */
+/* since the pack the registers depending strictly on the MCU */
+/*-----------------------------------------------------------------*/
+
+extern void gen51Code (iCode *);
+#define D(x)
+
+/* Global data */
+static struct
+{
+ bitVect *spiltSet;
+ set *stackSpil;
+ bitVect *regAssigned;
+ bitVect *totRegAssigned; /* final set of LRs that got into registers */
+ short blockSpil;
+ int slocNum;
+ bitVect *funcrUsed; /* registers used in a function */
+ int stackExtend;
+ int dataExtend;
+ bitVect *allBitregs; /* all bit registers */
+ bitVect *allBankregs; /* all bank registers */
+}
+_G;
+
+/* Shared with gen.c */
+int mcs51_ptrRegReq; /* one byte pointer register required */
+
+/* 8051 registers */
+reg_info regs8051[] = {
+ {REG_GPR, R7_IDX, REG_GPR, "r7", "ar7", "0", 7, 1},
+ {REG_GPR, R6_IDX, REG_GPR, "r6", "ar6", "0", 6, 1},
+ {REG_GPR, R5_IDX, REG_GPR, "r5", "ar5", "0", 5, 1},
+ {REG_GPR, R4_IDX, REG_GPR, "r4", "ar4", "0", 4, 1},
+ {REG_GPR, R3_IDX, REG_GPR, "r3", "ar3", "0", 3, 1},
+ {REG_GPR, R2_IDX, REG_GPR, "r2", "ar2", "0", 2, 1},
+ {REG_PTR, R1_IDX, REG_PTR, "r1", "ar1", "0", 1, 1},
+ {REG_PTR, R0_IDX, REG_PTR, "r0", "ar0", "0", 0, 1},
+ {REG_BIT, B0_IDX, REG_BIT, "b0", "b0", "bits", 0, 1},
+ {REG_BIT, B1_IDX, REG_BIT, "b1", "b1", "bits", 1, 1},
+ {REG_BIT, B2_IDX, REG_BIT, "b2", "b2", "bits", 2, 1},
+ {REG_BIT, B3_IDX, REG_BIT, "b3", "b3", "bits", 3, 1},
+ {REG_BIT, B4_IDX, REG_BIT, "b4", "b4", "bits", 4, 1},
+ {REG_BIT, B5_IDX, REG_BIT, "b5", "b5", "bits", 5, 1},
+ {REG_BIT, B6_IDX, REG_BIT, "b6", "b6", "bits", 6, 1},
+ {REG_BIT, B7_IDX, REG_BIT, "b7", "b7", "bits", 7, 1},
+ {REG_GPR, X8_IDX, REG_GPR, "x8", "x8", "xreg", 0, 1},
+ {REG_GPR, X9_IDX, REG_GPR, "x9", "x9", "xreg", 1, 1},
+ {REG_GPR, X10_IDX, REG_GPR, "x10", "x10", "xreg", 2, 1},
+ {REG_GPR, X11_IDX, REG_GPR, "x11", "x11", "xreg", 3, 1},
+ {REG_GPR, X12_IDX, REG_GPR, "x12", "x12", "xreg", 4, 1},
+ {REG_CND, CND_IDX, REG_CND, "C", "psw", "0xd0", 0, 1},
+ {0, DPL_IDX, 0, "dpl", "dpl", "0x82", 0, 0},
+ {0, DPH_IDX, 0, "dph", "dph", "0x83", 0, 0},
+ {0, B_IDX, 0, "b", "b", "0xf0", 0, 0},
+ {0, A_IDX, 0, "a", "acc", "0xe0", 0, 0},
+};
+
+int mcs51_nRegs = 16;
+static void spillThis (symbol *);
+static void freeAllRegs ();
+
+/*-----------------------------------------------------------------*/
+/* allocReg - allocates register of given type */
+/*-----------------------------------------------------------------*/
+static reg_info *
+allocReg (short type)
+{
+ int i;
+
+ for (i = 0; i < mcs51_nRegs; i++)
+ {
+ /* if type is given as 0 then any
+ free register will do */
+ if (!type && regs8051[i].isFree)
+ {
+ regs8051[i].isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, i);
+ return &regs8051[i];
+ }
+ /* otherwise look for specific type
+ of register */
+ if (regs8051[i].isFree && regs8051[i].type == type)
+ {
+ regs8051[i].isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, i);
+ return &regs8051[i];
+ }
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* allocThisReg - allocates a particular register (if free) */
+/*-----------------------------------------------------------------*/
+static reg_info *
+allocThisReg (reg_info *reg)
+{
+ if (!reg->isFree)
+ return NULL;
+
+ reg->isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, reg->rIdx);
+
+ return reg;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* mcs51_regWithIdx - returns pointer to register with index number*/
+/*-----------------------------------------------------------------*/
+reg_info *
+mcs51_regWithIdx (int idx)
+{
+ int i;
+
+ for (i = 0; i < sizeof (regs8051) / sizeof (reg_info); i++)
+ if (regs8051[i].rIdx == idx)
+ return &regs8051[i];
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "regWithIdx not found");
+ exit (1);
+}
+
+/*-----------------------------------------------------------------*/
+/* freeReg - frees a register */
+/*-----------------------------------------------------------------*/
+static void
+freeReg (reg_info *reg)
+{
+ if (!reg)
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "freeReg - Freeing NULL register");
+ exit (1);
+ }
+
+ reg->isFree = 1;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* nFreeRegs - returns number of free registers */
+/*-----------------------------------------------------------------*/
+static int
+nFreeRegs (int type)
+{
+ int i;
+ int nfr = 0;
+
+ for (i = 0; i < mcs51_nRegs; i++)
+ if (regs8051[i].isFree && regs8051[i].type == type)
+ nfr++;
+ return nfr;
+}
+
+/*-----------------------------------------------------------------*/
+/* nfreeRegsType - free registers with type */
+/*-----------------------------------------------------------------*/
+static int
+nfreeRegsType (int type)
+{
+ int nfr;
+ if (type == REG_PTR)
+ {
+ if ((nfr = nFreeRegs (type)) == 0)
+ return nFreeRegs (REG_GPR);
+ }
+
+ return nFreeRegs (type);
+}
+
+/*-----------------------------------------------------------------*/
+/* useReg - marks a register as used */
+/*-----------------------------------------------------------------*/
+static void
+useReg (reg_info *reg)
+{
+ reg->isFree = 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* computeSpillable - given a point find the spillable live ranges */
+/*-----------------------------------------------------------------*/
+static bitVect *
+computeSpillable (iCode * ic)
+{
+ bitVect *spillable;
+
+ /* spillable live ranges are those that are live at this
+ point . the following categories need to be subtracted
+ from this set.
+ a) - those that are already spilt
+ b) - if being used by this one
+ c) - defined by this one */
+
+ spillable = bitVectCopy (ic->rlive);
+ spillable = bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */
+ spillable = bitVectCplAnd (spillable, ic->uses); /* used in this one */
+ bitVectUnSetBit (spillable, ic->defKey);
+ spillable = bitVectIntersect (spillable, _G.regAssigned);
+ return spillable;
+}
+
+/*-----------------------------------------------------------------*/
+/* bitType - will return 1 if the symbol has type REG_BIT */
+/*-----------------------------------------------------------------*/
+static int
+bitType (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return (sym->regType == REG_BIT ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* noSpilLoc - return true if a variable has no spil location */
+/*-----------------------------------------------------------------*/
+static int
+noSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return (sym->usl.spillLoc ? 0 : 1);
+}
+
+/*-----------------------------------------------------------------*/
+/* hasSpilLoc - will return 1 if the symbol has spil location */
+/*-----------------------------------------------------------------*/
+static int
+hasSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return (sym->usl.spillLoc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* directSpilLoc - will return 1 if the spillocation is in direct */
+/*-----------------------------------------------------------------*/
+static int
+directSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ if (sym->usl.spillLoc && (IN_DIRSPACE (SPEC_OCLS (sym->usl.spillLoc->etype))))
+ return 1;
+ else
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* hasSpilLocnoUptr - will return 1 if the symbol has spil */
+/* location but is not used as a pointer */
+/*-----------------------------------------------------------------*/
+static int
+hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* rematable - will return 1 if the remat flag is set */
+/*-----------------------------------------------------------------*/
+static int
+rematable (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return sym->remat;
+}
+
+/*-----------------------------------------------------------------*/
+/* notUsedInRemaining - not used or defined in remain of the block */
+/*-----------------------------------------------------------------*/
+static int
+notUsedInRemaining (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return ((usedInRemaining (operandFromSymbol (sym), ic) ? 0 : 1) && allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq));
+}
+
+/*-----------------------------------------------------------------*/
+/* allLRs - return true for all */
+/*-----------------------------------------------------------------*/
+static int
+allLRs (symbol * sym, eBBlock * ebp, iCode * ic)
+{
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* liveRangesWith - applies function to a given set of live range */
+/*-----------------------------------------------------------------*/
+static set *
+liveRangesWith (bitVect * lrs, int (func) (symbol *, eBBlock *, iCode *), eBBlock * ebp, iCode * ic)
+{
+ set *rset = NULL;
+ int i;
+
+ if (!lrs || !lrs->size)
+ return NULL;
+
+ for (i = 1; i < lrs->size; i++)
+ {
+ symbol *sym;
+ if (!bitVectBitValue (lrs, i))
+ continue;
+
+ /* if we don't find it in the live range
+ hash table we are in serious trouble */
+ if (!(sym = hTabItemWithKey (liveRanges, i)))
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "liveRangesWith could not find liveRange");
+ exit (1);
+ }
+
+ if (func (sym, ebp, ic) && bitVectBitValue (_G.regAssigned, sym->key))
+ addSetHead (&rset, sym);
+ }
+
+ return rset;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* leastUsedLR - given a set determines which is the least used */
+/*-----------------------------------------------------------------*/
+static symbol *
+leastUsedLR (set * sset)
+{
+ symbol *sym = NULL, *lsym = NULL;
+
+ sym = lsym = setFirstItem (sset);
+
+ if (!lsym)
+ return NULL;
+
+ for (; lsym; lsym = setNextItem (sset))
+ {
+ /* if usage is the same then prefer
+ to spill the smaller of the two */
+ if (lsym->used == sym->used)
+ if (getSize (lsym->type) < getSize (sym->type))
+ sym = lsym;
+
+ /* if less usage */
+ if (lsym->used < sym->used)
+ sym = lsym;
+ }
+
+ setToNull ((void *) &sset);
+ sym->blockSpil = 0;
+ return sym;
+}
+
+/*-----------------------------------------------------------------*/
+/* noOverLap - will iterate through the list looking for over lap */
+/*-----------------------------------------------------------------*/
+static int
+noOverLap (set * itmpStack, symbol * fsym)
+{
+ symbol *sym;
+
+ for (sym = setFirstItem (itmpStack); sym; sym = setNextItem (itmpStack))
+ {
+ if (bitVectBitValue (sym->clashes, fsym->key))
+ return 0;
+ }
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* isFree - will return 1 if the a free spil location is found */
+/*-----------------------------------------------------------------*/
+static
+DEFSETFUNC (isFree)
+{
+ symbol *sym = item;
+ V_ARG (symbol **, sloc);
+ V_ARG (symbol *, fsym);
+
+ /* if already found */
+ if (*sloc)
+ return 0;
+
+ /* if it is free && and the itmp assigned to
+ this does not have any overlapping live ranges
+ with the one currently being assigned and
+ the size can be accomodated */
+ if (sym->isFree && noOverLap (sym->usl.itmpStack, fsym) && getSize (sym->type) >= getSize (fsym->type)
+ && (IS_BIT (sym->type) == IS_BIT (fsym->type)))
+ {
+ *sloc = sym;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* spillLRWithPtrReg :- will spil those live ranges which use PTR */
+/*-----------------------------------------------------------------*/
+static void
+spillLRWithPtrReg (symbol * forSym)
+{
+ symbol *lrsym;
+ reg_info *r0, *r1;
+ int k;
+
+ if (!_G.regAssigned || bitVectIsZero (_G.regAssigned))
+ return;
+
+ r0 = mcs51_regWithIdx (R0_IDX);
+ r1 = mcs51_regWithIdx (R1_IDX);
+
+ /* for all live ranges */
+ for (lrsym = hTabFirstItem (liveRanges, &k); lrsym; lrsym = hTabNextItem (liveRanges, &k))
+ {
+ int j;
+
+ /* if no registers assigned to it or spilt */
+ /* if it does not overlap this then
+ no need to spill it */
+
+ if (lrsym->isspilt || !lrsym->nRegs || (lrsym->liveTo < forSym->liveFrom))
+ continue;
+
+ /* go thru the registers : if it is either
+ r0 or r1 then spill it */
+ for (j = 0; j < lrsym->nRegs; j++)
+ if (lrsym->regs[j] == r0 || lrsym->regs[j] == r1)
+ {
+ spillThis (lrsym);
+ break;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* createStackSpil - create a location on the stack to spil */
+/*-----------------------------------------------------------------*/
+static symbol *
+createStackSpil (symbol * sym)
+{
+ symbol *sloc = NULL;
+ int useXstack, model;
+
+ struct dbuf_s dbuf;
+
+ /* first go try and find a free one that is already
+ existing on the stack */
+ if (applyToSet (_G.stackSpil, isFree, &sloc, sym))
+ {
+ /* found a free one : just update & return */
+ sym->usl.spillLoc = sloc;
+ sym->stackSpil = 1;
+ sloc->isFree = 0;
+ addSetHead (&sloc->usl.itmpStack, sym);
+ return sym;
+ }
+
+ /* could not then have to create one , this is the hard part
+ we need to allocate this on the stack : this is really a
+ hack!! but cannot think of anything better at this time */
+
+ dbuf_init (&dbuf, 128);
+ dbuf_printf (&dbuf, "sloc%d", _G.slocNum++);
+
+ sloc = newiTemp (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+
+ /* set the type to the spilling symbol */
+ sloc->type = copyLinkChain (sym->type);
+ sloc->etype = getSpec (sloc->type);
+ if (!IS_BIT (sloc->etype))
+ {
+ SPEC_SCLS (sloc->etype) = S_DATA;
+ }
+ else if (SPEC_SCLS (sloc->etype) == S_SBIT)
+ {
+ SPEC_SCLS (sloc->etype) = S_BIT;
+ }
+ SPEC_EXTR (sloc->etype) = 0;
+ SPEC_STAT (sloc->etype) = 0;
+ SPEC_VOLATILE (sloc->etype) = 0;
+ SPEC_ABSA (sloc->etype) = 0;
+
+ /* we don't allow it to be allocated
+ onto the external stack since : so we
+ temporarily turn it off ; we also
+ turn off memory model to prevent
+ the spil from going to the external storage
+ */
+
+ useXstack = options.useXstack;
+ model = options.model;
+/* noOverlay = options.noOverlay; */
+/* options.noOverlay = 1; */
+ options.model = options.useXstack = 0;
+
+ allocLocal (sloc);
+
+ options.useXstack = useXstack;
+ options.model = model;
+/* options.noOverlay = noOverlay; */
+ sloc->isref = 1; /* to prevent compiler warning */
+
+ /* if it is on the stack then update the stack */
+ if (IN_STACK (sloc->etype))
+ {
+ currFunc->stack += getSize (sloc->type);
+ _G.stackExtend += getSize (sloc->type);
+ }
+ else
+ _G.dataExtend += getSize (sloc->type);
+
+ /* add it to the _G.stackSpil set */
+ addSetHead (&_G.stackSpil, sloc);
+ sym->usl.spillLoc = sloc;
+ sym->stackSpil = 1;
+
+ /* add it to the set of itempStack set
+ of the spill location */
+ addSetHead (&sloc->usl.itmpStack, sym);
+ return sym;
+}
+
+/*-----------------------------------------------------------------*/
+/* isSpiltOnStack - returns true if the spil location is on stack */
+/* or otherwise needs a pointer register */
+/*-----------------------------------------------------------------*/
+static bool
+isSpiltOnStack (symbol * sym)
+{
+ sym_link *etype;
+
+ if (!sym)
+ return FALSE;
+
+ if (!sym->isspilt)
+ return FALSE;
+
+/* if (sym->_G.stackSpil) */
+/* return TRUE; */
+
+ if (!sym->usl.spillLoc)
+ return FALSE;
+
+ if (sym->usl.spillLoc->onStack || sym->usl.spillLoc->iaccess)
+ return TRUE;
+
+ etype = getSpec (sym->usl.spillLoc->type);
+ if (IN_STACK (etype))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* spillThis - spils a specific operand */
+/*-----------------------------------------------------------------*/
+static void
+spillThis (symbol * sym)
+{
+ int i;
+ /* if this is rematerializable or has a spillLocation
+ we are okay, else we need to create a spillLocation
+ for it */
+ if (!(sym->remat || sym->usl.spillLoc))
+ createStackSpil (sym);
+
+ /* mark it as spilt & put it in the spilt set */
+ sym->isspilt = sym->spillA = 1;
+ _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key);
+
+ bitVectUnSetBit (_G.regAssigned, sym->key);
+ bitVectUnSetBit (_G.totRegAssigned, sym->key);
+
+ for (i = 0; i < sym->nRegs; i++)
+ {
+ if (sym->regs[i])
+ {
+ freeReg (sym->regs[i]);
+ sym->regs[i] = NULL;
+ }
+ }
+
+ /* if spilt on stack then free up r0 & r1
+ if they could have been assigned to some
+ LIVE ranges */
+ if (!mcs51_ptrRegReq && isSpiltOnStack (sym))
+ {
+ spillLRWithPtrReg (sym);
+ mcs51_ptrRegReq++;
+ }
+
+ if (sym->usl.spillLoc && !sym->remat)
+ sym->usl.spillLoc->allocreq++;
+ return;
+}
+
+/*-----------------------------------------------------------------*/
+/* selectSpil - select a iTemp to spil : rather a simple procedure */
+/*-----------------------------------------------------------------*/
+static symbol *
+selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
+{
+ bitVect *lrcs = NULL;
+ set *selectS;
+ symbol *sym;
+
+ /* get the spillable live ranges */
+ lrcs = computeSpillable (ic);
+
+ /* remove incompatible registers */
+ if ((forSym->regType == REG_PTR) || (forSym->regType == REG_GPR))
+ {
+ selectS = liveRangesWith (lrcs, bitType, ebp, ic);
+
+ for (sym = setFirstItem (selectS); sym; sym = setNextItem (selectS))
+ {
+ bitVectUnSetBit (lrcs, sym->key);
+ }
+ }
+
+ /* get all live ranges that are rematerializable */
+ if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic)))
+ {
+ /* return the least used of these */
+ return leastUsedLR (selectS);
+ }
+
+ /* get live ranges with spillLocations in direct space */
+ if ((selectS = liveRangesWith (lrcs, directSpilLoc, ebp, ic)))
+ {
+ sym = leastUsedLR (selectS);
+ strncpyz (sym->rname,
+ sym->usl.spillLoc->rname[0] ? sym->usl.spillLoc->rname : sym->usl.spillLoc->name, sizeof (sym->rname));
+ sym->spildir = 1;
+ /* mark it as allocation required */
+ sym->usl.spillLoc->allocreq++;
+ return sym;
+ }
+
+ /* if the symbol is local to the block then */
+ if (forSym->liveTo < ebp->lSeq)
+ {
+ /* check if there are any live ranges allocated
+ to registers that are not used in this block */
+ if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInBlock, ebp, ic)))
+ {
+ sym = leastUsedLR (selectS);
+ /* if this is not rematerializable */
+ if (!sym->remat)
+ {
+ _G.blockSpil++;
+ sym->blockSpil = 1;
+ }
+ return sym;
+ }
+
+ /* check if there are any live ranges that are
+ not used in the remainder of the block */
+ if (!_G.blockSpil && !isiCodeInFunctionCall (ic) && (selectS = liveRangesWith (lrcs, notUsedInRemaining, ebp, ic)))
+ {
+ sym = leastUsedLR (selectS);
+ if (sym != forSym)
+ {
+ if (!sym->remat)
+ {
+ sym->remainSpil = 1;
+ _G.blockSpil++;
+ }
+ return sym;
+ }
+ }
+ }
+
+ /* find live ranges with spillocation && not used as pointers */
+ if ((selectS = liveRangesWith (lrcs, hasSpilLocnoUptr, ebp, ic)))
+ {
+ sym = leastUsedLR (selectS);
+ /* mark this as allocation required */
+ sym->usl.spillLoc->allocreq++;
+ return sym;
+ }
+
+ /* find live ranges with spillocation */
+ if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic)))
+ {
+ sym = leastUsedLR (selectS);
+ sym->usl.spillLoc->allocreq++;
+ return sym;
+ }
+
+ /* couldn't find then we need to create a spil
+ location on the stack, for which one?
+ the least used ofcourse */
+ if ((selectS = liveRangesWith (lrcs, noSpilLoc, ebp, ic)))
+ {
+ /* return a created spil location */
+ sym = createStackSpil (leastUsedLR (selectS));
+ sym->usl.spillLoc->allocreq++;
+ return sym;
+ }
+
+ /* this is an extreme situation we will spill
+ this one : happens very rarely but it does happen */
+ spillThis (forSym);
+ return forSym;
+}
+
+/*-----------------------------------------------------------------*/
+/* spilSomething - spil some variable & mark registers as free */
+/*-----------------------------------------------------------------*/
+static bool
+spilSomething (iCode * ic, eBBlock * ebp, symbol * forSym)
+{
+ symbol *ssym;
+ int i;
+
+ /* get something we can spil */
+ ssym = selectSpil (ic, ebp, forSym);
+
+ /* mark it as spilt */
+ ssym->isspilt = ssym->spillA = 1;
+ _G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key);
+
+ /* mark it as not register assigned &
+ take it away from the set */
+ bitVectUnSetBit (_G.regAssigned, ssym->key);
+ bitVectUnSetBit (_G.totRegAssigned, ssym->key);
+
+ /* mark the registers as free */
+ for (i = 0; i < ssym->nRegs; i++)
+ if (ssym->regs[i])
+ freeReg (ssym->regs[i]);
+
+ /* if spilt on stack then free up r0 & r1
+ if they could have been assigned to as gprs */
+ if (!mcs51_ptrRegReq && isSpiltOnStack (ssym))
+ {
+ spillLRWithPtrReg (ssym);
+ mcs51_ptrRegReq++;
+ }
+
+ /* if this was a block level spil then insert push & pop
+ at the start & end of block respectively */
+ if (ssym->blockSpil)
+ {
+ iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL);
+ /* add push to the start of the block */
+ addiCodeToeBBlock (ebp, nic, (ebp->sch->op == LABEL ? ebp->sch->next : ebp->sch));
+ nic = newiCode (IPOP, operandFromSymbol (ssym), NULL);
+ /* add pop to the end of the block */
+ addiCodeToeBBlock (ebp, nic, NULL);
+ }
+
+ /* if spilt because not used in the remainder of the
+ block then add a push before this instruction and
+ a pop at the end of the block */
+ if (ssym->remainSpil)
+ {
+ iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL);
+ /* add push just before this instruction */
+ addiCodeToeBBlock (ebp, nic, ic);
+
+ nic = newiCode (IPOP, operandFromSymbol (ssym), NULL);
+ /* add pop to the end of the block */
+ addiCodeToeBBlock (ebp, nic, NULL);
+ }
+
+ if (ssym == forSym)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegPtr - will try for PTR if not a GPR type if not spil */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ reg_info *reg;
+ int j;
+
+tryAgain:
+ /* try for a ptr type */
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ /* we have to spil */
+ if (!spilSomething (ic, ebp, sym))
+ return NULL;
+
+ /* make sure partially assigned registers aren't reused */
+ for (j = 0; j <= sym->nRegs; j++)
+ if (sym->regs[j])
+ sym->regs[j]->isFree = 0;
+
+ /* this looks like an infinite loop but
+ in reality selectSpil will abort */
+ goto tryAgain;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegGpr - will try for GPR if not spil */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ reg_info *reg;
+ int j;
+
+tryAgain:
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ if (!mcs51_ptrRegReq)
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ /* we have to spil */
+ if (!spilSomething (ic, ebp, sym))
+ return NULL;
+
+ /* make sure partially assigned registers aren't reused */
+ for (j = 0; j <= sym->nRegs; j++)
+ if (sym->regs[j])
+ sym->regs[j]->isFree = 0;
+
+ /* this looks like an infinite loop but
+ in reality selectSpil will abort */
+ goto tryAgain;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegBit - will try for Bit if not spill this */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegBitTry (symbol * sym)
+{
+ reg_info *reg;
+
+ /* try for a bit type */
+ if ((reg = allocReg (REG_BIT)))
+ return reg;
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegPtrNoSpil - get it cannot be spilt */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegPtrNoSpil ()
+{
+ reg_info *reg;
+
+ /* try for a ptr type */
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ assert (0);
+
+ /* just to make the compiler happy */
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegGprNoSpil - get it cannot be spilt */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegGprNoSpil ()
+{
+ reg_info *reg;
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ if (!mcs51_ptrRegReq)
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ assert (0);
+
+ /* just to make the compiler happy */
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegBitNoSpil - get it cannot be spilt */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegBitNoSpil ()
+{
+ reg_info *reg;
+
+ /* try for a ptr type */
+ if ((reg = allocReg (REG_BIT)))
+ return reg;
+
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ assert (0);
+
+ /* just to make the compiler happy */
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* symHasReg - symbol has a given register */
+/*-----------------------------------------------------------------*/
+static bool
+symHasReg (symbol * sym, reg_info * reg)
+{
+ int i;
+
+ for (i = 0; i < sym->nRegs; i++)
+ if (sym->regs[i] == reg)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* updateRegUsage - update the registers in use at the start of */
+/* this icode */
+/*-----------------------------------------------------------------*/
+static void
+updateRegUsage (iCode * ic)
+{
+ int reg;
+
+ for (reg = 0; reg < mcs51_nRegs; reg++)
+ {
+ if (regs8051[reg].isFree)
+ {
+ ic->riu &= ~(1 << regs8051[reg].offset);
+ }
+ else
+ {
+ ic->riu |= (1 << regs8051[reg].offset);
+ BitBankUsed |= (reg >= 8);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* deassignLRs - check the live to and if they have registers & are */
+/* not spilt then free up the registers */
+/*-----------------------------------------------------------------*/
+static void
+deassignLRs (iCode * ic, eBBlock * ebp)
+{
+ symbol *sym;
+ int k;
+ symbol *result;
+
+ for (sym = hTabFirstItem (liveRanges, &k); sym; sym = hTabNextItem (liveRanges, &k))
+ {
+ symbol *psym = NULL;
+ /* if it does not end here */
+ if (sym->liveTo > ic->seq)
+ continue;
+
+ /* if it was spilt on stack then we can
+ mark the stack spil location as free */
+ if (sym->isspilt)
+ {
+ if (sym->stackSpil)
+ {
+ sym->usl.spillLoc->isFree = 1;
+ sym->stackSpil = 0;
+ }
+ continue;
+ }
+
+ if (!bitVectBitValue (_G.regAssigned, sym->key))
+ continue;
+
+ /* special case check if this is an IFX &
+ the privious one was a pop and the
+ previous one was not spilt then keep track
+ of the symbol */
+ if (ic->op == IFX && ic->prev && ic->prev->op == IPOP && !ic->prev->parmPush && !OP_SYMBOL (IC_LEFT (ic->prev))->isspilt)
+ psym = OP_SYMBOL (IC_LEFT (ic->prev));
+
+ if (sym->nRegs)
+ {
+ int i = 0;
+
+ bitVectUnSetBit (_G.regAssigned, sym->key);
+
+ /* if the result of this one needs registers
+ and does not have it then assign it right
+ away */
+ if (IC_RESULT (ic) &&
+ !( SKIP_IC2 (ic) || /* not a special icode */
+ ic->op == JUMPTABLE ||
+ ic->op == IFX ||
+ ic->op == IPUSH ||
+ ic->op == IPOP ||
+ ic->op == RETURN ||
+ POINTER_SET (ic) ) &&
+ (result = OP_SYMBOL (IC_RESULT (ic))) && /* has a result */
+ result->liveTo > ic->seq && /* and will live beyond this */
+ result->liveTo <= ebp->lSeq && /* does not go beyond this block */
+ result->liveFrom == ic->seq && /* does not start before here */
+ result->regType == sym->regType && /* same register types */
+ result->nRegs && /* which needs registers */
+ !result->isspilt && /* and does not already have them */
+ !result->remat &&
+ !bitVectBitValue (_G.regAssigned, result->key) &&
+ /* the number of free regs + number of regs in this LR
+ can accomodate the what result Needs */
+ ((nfreeRegsType (result->regType) + sym->nRegs) >= result->nRegs))
+ {
+ for (i = 0; i < result->nRegs; i++)
+ if (i < sym->nRegs)
+ result->regs[i] = sym->regs[i];
+ else
+ result->regs[i] = getRegGpr (ic, ebp, result);
+
+ _G.regAssigned = bitVectSetBit (_G.regAssigned, result->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, result->key);
+ }
+
+ /* free the remaining */
+ for (; i < sym->nRegs; i++)
+ {
+ if (psym)
+ {
+ if (!symHasReg (psym, sym->regs[i]))
+ freeReg (sym->regs[i]);
+ }
+ else
+ freeReg (sym->regs[i]);
+ }
+ }
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* reassignLR - reassign this to registers */
+/*-----------------------------------------------------------------*/
+static void
+reassignLR (operand * op)
+{
+ symbol *sym = OP_SYMBOL (op);
+ int i;
+
+ /* not spilt any more */
+ sym->isspilt = sym->spillA = sym->blockSpil = sym->remainSpil = 0;
+ bitVectUnSetBit (_G.spiltSet, sym->key);
+
+ _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
+
+ _G.blockSpil--;
+
+ for (i = 0; i < sym->nRegs; i++)
+ sym->regs[i]->isFree = 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* willCauseSpill - determines if allocating will cause a spill */
+/*-----------------------------------------------------------------*/
+static int
+willCauseSpill (int nr, int rt)
+{
+ /* first check if there are any available registers
+ of the type required */
+ if (rt == REG_PTR)
+ {
+ /* special case for pointer type
+ if pointer type not available then
+ check for type gpr */
+ if (nFreeRegs (rt) >= nr)
+ return 0;
+ if (nFreeRegs (REG_GPR) >= nr)
+ return 0;
+ }
+ else if (rt == REG_BIT)
+ {
+ if (nFreeRegs (rt) >= nr)
+ return 0;
+ }
+ else
+ {
+ if (mcs51_ptrRegReq)
+ {
+ if (nFreeRegs (rt) >= nr)
+ return 0;
+ }
+ else
+ {
+ if (nFreeRegs (REG_PTR) + nFreeRegs (REG_GPR) >= nr)
+ return 0;
+ }
+ }
+
+ /* it will cause a spil */
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* positionRegs - the allocator can allocate same registers to */
+/* result and operand, if this happens make sure they are in the */
+/* same position as the operand otherwise chaos results */
+/*-----------------------------------------------------------------*/
+static int
+positionRegs (symbol * result, symbol * opsym, int chOp)
+{
+ int count = min (result->nRegs, opsym->nRegs);
+ int i, j = 0, shared = 0;
+ int change = 0;
+
+ /* if the result has been spilt then cannot share */
+ if (opsym->isspilt)
+ return 0;
+
+ for (;;)
+ {
+ shared = 0;
+ /* first make sure that they actually share */
+ for (i = 0; i < count; i++)
+ for (j = 0; j < count; j++)
+ if (result->regs[i] == opsym->regs[j] && i != j)
+ {
+ shared = 1;
+ goto xchgPositions;
+ }
+xchgPositions:
+ if (shared)
+ if (!chOp)
+ {
+ reg_info *tmp = result->regs[i];
+ result->regs[i] = result->regs[j];
+ result->regs[j] = tmp;
+ change++;
+ }
+ else
+ {
+ reg_info *tmp = opsym->regs[i];
+ opsym->regs[i] = opsym->regs[j];
+ opsym->regs[j] = tmp;
+ change++;
+ }
+ else
+ return change;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* verifyRegsAssigned - make sure an iTemp is properly initialized; */
+/* it should either have registers or have beed spilled. Otherwise, */
+/* there was an uninitialized variable, so just spill this to get */
+/* the operand in a valid state. */
+/*------------------------------------------------------------------*/
+static void
+verifyRegsAssigned (operand * op, iCode * ic)
+{
+ symbol *sym;
+
+ if (!op)
+ return;
+ if (!IS_ITEMP (op))
+ return;
+
+ sym = OP_SYMBOL (op);
+ if (sym->isspilt)
+ return;
+ if (!sym->nRegs)
+ return;
+ if (sym->regs[0])
+ return;
+
+ werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT, sym->prereqv ? sym->prereqv->name : sym->name);
+ spillThis (sym);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* serialRegAssign - serially allocate registers to the variables */
+/*-----------------------------------------------------------------*/
+static void
+serialRegAssign (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ /* for all blocks */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel))
+ continue;
+
+ /* for all instructions do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ updateRegUsage (ic);
+
+ /* if this is an ipop that means some live
+ range will have to be assigned again */
+ if (ic->op == IPOP)
+ reassignLR (IC_LEFT (ic));
+
+ /* if result is present && is a true symbol */
+ if (IC_RESULT (ic) && ic->op != IFX && IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+ OP_SYMBOL (IC_RESULT (ic))->allocreq++;
+ }
+
+ /* take away registers from live
+ ranges that end at this instruction */
+ deassignLRs (ic, ebbs[i]);
+
+ /* some don't need registers */
+ if (SKIP_IC2 (ic) ||
+ ic->op == JUMPTABLE ||
+ ic->op == IFX ||
+ ic->op == IPUSH ||
+ ic->op == IPOP ||
+ (IC_RESULT (ic) && POINTER_SET (ic)))
+ {
+ continue;
+ }
+
+ /* now we need to allocate registers only for the result */
+ if (IC_RESULT (ic))
+ {
+ symbol *sym = OP_SYMBOL (IC_RESULT (ic));
+ bitVect *spillable;
+ int willCS;
+ int j;
+ int ptrRegSet = 0;
+
+ /* Make sure any spill location is definitely allocated */
+ if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq)
+ {
+ sym->usl.spillLoc->allocreq++;
+ }
+
+ /* if it does not need or is spilt
+ or is already assigned to registers
+ or will not live beyond this instructions */
+ if (!sym->nRegs || sym->isspilt || bitVectBitValue (_G.regAssigned, sym->key) || sym->liveTo <= ic->seq)
+ {
+ continue;
+ }
+
+ /* do not try to spil bit registers as it won't work */
+ if (sym->regType != REG_BIT)
+ {
+ /* if some liverange has been spilt at the block level
+ and this one live beyond this block then spil this
+ to be safe */
+ if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq)
+ {
+ spillThis (sym);
+ continue;
+ }
+
+ willCS = willCauseSpill (sym->nRegs, sym->regType);
+ /* if this is a bit variable then don't use precious registers
+ along with expensive bit-to-char conversions but just spill
+ it */
+ if (willCS && SPEC_NOUN (sym->etype) == V_BIT)
+ {
+ spillThis (sym);
+ continue;
+ }
+
+ /* if trying to allocate this will cause
+ a spill and there is nothing to spill
+ or this one is rematerializable then
+ spill this one */
+ spillable = computeSpillable (ic);
+ if (sym->remat || (willCS && bitVectIsZero (spillable)))
+ {
+ spillThis (sym);
+ continue;
+ }
+
+ /* If the live range preceeds the point of definition
+ then ideally we must take into account registers that
+ have been allocated after sym->liveFrom but freed
+ before ic->seq. This is complicated, so spill this
+ symbol instead and let fillGaps handle the allocation. */
+ if (sym->liveFrom < ic->seq)
+ {
+ spillThis (sym);
+ continue;
+ }
+
+ /* if it has a spillocation & is used less than
+ all other live ranges then spill this */
+ if (willCS)
+ {
+ if (sym->usl.spillLoc)
+ {
+ symbol *leastUsed = leastUsedLR (liveRangesWith (spillable,
+ allLRs, ebbs[i], ic));
+ if (leastUsed && leastUsed->used > sym->used)
+ {
+ spillThis (sym);
+ continue;
+ }
+ }
+ else
+ {
+ /* if none of the liveRanges have a spillLocation then better
+ to spill this one than anything else already assigned to registers */
+ if (liveRangesWith (spillable, noSpilLoc, ebbs[i], ic))
+ {
+ /* if this is local to this block then we might find a block spil */
+ if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq))
+ {
+ spillThis (sym);
+ continue;
+ }
+ }
+ }
+ }
+ }
+ /* if we need ptr regs for the right side
+ then mark it */
+ if (POINTER_GET (ic) && IS_SYMOP (IC_LEFT (ic))
+ && getSize (OP_SYMBOL (IC_LEFT (ic))->type) <= (unsigned int) NEARPTRSIZE)
+ {
+ mcs51_ptrRegReq++;
+ ptrRegSet = 1;
+ }
+ if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && SPEC_OCLS (OP_SYMBOL (IC_LEFT (ic))->etype) == idata)
+ {
+ mcs51_ptrRegReq++;
+ ptrRegSet = 1;
+ }
+ if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && SPEC_OCLS (OP_SYMBOL (IC_RIGHT (ic))->etype) == idata)
+ {
+ mcs51_ptrRegReq++;
+ ptrRegSet = 1;
+ }
+
+ /* else we assign registers to it */
+ _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
+
+ for (j = 0; j < sym->nRegs; j++)
+ {
+ sym->regs[j] = NULL;
+ if (sym->regType == REG_PTR)
+ sym->regs[j] = getRegPtr (ic, ebbs[i], sym);
+ else
+ {
+ if (sym->regType == REG_BIT) /* Try to allocate to bit register if possible */
+ sym->regs[j] = getRegBitTry (sym);
+ if (ic->op == CAST && IS_SYMOP (IC_RIGHT (ic)))
+ {
+ symbol *right = OP_SYMBOL (IC_RIGHT (ic));
+
+ if (right->regs[j] && (right->regType != REG_BIT))
+ sym->regs[j] = allocThisReg (right->regs[j]);
+ }
+ if (!sym->regs[j])
+ sym->regs[j] = getRegGpr (ic, ebbs[i], sym);
+ }
+
+ /* if the allocation failed which means
+ this was spilt then break */
+ if (!sym->regs[j])
+ {
+ int i;
+ for (i = 0; i < sym->nRegs; i++)
+ sym->regs[i] = NULL;
+ break;
+ }
+ }
+
+ /* for debugging prefer to keep the sym in ascending
+ registers so sort them by address */
+ if (sym->regs[0])
+ {
+ for (j = 0; j < sym->nRegs - 1; j++)
+ {
+ int k;
+ for (k=j+1; k<sym->nRegs; k++)
+ {
+ if (sym->regs[j]->offset > sym->regs[k]->offset)
+ {
+ reg_info *tmp = sym->regs[j];
+ sym->regs[j] = sym->regs[k];
+ sym->regs[k] = tmp;
+ }
+ }
+ }
+ }
+
+ if (!POINTER_SET (ic) && !POINTER_GET (ic))
+ {
+ /* if it shares registers with operands make sure
+ that they are in the same position */
+ if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->nRegs)
+ {
+ positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_LEFT (ic)), 0);
+ }
+ /* do the same for the right operand */
+ if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->nRegs)
+ {
+ positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_RIGHT (ic)), 0);
+ }
+ }
+
+ if (ptrRegSet)
+ {
+ mcs51_ptrRegReq--;
+ ptrRegSet = 0;
+ }
+ }
+ }
+ }
+
+ /* Check for and fix any problems with uninitialized operands */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel))
+ {
+ continue;
+ }
+
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ if (SKIP_IC2 (ic))
+ continue;
+
+ if (ic->op == IFX)
+ {
+ verifyRegsAssigned (IC_COND (ic), ic);
+ continue;
+ }
+
+ if (ic->op == JUMPTABLE)
+ {
+ verifyRegsAssigned (IC_JTCOND (ic), ic);
+ continue;
+ }
+
+ verifyRegsAssigned (IC_RESULT (ic), ic);
+ verifyRegsAssigned (IC_LEFT (ic), ic);
+ verifyRegsAssigned (IC_RIGHT (ic), ic);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* fillGaps - Try to fill in the Gaps left by Pass1 */
+/*-----------------------------------------------------------------*/
+static void
+fillGaps (void)
+{
+ symbol *sym = NULL;
+ int key = 0;
+ int pass;
+ iCode *ic = NULL;
+
+ if (getenv ("DISABLE_FILL_GAPS"))
+ return;
+
+ /* look for liveranges that were spilt by the allocator */
+ for (sym = hTabFirstItem (liveRanges, &key); sym; sym = hTabNextItem (liveRanges, &key))
+ {
+ int i;
+ int pdone = 0;
+
+ if (!sym->spillA || !sym->clashes || sym->remat)
+ continue;
+
+ /* if spilt in direct space the original rname is lost */
+ if (sym->usl.spillLoc && (IN_DIRSPACE (SPEC_OCLS (sym->usl.spillLoc->etype))))
+ continue;
+
+ /* find the liveRanges this one clashes with, that are
+ still assigned to registers & mark the registers as used */
+ for (i = 0; i < sym->clashes->size; i++)
+ {
+ int k;
+ symbol *clr;
+
+ if (bitVectBitValue (sym->clashes, i) == 0 || /* those that clash with this */
+ bitVectBitValue (_G.totRegAssigned, i) == 0) /* and are still assigned to registers */
+ continue;
+
+ clr = hTabItemWithKey (liveRanges, i);
+ assert (clr);
+
+ /* mark these registers as used */
+ for (k = 0; k < clr->nRegs; k++)
+ useReg (clr->regs[k]);
+ }
+
+ if (willCauseSpill (sym->nRegs, sym->regType))
+ {
+ /* NOPE :( clear all registers & and continue */
+ freeAllRegs ();
+ continue;
+ }
+
+ ic = NULL;
+ for (i = 0; i < sym->defs->size; i++)
+ {
+ if (bitVectBitValue (sym->defs, i))
+ {
+ if (!(ic = hTabItemWithKey (iCodehTab, i)))
+ continue;
+ if (ic->op == CAST)
+ break;
+ }
+ }
+
+ D (printf ("Attempting fillGaps on %s: [", sym->name));
+ /* THERE IS HOPE !!!! */
+ for (i = 0; i < sym->nRegs; i++)
+ {
+ if (sym->regType == REG_PTR)
+ sym->regs[i] = getRegPtrNoSpil ();
+ else if (sym->regType == REG_BIT)
+ sym->regs[i] = getRegBitNoSpil ();
+ else
+ {
+ sym->regs[i] = NULL;
+ if (ic && ic->op == CAST && IS_SYMOP (IC_RIGHT (ic)))
+ {
+ symbol *right = OP_SYMBOL (IC_RIGHT (ic));
+
+ if (right->regs[i])
+ sym->regs[i] = allocThisReg (right->regs[i]);
+ }
+ if (!sym->regs[i])
+ sym->regs[i] = getRegGprNoSpil ();
+ }
+ D (printf ("%s ", sym->regs[i]->name));
+ }
+ D (printf ("]\n"));
+
+ /* For all its definitions check if the registers
+ allocated needs positioning NOTE: we can position
+ only ONCE if more than One positioning required
+ then give up.
+ We may need to perform the checks twice; once to
+ position the registers as needed, the second to
+ verify any register repositioning is still
+ compatible.
+ */
+ sym->isspilt = 0;
+ for (pass = 0; pass < 2; pass++)
+ {
+ D (printf (" checking definitions\n"));
+ for (i = 0; i < sym->defs->size; i++)
+ {
+ if (bitVectBitValue (sym->defs, i))
+ {
+ if (!(ic = hTabItemWithKey (iCodehTab, i)))
+ continue;
+ D (printf (" ic->seq = %d\n", ic->seq));
+ if (SKIP_IC (ic))
+ continue;
+ assert (isSymbolEqual (sym, OP_SYMBOL (IC_RESULT (ic)))); /* just making sure */
+ /* if left is assigned to registers */
+ if (IS_SYMOP (IC_LEFT (ic)))
+ {
+ D (printf (" left = "));
+ D (printOperand (IC_LEFT (ic), NULL));
+ }
+ if (IS_SYMOP (IC_LEFT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_LEFT (ic))->key))
+ {
+ pdone += (positionRegs (sym, OP_SYMBOL (IC_LEFT (ic)), 0) > 0);
+ }
+ if (IS_SYMOP (IC_RIGHT (ic)))
+ {
+ D (printf (" right = "));
+ D (printOperand (IC_RIGHT (ic), NULL));
+ }
+ if (IS_SYMOP (IC_RIGHT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_RIGHT (ic))->key))
+ {
+ pdone += (positionRegs (sym, OP_SYMBOL (IC_RIGHT (ic)), 0) > 0);
+ }
+ D (printf (" pdone = %d\n", pdone));
+ if (pdone > 1)
+ break;
+ }
+ }
+ D (printf (" checking uses\n"));
+ for (i = 0; i < sym->uses->size; i++)
+ {
+ if (bitVectBitValue (sym->uses, i))
+ {
+ iCode *ic;
+ if (!(ic = hTabItemWithKey (iCodehTab, i)))
+ continue;
+ D (printf (" ic->seq = %d\n", ic->seq));
+ if (SKIP_IC (ic))
+ continue;
+ if (POINTER_SET (ic) || POINTER_GET (ic))
+ continue;
+
+ /* if result is assigned to registers */
+ if (IS_SYMOP (IC_RESULT (ic)))
+ {
+ D (printf (" result = "));
+ D (printOperand (IC_RESULT (ic), NULL));
+ }
+ if (IS_SYMOP (IC_RESULT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_RESULT (ic))->key))
+ {
+ pdone += (positionRegs (sym, OP_SYMBOL (IC_RESULT (ic)), 0) > 0);
+ }
+ D (printf (" pdone = %d\n", pdone));
+ if (pdone > 1)
+ break;
+ }
+ }
+ if (pdone == 0)
+ break; /* second pass only if regs repositioned */
+ if (pdone > 1)
+ break;
+ }
+ D (printf (" sym->regs = ["));
+ for (i = 0; i < sym->nRegs; i++)
+ D (printf ("%s ", sym->regs[i]->name));
+ D (printf ("]\n"));
+ /* had to position more than once GIVE UP */
+ if (pdone > 1)
+ {
+ /* UNDO all the changes we made to try this */
+ sym->isspilt = 1;
+ for (i = 0; i < sym->nRegs; i++)
+ {
+ sym->regs[i] = NULL;
+ }
+ freeAllRegs ();
+ D (printf
+ ("Fill Gap gave up due to positioning for %s in function %s\n", sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+ continue;
+ }
+ D (printf ("FILLED GAP for %s in function %s\n", sym->name, currFunc ? currFunc->name : "UNKNOWN"));
+
+ _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key);
+ sym->isspilt = sym->spillA = 0;
+ sym->usl.spillLoc->allocreq--;
+ freeAllRegs ();
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* findAllBitregs :- returns bit vector of all bit registers */
+/*-----------------------------------------------------------------*/
+static bitVect *
+findAllBitregs (void)
+{
+ bitVect *rmask = newBitVect (mcs51_nRegs);
+ int j;
+
+ for (j = 0; j < mcs51_nRegs; j++)
+ {
+ if (regs8051[j].type == REG_BIT)
+ rmask = bitVectSetBit (rmask, regs8051[j].rIdx);
+ }
+
+ return rmask;
+}
+
+/*-----------------------------------------------------------------*/
+/* mcs51_allBitregs :- returns bit vector of all bit registers */
+/*-----------------------------------------------------------------*/
+bitVect *
+mcs51_allBitregs (void)
+{
+ return _G.allBitregs;
+}
+
+/*-----------------------------------------------------------------*/
+/* findAllBankregs :- returns bit vector of all bank registers */
+/*-----------------------------------------------------------------*/
+static bitVect *
+findAllBankregs (void)
+{
+ bitVect *rmask = newBitVect (mcs51_nRegs);
+ int j;
+
+ for (j = 0; j < mcs51_nRegs; j++)
+ {
+ if ((regs8051[j].type == REG_GPR) || (regs8051[j].type == REG_PTR))
+ rmask = bitVectSetBit (rmask, regs8051[j].rIdx);
+ }
+
+ return rmask;
+}
+
+/*-----------------------------------------------------------------*/
+/* mcs51_allBankregs :- returns bit vector of all bank registers */
+/*-----------------------------------------------------------------*/
+bitVect *
+mcs51_allBankregs (void)
+{
+ return _G.allBankregs;
+}
+
+/*-----------------------------------------------------------------*/
+/* rUmaskForOp :- returns register mask for an operand */
+/*-----------------------------------------------------------------*/
+bitVect *
+mcs51_rUmaskForOp (operand * op)
+{
+ bitVect *rumask;
+ symbol *sym;
+ int j;
+
+ /* only temporaries are assigned registers */
+ if (!IS_ITEMP (op))
+ return NULL;
+
+ sym = OP_SYMBOL (op);
+
+ /* if spilt or no registers assigned to it
+ then nothing */
+ if (sym->isspilt || !sym->nRegs)
+ return NULL;
+
+ rumask = newBitVect (mcs51_nRegs);
+
+ for (j = 0; j < sym->nRegs; j++)
+ {
+ if (sym->regs[j]) /* EEP - debug */
+ rumask = bitVectSetBit (rumask, sym->regs[j]->rIdx);
+ }
+
+ return rumask;
+}
+
+/*-----------------------------------------------------------------*/
+/* regsUsedIniCode :- returns bit vector of registers used in iCode */
+/*-----------------------------------------------------------------*/
+static bitVect *
+regsUsedIniCode (iCode * ic)
+{
+ bitVect *rmask = newBitVect (mcs51_nRegs);
+
+ /* do the special cases first */
+ if (ic->op == IFX)
+ {
+ rmask = bitVectUnion (rmask, mcs51_rUmaskForOp (IC_COND (ic)));
+ goto ret;
+ }
+
+ /* for the jumptable */
+ if (ic->op == JUMPTABLE)
+ {
+ rmask = bitVectUnion (rmask, mcs51_rUmaskForOp (IC_JTCOND (ic)));
+ goto ret;
+ }
+
+ /* of all other cases */
+ if (IC_LEFT (ic))
+ rmask = bitVectUnion (rmask, mcs51_rUmaskForOp (IC_LEFT (ic)));
+
+ if (IC_RIGHT (ic))
+ rmask = bitVectUnion (rmask, mcs51_rUmaskForOp (IC_RIGHT (ic)));
+
+ if (IC_RESULT (ic))
+ rmask = bitVectUnion (rmask, mcs51_rUmaskForOp (IC_RESULT (ic)));
+
+ret:
+ return rmask;
+}
+
+/*-----------------------------------------------------------------*/
+/* createRegMask - for each instruction will determine the regsUsed */
+/*-----------------------------------------------------------------*/
+static void
+createRegMask (eBBlock ** ebbs, int count)
+{
+ int i;
+
+ /* for all blocks */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel))
+ continue;
+
+ /* for all instructions */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ int j;
+
+ if (SKIP_IC2 (ic) || !ic->rlive)
+ continue;
+
+ /* first mark the registers used in this
+ instruction */
+ ic->rUsed = regsUsedIniCode (ic);
+ _G.funcrUsed = bitVectUnion (_G.funcrUsed, ic->rUsed);
+
+ /* now create the register mask for those
+ registers that are in use : this is a
+ super set of ic->rUsed */
+ ic->rMask = newBitVect (mcs51_nRegs + 1);
+
+ /* for all live Ranges alive at this point */
+ for (j = 1; j < ic->rlive->size; j++)
+ {
+ symbol *sym;
+ int k;
+
+ /* if not alive then continue */
+ if (!bitVectBitValue (ic->rlive, j))
+ continue;
+
+ /* find the live range we are interested in */
+ if (!(sym = hTabItemWithKey (liveRanges, j)))
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "createRegMask cannot find live range");
+ fprintf (stderr, "\tmissing live range: key=%d\n", j);
+ exit (0);
+ }
+
+ /* if no register assigned to it */
+ if (!sym->nRegs || sym->isspilt)
+ continue;
+
+ /* for all the registers allocated to it */
+ for (k = 0; k < sym->nRegs; k++)
+ if (sym->regs[k])
+ ic->rMask = bitVectSetBit (ic->rMask, sym->regs[k]->rIdx);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* rematStr - returns the rematerialized string for a remat var */
+/*-----------------------------------------------------------------*/
+static char *
+rematStr (symbol * sym)
+{
+ iCode *ic = sym->rematiCode;
+ int offset = 0;
+ struct dbuf_s dbuf;
+
+ while (1)
+ {
+ /* if plus adjust offset to right hand side */
+ if (ic->op == '+')
+ {
+ offset += (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+
+ /* if minus adjust offset to right hand side */
+ if (ic->op == '-')
+ {
+ offset -= (int) operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+
+ /* cast then continue */
+ if (IS_CAST_ICODE (ic))
+ {
+ ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+ continue;
+ }
+ /* we reached the end */
+ break;
+ }
+
+ dbuf_init (&dbuf, 128);
+ if (offset)
+ {
+ dbuf_printf (&dbuf, "(%s %c 0x%04x)", OP_SYMBOL (IC_LEFT (ic))->rname, offset >= 0 ? '+' : '-', abs (offset) & 0xffff);
+ }
+ else
+ {
+ dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname);
+ }
+ return dbuf_detach_c_str (&dbuf);
+}
+
+/*------------------------------------------------------------------*/
+/* isBitVar - returns true if sym is a good candiate for allocation */
+/* to a bit */
+/*------------------------------------------------------------------*/
+static bool isFlagVar (symbol *sym)
+{
+ if (IS_BIT (sym->type))
+ return (true);
+
+ if (!(IS_SPEC(sym->type) && SPEC_NOUN (sym->type) == V_BOOL && !sym->addrtaken))
+ return (false);
+
+ bitVect *defs = bitVectCopy (sym->defs);
+ bitVect *uses = bitVectCopy (sym->uses);
+ int key;
+ unsigned int gooduses = 0;
+ unsigned int baduses = 0;
+
+ for (key = bitVectFirstBit (defs); key >= 0; key = bitVectFirstBit (defs))
+ {
+ bitVectUnSetBit (defs, key);
+
+ iCode *ic = hTabItemWithKey (iCodehTab, key);
+
+ if (ic->op == AND_OP || ic->op == OR_OP || ic->op == EQ_OP || ic->op == '<' || ic->op == '>' || ic->op == CAST || ic->op == '!')
+ gooduses++;
+ else if (ic->op == '=' &&
+ (IS_OP_LITERAL (IC_RIGHT (ic)) || IS_SYMOP (IC_RIGHT (ic)) && IS_BIT (OP_SYMBOL (IC_RIGHT (ic))->type)))
+ gooduses++;
+ else
+ baduses++;
+ }
+
+ for (key = bitVectFirstBit (uses); key >= 0; key = bitVectFirstBit (uses))
+ {
+ bitVectUnSetBit (uses, key);
+
+ iCode *ic = hTabItemWithKey (iCodehTab, key);
+
+ if (!ic) /* Shouldn't happen, but does */
+ continue;
+
+ if (ic->op == IFX || ic->op == '!' || ic->op == AND_OP || ic->op == OR_OP)
+ gooduses++;
+ else if (ic->op == BITWISEAND || ic->op == '|' || ic->op == '^')
+ gooduses++;
+ else if (ic->op == '=' && !POINTER_SET (ic) && IS_SYMOP (IC_RESULT (ic)) && IS_BIT (OP_SYMBOL (IC_RESULT (ic))->type))
+ gooduses++;
+ else
+ baduses++;
+ }
+
+ freeBitVect (defs);
+ freeBitVect (uses);
+
+ return (gooduses >= baduses * 2);
+}
+
+/*-----------------------------------------------------------------*/
+/* regTypeNum - computes the type & number of registers required */
+/*-----------------------------------------------------------------*/
+static void
+regTypeNum (eBBlock * ebbs)
+{
+ symbol *sym;
+ int k;
+ iCode *ic;
+
+ /* for each live range do */
+ for (sym = hTabFirstItem (liveRanges, &k); sym; sym = hTabNextItem (liveRanges, &k))
+ {
+ /* if used zero times then no registers needed */
+ if ((sym->liveTo - sym->liveFrom) == 0)
+ continue;
+
+ /* if the live range is a temporary */
+ if (sym->isitmp)
+ {
+ /* if the type is marked as a conditional */
+ if (sym->regType == REG_CND)
+ continue;
+
+ /* if used in return only then we don't
+ need registers */
+ if (sym->ruonly || sym->accuse)
+ {
+ if (IS_AGGREGATE (sym->type) || sym->isptr)
+ sym->type = aggrToPtr (sym->type, FALSE);
+ else if (IS_BIT (sym->type))
+ sym->regType = REG_CND;
+ continue;
+ }
+
+ /* if the symbol has only one definition &
+ that definition is a get_pointer */
+ if (bitVectnBitsOn (sym->defs) == 1 &&
+ (ic = hTabItemWithKey (iCodehTab, bitVectFirstBit (sym->defs))) &&
+ POINTER_GET (ic) && !IS_BITVAR (sym->etype) && (aggrToPtrDclType (operandType (IC_LEFT (ic)), FALSE) == POINTER))
+ {
+ if (ptrPseudoSymSafe (sym, ic))
+ {
+ char *s = rematStr (OP_SYMBOL (IC_LEFT (ic)));
+ ptrPseudoSymConvert (sym, ic, s);
+ Safe_free (s);
+ continue;
+ }
+
+ /* if in data space or idata space then try to
+ allocate pointer register */
+ }
+
+ /* if not then we require registers */
+ sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ?
+ getSize (sym->type = aggrToPtr (sym->type, FALSE)) : getSize (sym->type));
+
+ if (sym->nRegs > 8)
+ {
+ fprintf (stderr, "allocated more than 8 or 0 registers for type ");
+ printTypeChain (sym->type, stderr);
+ fprintf (stderr, "\n");
+ }
+
+ /* determine the type of register required */
+ if (sym->nRegs == 1 && IS_PTR (sym->type) && sym->uptr)
+ sym->regType = REG_PTR;
+ else if (isFlagVar (sym))
+ sym->regType = REG_BIT;
+ else
+ sym->regType = REG_GPR;
+ }
+ else
+ /* for the first run we don't provide */
+ /* registers for true symbols we will */
+ /* see how things go */
+ sym->nRegs = 0;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAllRegs - mark all registers as free */
+/*-----------------------------------------------------------------*/
+static void
+freeAllRegs ()
+{
+ int i;
+
+ for (i = 0; i < mcs51_nRegs; i++)
+ regs8051[i].isFree = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* deallocStackSpil - this will set the stack pointer back */
+/*-----------------------------------------------------------------*/
+static
+DEFSETFUNC (deallocStackSpil)
+{
+ symbol *sym = item;
+
+ deallocLocal (sym);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* farSpacePackable - returns the packable icode for far variables */
+/*-----------------------------------------------------------------*/
+static iCode *
+farSpacePackable (iCode * ic)
+{
+ iCode *dic;
+
+ /* go thru till we find a definition for the
+ symbol on the right */
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+ /* if the definition is a call then no */
+ if ((dic->op == CALL || dic->op == PCALL) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ {
+ return NULL;
+ }
+
+ /* if shift by unknown amount then not */
+ if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ return NULL;
+
+ /* if pointer get and size > 1 */
+ if (POINTER_GET (dic) && getSize (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)) > 1)
+ return NULL;
+
+ if (POINTER_SET (dic) && getSize (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)) > 1)
+ return NULL;
+
+ if (dic->op == IFX)
+ {
+ if (IC_COND (dic) && IS_TRUE_SYMOP (IC_COND (dic)) && isOperandInFarSpace (IC_COND (dic)))
+ return NULL;
+ }
+ else if (dic->op == JUMPTABLE)
+ {
+ if (IC_JTCOND (dic) && IS_TRUE_SYMOP (IC_JTCOND (dic)) && isOperandInFarSpace (IC_JTCOND (dic)))
+ return NULL;
+ }
+ else
+ {
+ /* if any tree is a true symbol in far space */
+ if (IC_RESULT (dic) && IS_TRUE_SYMOP (IC_RESULT (dic)) && isOperandInFarSpace (IC_RESULT (dic)))
+ return NULL;
+
+ if (IC_RIGHT (dic) &&
+ IS_TRUE_SYMOP (IC_RIGHT (dic)) &&
+ isOperandInFarSpace (IC_RIGHT (dic)) && !isOperandEqual (IC_RIGHT (dic), IC_RESULT (ic)))
+ return NULL;
+
+ if (IC_LEFT (dic) &&
+ IS_TRUE_SYMOP (IC_LEFT (dic)) &&
+ isOperandInFarSpace (IC_LEFT (dic)) && !isOperandEqual (IC_LEFT (dic), IC_RESULT (ic)))
+ return NULL;
+ }
+
+ if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (dic)))
+ {
+ if ((dic->op == LEFT_OP || dic->op == RIGHT_OP || dic->op == '-') && IS_OP_LITERAL (IC_RIGHT (dic)))
+ return NULL;
+ else
+ return dic;
+ }
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegsForAssign - register reduction for assignment */
+/*-----------------------------------------------------------------*/
+static int
+packRegsForAssign (iCode * ic, eBBlock * ebp)
+{
+ iCode *dic, *sic;
+
+ if (!IS_ITEMP (IC_RIGHT (ic)) || OP_SYMBOL (IC_RIGHT (ic))->isind || OP_LIVETO (IC_RIGHT (ic)) > ic->seq)
+ {
+ return 0;
+ }
+
+ /* if the true symbol is defined in far space or on stack
+ then we should not since this will increase register pressure */
+ if (isOperandInFarSpace (IC_RESULT (ic)) && !farSpacePackable (ic))
+ {
+ return 0;
+ }
+
+ /* find the definition of iTempNN scanning backwards if we find
+ a use of the true symbol before we find the definition then
+ we cannot */
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+ int crossedCall = 0;
+
+ /* We can pack across a function call only if it's a local */
+ /* variable or our parameter. Never pack global variables */
+ /* or parameters to a function we call. */
+ if ((dic->op == CALL || dic->op == PCALL))
+ {
+ if (!OP_SYMBOL (IC_RESULT (ic))->ismyparm && !OP_SYMBOL (IC_RESULT (ic))->islocal)
+ {
+ crossedCall = 1;
+ }
+ }
+
+ if (dic->op == INLINEASM)
+ {
+ dic = NULL;
+ break;
+ }
+
+ /* Don't move an assignment out of a critical block */
+ if (dic->op == CRITICAL)
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (SKIP_IC2 (dic))
+ continue;
+
+ if (dic->op == IFX)
+ {
+ if (IS_SYMOP (IC_COND (dic)) &&
+ (IC_COND (dic)->key == IC_RESULT (ic)->key || IC_COND (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+ }
+ else
+ {
+ if (IS_TRUE_SYMOP (IC_RESULT (dic)) && IS_OP_VOLATILE (IC_RESULT (dic)))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
+ {
+ if (POINTER_SET (dic))
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_RIGHT (dic)) &&
+ (IC_RIGHT (dic)->key == IC_RESULT (ic)->key || IC_RIGHT (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_LEFT (dic)) &&
+ (IC_LEFT (dic)->key == IC_RESULT (ic)->key || IC_LEFT (dic)->key == IC_RIGHT (ic)->key))
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RESULT (ic)->key)
+ {
+ dic = NULL;
+ break;
+ }
+
+ if (crossedCall)
+ {
+ dic = NULL;
+ break;
+ }
+ }
+ }
+
+ if (!dic)
+ return 0; /* did not find */
+
+ /* if assignment then check that right is not a bit */
+ if (ASSIGNMENT (ic) && !POINTER_SET (ic))
+ {
+ sym_link *etype = operandType (IC_RESULT (dic));
+ if (IS_BITFIELD (etype))
+ {
+ /* if result is a bit too then it's ok */
+ etype = operandType (IC_RESULT (ic));
+ if (!IS_BITFIELD (etype))
+ {
+ return 0;
+ }
+ }
+ }
+
+ /* if the result is on stack or iaccess then it must be
+ the same atleast one of the operands */
+ if (OP_SYMBOL (IC_RESULT (ic))->onStack || OP_SYMBOL (IC_RESULT (ic))->iaccess)
+ {
+ /* the operation has only one symbol
+ operator then we can pack */
+ if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic))))
+ goto pack;
+
+ if (!((IC_LEFT (dic) &&
+ IC_RESULT (ic)->key == IC_LEFT (dic)->key) || (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key)))
+ return 0;
+ }
+pack:
+ /* found the definition */
+
+ /* delete from liverange table also
+ delete from all the points inbetween and the new
+ one */
+ for (sic = dic; sic != ic; sic = sic->next)
+ {
+ bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key);
+ if (IS_ITEMP (IC_RESULT (dic)))
+ bitVectSetBit (sic->rlive, IC_RESULT (dic)->key);
+ }
+
+ /* replace the result with the result of */
+ /* this assignment and remove this assignment */
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key);
+ ReplaceOpWithCheaperOp (&IC_RESULT (dic), IC_RESULT (ic));
+
+ if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq)
+ {
+ OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq;
+ }
+ // TODO: and the otherway around?
+
+ remiCodeFromeBBlock (ebp, ic);
+ bitVectUnSetBit (OP_DEFS (IC_RESULT (ic)), ic->key);
+ hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
+ OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
+ return 1;
+}
+
+/*------------------------------------------------------------------*/
+/* findAssignToSym : scanning backwards looks for first assig found */
+/*------------------------------------------------------------------*/
+static iCode *
+findAssignToSym (operand * op, iCode * ic)
+{
+ iCode *dic;
+
+ /* This routine is used to find sequences like
+ iTempAA = FOO;
+ ...; (intervening ops don't use iTempAA or modify FOO)
+ blah = blah + iTempAA;
+
+ and eliminate the use of iTempAA, freeing up its register for
+ other uses.
+ */
+
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+ /* if definition by assignment */
+ if (dic->op == '=' && !POINTER_SET (dic) && IC_RESULT (dic)->key == op->key
+/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */
+ )
+ break; /* found where this temp was defined */
+
+ /* if we find an usage then we cannot delete it */
+
+ if (dic->op == IFX)
+ {
+ if (IC_COND (dic) && IC_COND (dic)->key == op->key)
+ return NULL;
+ }
+ else if (dic->op == JUMPTABLE)
+ {
+ if (IC_JTCOND (dic) && IC_JTCOND (dic)->key == op->key)
+ return NULL;
+ }
+ else
+ {
+ if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key)
+ return NULL;
+
+ if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key)
+ return NULL;
+
+ if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key)
+ return NULL;
+ }
+ }
+
+ if (!dic)
+ return NULL; /* didn't find any assignment to op */
+
+ /* we are interested only if defined in far space */
+ /* or in stack space in case of + & - */
+
+ /* if assigned to a non-symbol then don't repack regs */
+ if (!IS_SYMOP (IC_RIGHT (dic)))
+ return NULL;
+
+ /* if the symbol is volatile then we should not */
+ if (isOperandVolatile (IC_RIGHT (dic), TRUE))
+ return NULL;
+ /* XXX TODO --- should we be passing FALSE to isOperandVolatile()?
+ What does it mean for an iTemp to be volatile, anyway? Passing
+ TRUE is more cautious but may prevent possible optimizations */
+
+ /* if the symbol is in far space then we should not */
+ if (isOperandInFarSpace (IC_RIGHT (dic)))
+ return NULL;
+
+ /* for + & - operations make sure that
+ if it is on the stack it is the same
+ as one of the three operands */
+ if ((ic->op == '+' || ic->op == '-') && OP_SYMBOL (IC_RIGHT (dic))->onStack)
+ {
+ if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key &&
+ IC_LEFT (ic)->key != IC_RIGHT (dic)->key && IC_RIGHT (ic)->key != IC_RIGHT (dic)->key)
+ return NULL;
+ }
+
+ /* now make sure that the right side of dic
+ is not defined between ic & dic */
+ if (dic)
+ {
+ iCode *sic = dic->next;
+
+ for (; sic != ic; sic = sic->next)
+ if (IC_RESULT (sic) && IC_RESULT (sic)->key == IC_RIGHT (dic)->key)
+ return NULL;
+ }
+
+ return dic;
+}
+
+/*-----------------------------------------------------------------*/
+/* reassignAliasedSym - used by packRegsForSupport to replace */
+/* redundant iTemp with equivalent symbol */
+/*-----------------------------------------------------------------*/
+static void
+reassignAliasedSym (eBBlock * ebp, iCode * assignment, iCode * use, operand * op)
+{
+ iCode *ic;
+ unsigned oldSymKey, newSymKey;
+
+ oldSymKey = op->key;
+ newSymKey = IC_RIGHT (assignment)->key;
+
+ /* only track live ranges of compiler-generated temporaries */
+ if (!IS_ITEMP (IC_RIGHT (assignment)))
+ newSymKey = 0;
+
+ /* update the live-value bitmaps */
+ for (ic = assignment; ic != use; ic = ic->next)
+ {
+ bitVectUnSetBit (ic->rlive, oldSymKey);
+ if (newSymKey != 0)
+ ic->rlive = bitVectSetBit (ic->rlive, newSymKey);
+ }
+
+ /* update the sym of the used operand */
+ OP_SYMBOL (op) = OP_SYMBOL (IC_RIGHT (assignment));
+ op->key = OP_SYMBOL (op)->key;
+ OP_SYMBOL (op)->accuse = 0;
+
+ /* update the sym's liverange */
+ if (OP_LIVETO (op) < ic->seq)
+ setToRange (op, ic->seq, FALSE);
+
+ /* remove the assignment iCode now that its result is unused */
+ remiCodeFromeBBlock (ebp, assignment);
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (assignment))->defs, assignment->key);
+ hTabDeleteItem (&iCodehTab, assignment->key, assignment, DELETE_ITEM, NULL);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* packRegsForSupport :- reduce some registers for support calls */
+/*-----------------------------------------------------------------*/
+static int
+packRegsForSupport (iCode * ic, eBBlock * ebp)
+{
+ iCode *dic;
+
+ /* for the left & right operand :- look to see if the
+ left was assigned a true symbol in far space in that
+ case replace them */
+
+ if (IS_ITEMP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq)
+ {
+ dic = findAssignToSym (IC_LEFT (ic), ic);
+
+ if (dic)
+ {
+ /* found it we need to remove it from the block */
+ reassignAliasedSym (ebp, dic, ic, IC_LEFT (ic));
+ return 1;
+ }
+ }
+
+ /* do the same for the right operand */
+ if (IS_ITEMP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq)
+ {
+ iCode *dic = findAssignToSym (IC_RIGHT (ic), ic);
+
+ if (dic)
+ {
+ /* if this is a subtraction & the result
+ is a true symbol in far space then don't pack */
+ if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic)))
+ {
+ sym_link *etype = getSpec (operandType (IC_RESULT (dic)));
+ if (IN_FARSPACE (SPEC_OCLS (etype)))
+ return 0;
+ }
+ /* found it we need to remove it from the block */
+ reassignAliasedSym (ebp, dic, ic, IC_RIGHT (ic));
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* packRegsForOneuse : - will reduce some registers for single Use */
+/*-----------------------------------------------------------------*/
+static iCode *
+packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
+{
+ iCode *dic, *sic;
+ sym_link *type;
+ int usingCarry=0;
+
+ /* if returning a literal then do nothing */
+ if (!IS_ITEMP (op))
+ return NULL;
+
+ /* if rematerializable or already return use then do nothing */
+ if (OP_SYMBOL (op)->remat || OP_SYMBOL (op)->ruonly)
+ return NULL;
+
+ /* only upto 2 bytes since we cannot predict
+ the usage of b, & acc */
+ type = operandType (op);
+ if (getSize (type) > (fReturnSizeMCS51 - 2))
+ return NULL;
+ usingCarry = IS_BIT(type);
+
+ if (ic->op != RETURN && ic->op != SEND && !POINTER_SET (ic) && !POINTER_GET (ic))
+ return NULL;
+
+ if (ic->op == SEND && ic->argreg != 1)
+ return NULL;
+
+ /* this routine will mark the symbol as used in one
+ instruction use only && if the definition is local
+ (ie. within the basic block) && has only one definition &&
+ that definition is either a return value from a
+ function or does not contain any variables in
+ far space */
+ if (bitVectnBitsOn (OP_USES (op)) > 1)
+ return NULL;
+
+ /* if it has only one definition */
+ if (bitVectnBitsOn (OP_DEFS (op)) > 1)
+ return NULL; /* has more than one definition */
+
+ /* get that definition */
+ if (!(dic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_DEFS (op)))))
+ return NULL;
+
+ /* if that only usage is a cast */
+ if (dic->op == CAST)
+ {
+ /* to a bigger type */
+ if (getSize (OP_SYM_TYPE (IC_RESULT (dic))) > getSize (OP_SYM_TYPE (IC_RIGHT (dic))))
+ {
+ /* then we can not, since we cannot predict the usage of b & acc */
+ return NULL;
+ }
+ }
+
+ /* found the definition now check if it is local */
+ if (dic->seq < ebp->fSeq || dic->seq > ebp->lSeq)
+ return NULL; /* non-local */
+
+ /* now check if it is the return from a function call */
+ if (dic->op == CALL || dic->op == PCALL)
+ {
+ if (ic->op != SEND && ic->op != RETURN && !POINTER_SET (ic) && !POINTER_GET (ic))
+ {
+ OP_SYMBOL (op)->ruonly = 1;
+ return dic;
+ }
+ }
+ else
+ {
+ /* otherwise check that the definition does
+ not contain any symbols in far space */
+ if (isOperandInFarSpace (IC_LEFT (dic)) ||
+ isOperandInFarSpace (IC_RIGHT (dic)) || IS_OP_RUONLY (IC_LEFT (ic)) || IS_OP_RUONLY (IC_RIGHT (ic)))
+ {
+ return NULL;
+ }
+
+ /* if pointer set then make sure the pointer is one byte */
+ if (POINTER_SET (dic) && !IS_SMALL_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) && !IS_SMALL_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+ }
+
+ /* Make sure no overlapping liverange is already assigned to DPTR */
+ if (OP_SYMBOL (op)->clashes)
+ {
+ symbol *sym;
+ int i;
+
+ for (i = 0; i < OP_SYMBOL (op)->clashes->size; i++)
+ {
+ if (bitVectBitValue (OP_SYMBOL (op)->clashes, i))
+ {
+ sym = hTabItemWithKey (liveRanges, i);
+ if (sym->ruonly)
+ return NULL;
+ }
+ }
+ }
+
+ sic = dic;
+
+ if (ic->op == SEND)
+ {
+ /* look for the call to extend following
+ far space search to include all parameters.
+ see bug 3004918 */
+ for (; ic; ic = ic->next)
+ if (ic->op == CALL || ic->op == PCALL)
+ break;
+ if (!ic) /* not found */
+ return NULL;
+ }
+
+ if (ic->op == PCALL && !IS_SMALL_PTR(aggrToPtr(operandType(IC_LEFT(ic)), FALSE)))
+ return NULL;
+
+ /* make sure the intervening instructions
+ don't have anything in far space */
+ for (dic = dic->next; dic && dic != ic && sic != ic; dic = dic->next)
+ {
+ /* if there is an intervening function call then no */
+ if (dic->op == CALL || dic->op == PCALL)
+ return NULL;
+ /* if pointer set then make sure the pointer
+ is one byte */
+ if (POINTER_SET (dic) && !IS_SMALL_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) && !IS_SMALL_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+
+ /* if address of & the result is remat then okay */
+ if (dic->op == ADDRESS_OF && OP_SYMBOL (IC_RESULT (dic))->remat)
+ continue;
+
+ /* if operand has size of three or more & this
+ operation is a '*','/' or '%' then 'b' may
+ cause a problem */
+ if ((dic->op == '%' || dic->op == '/' || dic->op == '*') && getSize (operandType (op)) >= 3)
+ return NULL;
+
+ /* if left or right or result is in far space */
+ if (isOperandInFarSpace (IC_LEFT (dic)) ||
+ isOperandInFarSpace (IC_RIGHT (dic)) ||
+ isOperandInFarSpace (IC_RESULT (dic)) ||
+ IS_OP_RUONLY (IC_LEFT (dic)) || IS_OP_RUONLY (IC_RIGHT (dic)) || IS_OP_RUONLY (IC_RESULT (dic)))
+ {
+ return NULL;
+ }
+ /* if left or right or result is on stack */
+ if (isOperandOnStack (IC_LEFT (dic)) || isOperandOnStack (IC_RIGHT (dic)) || isOperandOnStack (IC_RESULT (dic)))
+ {
+ return NULL;
+ }
+ if (usingCarry)
+ {
+ if (isOperandInBitSpace (IC_LEFT (dic)) ||
+ isOperandInBitSpace (IC_RIGHT (dic)) ||
+ isOperandInBitSpace (IC_RESULT (dic)))
+ {
+ return NULL;
+ }
+ if (dic->op != SEND || dic->op != IPUSH || dic->op != '=')
+ {
+ return NULL;
+ }
+ }
+ }
+
+ OP_SYMBOL (op)->ruonly = 1;
+ return sic;
+}
+
+/*-----------------------------------------------------------------*/
+/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */
+/*-----------------------------------------------------------------*/
+static bool
+isBitwiseOptimizable (iCode * ic)
+{
+ sym_link *ltype = getSpec (operandType (IC_LEFT (ic)));
+ sym_link *rtype = getSpec (operandType (IC_RIGHT (ic)));
+
+ /* bitwise operations are considered optimizable
+ under the following conditions (Jean-Louis VERN)
+
+ x & lit
+ bit & bit
+ bit & x
+ bit ^ bit
+ bit ^ x
+ x ^ lit
+ x | lit
+ bit | bit
+ bit | x
+ */
+ if (IS_LITERAL (rtype) || (IS_BITVAR (ltype) && IN_BITSPACE (SPEC_OCLS (ltype))))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* isCommutativeOp - tests whether this op cares what order its */
+/* operands are in */
+/*-----------------------------------------------------------------*/
+bool
+isCommutativeOp (unsigned int op)
+{
+ if (op == '+' || op == '*' || op == EQ_OP || op == '^' || op == '|' || op == BITWISEAND)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandUsesAcc - determines whether the code generated for this */
+/* operand will have to use the accumulator */
+/*-----------------------------------------------------------------*/
+bool
+operandUsesAcc (operand * op, bool allowBitspace)
+{
+ if (!op)
+ return FALSE;
+
+ if (IS_SYMOP (op))
+ {
+ symbol *sym = OP_SYMBOL (op);
+ memmap *symspace;
+
+ if (sym->accuse)
+ return TRUE; /* duh! */
+
+ if (IN_STACK (sym->etype) || sym->onStack || (SPIL_LOC (op) && SPIL_LOC (op)->onStack))
+ return TRUE; /* acc is used to calc stack offset */
+
+ if (IS_ITEMP (op))
+ {
+ if (SPIL_LOC (op))
+ {
+ sym = SPIL_LOC (op); /* if spilled, look at spill location */
+ }
+ else
+ {
+ return FALSE; /* more checks? */
+ }
+ }
+
+ symspace = SPEC_OCLS (sym->etype);
+
+ if (sym->iaccess && symspace->paged)
+ return TRUE; /* must fetch paged indirect sym via accumulator */
+
+ if (!allowBitspace && IN_BITSPACE (symspace))
+ return TRUE; /* fetching bit vars uses the accumulator */
+
+ if (IN_FARSPACE (symspace) || IN_CODESPACE (symspace))
+ return TRUE; /* fetched via accumulator and dptr */
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegsForAccUse - pack registers for acc use */
+/*-----------------------------------------------------------------*/
+static void
+packRegsForAccUse (iCode * ic)
+{
+ iCode *uic;
+
+ /* if this is an aggregate, e.g. a one byte char array */
+ if (IS_AGGREGATE (operandType (IC_RESULT (ic))))
+ return;
+
+ /* if we are calling a reentrant function that has stack parameters */
+ if (ic->op == CALL && IFFUNC_ISREENT (operandType (IC_LEFT (ic))) && FUNC_HASSTACKPARM (operandType (IC_LEFT (ic))))
+ return;
+
+ if (ic->op == PCALL &&
+ IFFUNC_ISREENT (operandType (IC_LEFT (ic))->next) && FUNC_HASSTACKPARM (operandType (IC_LEFT (ic))->next))
+ return;
+
+ /* if + or - then it has to be one byte result */
+ if ((ic->op == '+' || ic->op == '-') && getSize (operandType (IC_RESULT (ic))) > 1)
+ return;
+
+ /* if shift operation make sure right side is not a literal */
+ if (ic->op == RIGHT_OP && (isOperandLiteral (IC_RIGHT (ic)) || getSize (operandType (IC_RESULT (ic))) > 1))
+ return;
+
+ if (ic->op == LEFT_OP && (isOperandLiteral (IC_RIGHT (ic)) || getSize (operandType (IC_RESULT (ic))) > 1))
+ return;
+
+ if (IS_BITWISE_OP (ic) && getSize (operandType (IC_RESULT (ic))) > 1)
+ return;
+
+ /* has only one definition */
+ if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
+ return;
+
+ /* has only one use */
+ if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1)
+ return;
+
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
+ return;
+
+ if (ic->next != uic)
+ return;
+
+ /* if it is a conditional branch then we definitely can */
+ if (uic->op == IFX)
+ goto accuse;
+
+ if (uic->op == JUMPTABLE)
+ return;
+
+ if (POINTER_SET (uic) && getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
+ return;
+
+ /* if the usage is not an assignment
+ or an arithmetic / bitwise / shift operation then not */
+ if (uic->op != '=' && !IS_ARITHMETIC_OP (uic) && !IS_BITWISE_OP (uic) && uic->op != LEFT_OP && uic->op != RIGHT_OP)
+ return;
+
+ /* if shift operation make sure right side is not a literal */
+ /* WIML: Why is this? */
+ if (uic->op == RIGHT_OP && (isOperandLiteral (IC_RIGHT (uic)) || getSize (operandType (IC_RESULT (uic))) > 1))
+ return;
+ if (uic->op == LEFT_OP && (isOperandLiteral (IC_RIGHT (uic)) || getSize (operandType (IC_RESULT (uic))) > 1))
+ return;
+
+ /* make sure that the result of this icode is not on the
+ stack, since acc is used to compute stack offset */
+#if 0
+ if (IS_TRUE_SYMOP (IC_RESULT (uic)) && OP_SYMBOL (IC_RESULT (uic))->onStack)
+ return;
+#else
+ if (isOperandOnStack (IC_RESULT (uic)))
+ return;
+#endif
+
+ /* if the usage has only one operand then we can */
+ if (IC_LEFT (uic) == NULL || IC_RIGHT (uic) == NULL)
+ goto accuse;
+
+ /* if the other operand uses the accumulator then we cannot */
+ if ((IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
+ operandUsesAcc (IC_RIGHT (uic), IS_BIT (operandType (IC_LEFT (uic))))) ||
+ (IC_RIGHT (uic)->key == IC_RESULT (ic)->key && operandUsesAcc (IC_LEFT (uic), IS_BIT (operandType (IC_RIGHT (uic))))))
+ return;
+
+ /* make sure this is on the left side if not commutative */
+ /* except for '-', which has been written to be able to
+ handle reversed operands */
+ if (!(isCommutativeOp (ic->op) || ic->op == '-') && IC_LEFT (uic)->key != IC_RESULT (ic)->key)
+ return;
+
+ /* Sign handling will overwrite a */
+ if (uic->op == '*' && getSize (operandType (IC_RESULT (uic))) > 1 &&
+ (!SPEC_USIGN (getSpec (operandType (IC_LEFT (uic)))) || !SPEC_USIGN (getSpec (operandType (IC_RIGHT (uic))))))
+ return;
+ if ((uic->op == '/' || uic->op == '%') &&
+ (!SPEC_USIGN (getSpec (operandType (IC_LEFT (uic)))) || !SPEC_USIGN (getSpec (operandType (IC_RIGHT (uic))))))
+ return;
+
+#if 0
+ // this is too dangerous and need further restrictions
+ // see bug #447547
+
+ /* if one of them is a literal then we can */
+ if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) || (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
+ {
+ OP_SYMBOL (IC_RESULT (ic))->accuse = 1;
+ return;
+ }
+#endif
+
+accuse:
+ OP_SYMBOL (IC_RESULT (ic))->accuse = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* packForPush - heuristics to reduce iCode for pushing */
+/*-----------------------------------------------------------------*/
+static void
+packForPush (iCode * ic, eBBlock ** ebpp, int blockno)
+{
+ iCode *dic, *lic;
+ bitVect *dbv;
+ struct eBBlock *ebp = ebpp[blockno];
+ int disallowHiddenAssignment = 0;
+
+ if (ic->op != IPUSH || !IS_ITEMP (IC_LEFT (ic)))
+ return;
+
+ /* must have only definition & one usage */
+ if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic))) != 1 || bitVectnBitsOn (OP_USES (IC_LEFT (ic))) != 1)
+ return;
+
+ /* The changes in SDCCopt.c #7741 should correct the use info, making */
+ /* this extra test redundant. */
+ if (ic->parmPush)
+ {// find Send or other Push for this func call
+ for (lic = ic->next; lic && lic->op != CALL; lic = lic->next)
+ {
+ if ((lic->op == IPUSH || lic->op == SEND) && IS_ITEMP (IC_LEFT (lic)))
+ {// and check parameter is not passed again
+ symbol * parm = OP_SYMBOL (IC_LEFT (ic));
+ symbol * other = OP_SYMBOL (IC_LEFT (lic));
+ if (other == parm)
+ return;
+ }
+ }
+ }
+
+ /* find the definition */
+ if (!(dic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_DEFS (IC_LEFT (ic))))))
+ return;
+
+ if (dic->op != '=' || POINTER_SET (dic))
+ return;
+
+ if (dic->seq < ebp->fSeq) // Evelyn did this
+ {
+ int i;
+ for (i = 0; i < blockno; i++)
+ {
+ if (dic->seq >= ebpp[i]->fSeq && dic->seq <= ebpp[i]->lSeq)
+ {
+ ebp = ebpp[i];
+ break;
+ }
+ }
+ wassert (i != blockno); // no way to recover from here
+ }
+
+ if (IS_SYMOP (IC_RIGHT (dic)))
+ {
+ if (IC_RIGHT (dic)->isvolatile)
+ return;
+
+ if (OP_SYMBOL (IC_RIGHT (dic))->addrtaken || isOperandGlobal (IC_RIGHT (dic)))
+ disallowHiddenAssignment = 1;
+
+ /* make sure the right side does not have any definitions
+ inbetween */
+ dbv = OP_DEFS (IC_RIGHT (dic));
+ for (lic = ic; lic && lic != dic; lic = lic->prev)
+ {
+ if (bitVectBitValue (dbv, lic->key))
+ return;
+ if (disallowHiddenAssignment && (lic->op == CALL || lic->op == PCALL || POINTER_SET (lic)))
+ return;
+ }
+ /* make sure they have the same type */
+ if (IS_SPEC (operandType (IC_LEFT (ic))))
+ {
+ sym_link *itype = operandType (IC_LEFT (ic));
+ sym_link *ditype = operandType (IC_RIGHT (dic));
+
+ if (SPEC_USIGN (itype) != SPEC_USIGN (ditype) || SPEC_LONG (itype) != SPEC_LONG (ditype))
+ return;
+ }
+ /* extend the live range of replaced operand if needed */
+ if (OP_SYMBOL (IC_RIGHT (dic))->liveTo < ic->seq)
+ {
+ OP_SYMBOL (IC_RIGHT (dic))->liveTo = ic->seq;
+ }
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key);
+ }
+ if (IS_ITEMP (IC_RIGHT (dic)))
+ OP_USES (IC_RIGHT (dic)) = bitVectSetBit (OP_USES (IC_RIGHT (dic)), ic->key);
+
+ /* now we know that it has one & only one def & use
+ and the that the definition is an assignment */
+ ReplaceOpWithCheaperOp (&IC_LEFT (ic), IC_RIGHT (dic));
+ remiCodeFromeBBlock (ebp, dic);
+ hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegisters - does some transformations to reduce register */
+/* pressure */
+/*-----------------------------------------------------------------*/
+static void
+packRegisters (eBBlock ** ebpp, int blockno)
+{
+ iCode *ic;
+ int change = 0;
+ eBBlock *ebp = ebpp[blockno];
+
+ do
+ {
+ change = 0;
+
+ /* look for assignments of the form */
+ /* iTempNN = TrueSym (someoperation) SomeOperand */
+ /* .... */
+ /* TrueSym := iTempNN:1 */
+ for (ic = ebp->sch; ic; ic = ic->next)
+ {
+ /* find assignment of the form TrueSym := iTempNN:1 */
+ if (ic->op == '=' && !POINTER_SET (ic))
+ change += packRegsForAssign (ic, ebp);
+ }
+ }
+ while (change);
+
+ for (ic = ebp->sch; ic; ic = ic->next)
+ {
+ /* Fix for bug #979599: */
+ /* P0 &= ~1; */
+
+ /* Look for two subsequent iCodes with */
+ /* iTemp := _c; */
+ /* _c = iTemp & op; */
+ /* and replace them by */
+ /* iTemp := _c; */
+ /* _c = _c & op; */
+ if ((ic->op == BITWISEAND || ic->op == '|' || ic->op == '^') &&
+ ic->prev &&
+ ic->prev->op == '=' &&
+ (IS_ITEMP (IC_LEFT (ic)) && isOperandEqual (IC_LEFT (ic), IC_RESULT (ic->prev)) && isOperandEqual (IC_RESULT (ic), IC_RIGHT (ic->prev)) ||
+ IS_ITEMP (IC_RIGHT (ic)) && isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic->prev)) && isOperandEqual (IC_RESULT (ic), IC_RIGHT (ic->prev))))
+ {
+ bool left = IS_ITEMP (IC_LEFT (ic)) && isOperandEqual (IC_LEFT (ic), IC_RESULT (ic->prev)) && isOperandEqual (IC_RESULT (ic), IC_RIGHT (ic->prev));
+
+ iCode *ic_prev = ic->prev;
+ symbol *prev_result_sym = OP_SYMBOL (IC_RESULT (ic_prev));
+
+ ReplaceOpWithCheaperOp (left ? &IC_LEFT (ic) : &IC_RIGHT (ic), IC_RESULT (ic));
+ if (IC_RESULT (ic_prev) != (left ? IC_RIGHT (ic) : IC_LEFT (ic)))
+ {
+ bitVectUnSetBit (OP_USES (IC_RESULT (ic_prev)), ic->key);
+ if ( /*IS_ITEMP (IC_RESULT (ic_prev)) && */
+ prev_result_sym->liveTo == ic->seq)
+ {
+ prev_result_sym->liveTo = ic_prev->seq;
+ }
+ }
+ bitVectSetBit (OP_USES (IC_RESULT (ic)), ic->key);
+
+ bitVectSetBit (ic->rlive, IC_RESULT (ic)->key);
+
+ if (bitVectIsZero (OP_USES (IC_RESULT (ic_prev))))
+ {
+ bitVectUnSetBit (ic->rlive, IC_RESULT (ic)->key);
+ bitVectUnSetBit (OP_DEFS (IC_RESULT (ic_prev)), ic_prev->key);
+ remiCodeFromeBBlock (ebp, ic_prev);
+ hTabDeleteItem (&iCodehTab, ic_prev->key, ic_prev, DELETE_ITEM, NULL);
+ }
+ }
+
+ /* if this is an itemp & result of an address of a true sym
+ then mark this as rematerialisable */
+ if (ic->op == ADDRESS_OF &&
+ IS_ITEMP (IC_RESULT (ic)) &&
+ IS_TRUE_SYMOP (IC_LEFT (ic)) &&
+ bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 &&
+ !OP_SYMBOL (IC_LEFT (ic))->onStack)
+ {
+ OP_SYMBOL (IC_RESULT (ic))->remat = 1;
+ OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
+ OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;
+ }
+
+ /* if straight assignment then carry remat flag if
+ this is the only definition */
+ if (ic->op == '=' &&
+ !POINTER_SET (ic) &&
+ IS_SYMOP (IC_RIGHT (ic)) &&
+ OP_SYMBOL (IC_RIGHT (ic))->remat &&
+ !IS_CAST_ICODE (OP_SYMBOL (IC_RIGHT (ic))->rematiCode) &&
+ !isOperandGlobal (IC_RESULT (ic)) && /* due to bug 1618050 */
+ bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1 &&
+ !OP_SYMBOL (IC_RESULT (ic))->addrtaken)
+ {
+ OP_SYMBOL (IC_RESULT (ic))->remat = OP_SYMBOL (IC_RIGHT (ic))->remat;
+ OP_SYMBOL (IC_RESULT (ic))->rematiCode = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+ }
+
+ /* if cast to a generic pointer & the pointer being
+ cast is remat, then we can remat this cast as well */
+ if (ic->op == CAST &&
+ IS_SYMOP (IC_RIGHT (ic)) &&
+ OP_SYMBOL (IC_RIGHT (ic))->remat &&
+ bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 &&
+ !OP_SYMBOL (IC_RESULT (ic))->addrtaken)
+ {
+ sym_link *to_type = operandType (IC_LEFT (ic));
+ sym_link *from_type = operandType (IC_RIGHT (ic));
+ if (IS_PTR (to_type) && IS_PTR (from_type))
+ {
+ OP_SYMBOL (IC_RESULT (ic))->remat = 1;
+ OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
+ OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;
+ }
+ }
+
+ /* if this is a +/- operation with a rematerializable
+ then mark this as rematerializable as well */
+ if ((ic->op == '+' || ic->op == '-') &&
+ IS_SYMOP (IC_LEFT (ic)) &&
+ IS_ITEMP (IC_RESULT (ic)) &&
+ IS_OP_LITERAL (IC_RIGHT (ic)) &&
+ OP_SYMBOL (IC_LEFT (ic))->remat &&
+ (!IS_SYMOP (IC_RIGHT (ic)) || !IS_CAST_ICODE (OP_SYMBOL (IC_RIGHT (ic))->rematiCode)) &&
+ bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1)
+ {
+ OP_SYMBOL (IC_RESULT (ic))->remat = 1;
+ OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
+ OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;
+ }
+
+ /* mark the pointer usages */
+ if (POINTER_SET (ic) && IS_SYMOP (IC_RESULT (ic)))
+ OP_SYMBOL (IC_RESULT (ic))->uptr = 1;
+
+ if (POINTER_GET (ic) && IS_SYMOP (IC_LEFT (ic)))
+ OP_SYMBOL (IC_LEFT (ic))->uptr = 1;
+
+ if (!SKIP_IC2 (ic))
+ {
+ /* if we are using a symbol on the stack
+ then we should say mcs51_ptrRegReq */
+ if (options.useXstack && ic->parmPush && (ic->op == IPUSH || ic->op == IPOP))
+ mcs51_ptrRegReq++;
+ if (ic->op == IFX && IS_SYMOP (IC_COND (ic)))
+ mcs51_ptrRegReq += ((OP_SYMBOL (IC_COND (ic))->onStack ||
+ OP_SYMBOL (IC_COND (ic))->iaccess ||
+ SPEC_OCLS (OP_SYMBOL (IC_COND (ic))->etype) == idata) ? 1 : 0);
+ else if (ic->op == JUMPTABLE && IS_SYMOP (IC_JTCOND (ic)))
+ mcs51_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack ||
+ OP_SYMBOL (IC_JTCOND (ic))->iaccess ||
+ SPEC_OCLS (OP_SYMBOL (IC_JTCOND (ic))->etype) == idata) ? 1 : 0);
+ else
+ {
+ if (IS_SYMOP (IC_LEFT (ic)))
+ mcs51_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack ||
+ OP_SYMBOL (IC_LEFT (ic))->iaccess ||
+ SPEC_OCLS (OP_SYMBOL (IC_LEFT (ic))->etype) == idata) ? 1 : 0);
+ if (IS_SYMOP (IC_RIGHT (ic)))
+ mcs51_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack ||
+ OP_SYMBOL (IC_RIGHT (ic))->iaccess ||
+ SPEC_OCLS (OP_SYMBOL (IC_RIGHT (ic))->etype) == idata) ? 1 : 0);
+ if (IS_SYMOP (IC_RESULT (ic)))
+ mcs51_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack ||
+ OP_SYMBOL (IC_RESULT (ic))->iaccess ||
+ SPEC_OCLS (OP_SYMBOL (IC_RESULT (ic))->etype) == idata) ? 1 : 0);
+ if (POINTER_GET (ic) && IS_SYMOP (IC_LEFT (ic))
+ && getSize (OP_SYMBOL (IC_LEFT (ic))->type) <= (unsigned int) NEARPTRSIZE)
+ mcs51_ptrRegReq++;
+ if (POINTER_SET (ic) && IS_SYMOP (IC_RESULT (ic))
+ && getSize (OP_SYMBOL (IC_RESULT (ic))->type) <= (unsigned int) NEARPTRSIZE)
+ mcs51_ptrRegReq++;
+ }
+ }
+
+ /* if the condition of an if instruction
+ is defined in the previous instruction and
+ this is the only usage then
+ mark the itemp as a conditional */
+ if ((IS_CONDITIONAL (ic) ||
+ (IS_BITWISE_OP (ic) && isBitwiseOptimizable (ic))) &&
+ ic->next && ic->next->op == IFX &&
+ bitVectnBitsOn (OP_USES (IC_RESULT (ic))) == 1 &&
+ isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) && OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq)
+ {
+ OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND;
+ continue;
+ }
+
+ /* if the condition of an if instruction
+ is defined in the previous GET_POINTER instruction and
+ this is the only usage then
+ mark the itemp as accumulator use */
+ if ((POINTER_GET (ic) && getSize (operandType (IC_RESULT (ic))) <= 1) &&
+ ic->next && ic->next->op == IFX &&
+ bitVectnBitsOn (OP_USES (IC_RESULT (ic))) == 1 &&
+ isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) && OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq)
+ {
+ OP_SYMBOL (IC_RESULT (ic))->accuse = 1;
+ continue;
+ }
+
+ /* reduce for support function calls */
+ if (ic->supportRtn || ic->op == '+' || ic->op == '-')
+ packRegsForSupport (ic, ebp);
+
+ /* some cases the redundant moves can
+ can be eliminated for return statements */
+ if ((ic->op == RETURN || (ic->op == SEND && ic->argreg == 1)) &&
+ !isOperandInFarSpace (IC_LEFT (ic)) && (options.model == MODEL_SMALL || options.model == MODEL_MEDIUM))
+ {
+ packRegsForOneuse (ic, IC_LEFT (ic), ebp);
+ }
+
+ /* if pointer set & left has a size more than
+ one and right is not in far space */
+ if (POINTER_SET (ic) &&
+ IS_SYMOP (IC_RESULT (ic)) &&
+ !isOperandInFarSpace (IC_RIGHT (ic)) &&
+ !OP_SYMBOL (IC_RESULT (ic))->remat &&
+ !IS_OP_RUONLY (IC_RIGHT (ic)) && getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1)
+ {
+ packRegsForOneuse (ic, IC_RESULT (ic), ebp);
+ }
+
+ /* if pointer get */
+ if (POINTER_GET (ic) &&
+ IS_SYMOP (IC_LEFT (ic)) &&
+ !isOperandInFarSpace (IC_RESULT (ic)) &&
+ !OP_SYMBOL (IC_LEFT (ic))->remat &&
+ !IS_OP_RUONLY (IC_RESULT (ic)) &&
+ getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1)
+ {
+ packRegsForOneuse (ic, IC_LEFT (ic), ebp);
+ }
+
+ /* if this is a cast for integral promotion then
+ check if it's the only use of the definition of the
+ operand being casted/ if yes then replace
+ the result of that arithmetic operation with
+ this result and get rid of the cast */
+ if (ic->op == CAST)
+ {
+ sym_link *fromType = operandType (IC_RIGHT (ic));
+ sym_link *toType = operandType (IC_LEFT (ic));
+
+ if (IS_INTEGRAL (fromType) && IS_INTEGRAL (toType) &&
+ getSize (fromType) != getSize (toType) && SPEC_USIGN (fromType) == SPEC_USIGN (toType))
+ {
+ iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp);
+ if (dic)
+ {
+ if (IS_ARITHMETIC_OP (dic))
+ {
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key);
+ ReplaceOpWithCheaperOp (&IC_RESULT (dic), IC_RESULT (ic));
+ remiCodeFromeBBlock (ebp, ic);
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key);
+ hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
+ OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
+ ic = ic->prev;
+ }
+ else
+ {
+ OP_SYMBOL (IC_RIGHT (ic))->ruonly = 0;
+ }
+ }
+ }
+ else
+ {
+ /* if the type from and type to are the same
+ then if this is the only use then pack it */
+ if (compareType (operandType (IC_RIGHT (ic)), operandType (IC_LEFT (ic))) == 1)
+ {
+ iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp);
+ if (dic)
+ {
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key);
+ ReplaceOpWithCheaperOp (&IC_RESULT (dic), IC_RESULT (ic));
+ remiCodeFromeBBlock (ebp, ic);
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key);
+ hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
+ OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
+ ic = ic->prev;
+ }
+ }
+ }
+ }
+
+ /* pack for PUSH
+ iTempNN := (some variable in farspace) V1
+ push iTempNN ;
+ -------------
+ push V1
+ */
+ if (ic->op == IPUSH)
+ {
+ packForPush (ic, ebpp, blockno);
+ }
+
+ /* pack registers for accumulator use, when the
+ result of an arithmetic or bit wise operation
+ has only one use, that use is immediately following
+ the definition and the using iCode has only one
+ operand or has two operands but one is literal &
+ the result of that operation is not on stack then
+ we can leave the result of this operation in acc:b
+ combination */
+ if ((IS_ARITHMETIC_OP (ic)
+ || IS_CONDITIONAL (ic)
+ || IS_BITWISE_OP (ic)
+ || ic->op == LEFT_OP || ic->op == RIGHT_OP || ic->op == CALL
+ || ic->op == '=' && !POINTER_SET(ic) && getSize (operandType (IC_RESULT (ic))) < 2
+ || (ic->op == ADDRESS_OF && isOperandOnStack (IC_LEFT (ic)))) &&
+ IS_ITEMP (IC_RESULT (ic)) && getSize (operandType (IC_RESULT (ic))) <= 2)
+ {
+ packRegsForAccUse (ic);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+/* positionRegsReverse - positioning registers from end to begin to avoid */
+/* conflict among result, left and right operands in some extrem cases */
+/*------------------------------------------------------------------------*/
+static void
+positionRegsReverse (eBBlock ** ebbs, int count)
+{
+ int i;
+ iCode *ic;
+
+ for (i = count - 1; i >= 0; i--)
+ for (ic = ebbs[i]->ech; ic; ic = ic->prev)
+ {
+ if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->nRegs &&
+ IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic))->nRegs)
+ {
+ positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_LEFT (ic)), 1);
+ }
+ if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->nRegs &&
+ IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic))->nRegs)
+ {
+ positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_RIGHT (ic)), 1);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignRegisters - assigns registers to each live range as need */
+/*-----------------------------------------------------------------*/
+void
+mcs51_assignRegisters (ebbIndex * ebbi)
+{
+ eBBlock **ebbs = ebbi->bbOrder;
+ int count = ebbi->count;
+ iCode *ic;
+ int i;
+
+ setToNull ((void *) &_G.funcrUsed);
+ setToNull ((void *) &_G.regAssigned);
+ setToNull ((void *) &_G.totRegAssigned);
+ mcs51_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
+ if ((currFunc && IFFUNC_ISREENT (currFunc->type)) || options.stackAuto)
+ {
+ mcs51_nRegs = 16;
+ }
+ else
+ {
+ mcs51_nRegs = 8;
+ }
+ _G.allBitregs = findAllBitregs ();
+ _G.allBankregs = findAllBankregs ();
+
+ /* change assignments this will remove some
+ live ranges reducing some register pressure */
+
+ for (i = 0; i < count; i++)
+ packRegisters (ebbs, i);
+
+ /* liveranges probably changed by register packing
+ so we compute them again */
+ recomputeLiveRanges (ebbs, count, FALSE);
+
+ if (options.dump_i_code)
+ dumpEbbsToFileExt (DUMP_PACK, ebbi);
+
+ /* first determine for each live range the number of
+ registers & the type of registers required for each */
+ regTypeNum (*ebbs);
+
+ /* and serially allocate registers */
+ serialRegAssign (ebbs, count);
+
+ freeAllRegs ();
+ //setToNull ((void *) &_G.regAssigned);
+ //setToNull ((void *) &_G.totRegAssigned);
+ fillGaps ();
+
+ /* do positionRegs() for all ICs from end to begin */
+ positionRegsReverse (ebbs, count);
+
+ /* if stack was extended then tell the user */
+ if (_G.stackExtend)
+ {
+/* werror(W_TOOMANY_SPILS,"stack", */
+/* _G.stackExtend,currFunc->name,""); */
+ _G.stackExtend = 0;
+ }
+
+ if (_G.dataExtend)
+ {
+/* werror(W_TOOMANY_SPILS,"data space", */
+/* _G.dataExtend,currFunc->name,""); */
+ _G.dataExtend = 0;
+ }
+
+ /* after that create the register mask
+ for each of the instruction */
+ createRegMask (ebbs, count);
+
+ /* redo that offsets for stacked automatic variables */
+ if (currFunc)
+ {
+ redoStackOffsets ();
+ }
+
+ /* make sure r0 & r1 are flagged as used if they might be used */
+ /* as pointers */
+ if (currFunc && mcs51_ptrRegReq)
+ {
+ currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, R0_IDX);
+ currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, R1_IDX);
+ }
+
+ if (options.dump_i_code)
+ {
+ dumpEbbsToFileExt (DUMP_RASSGN, ebbi);
+ dumpLiveRanges (DUMP_LRANGE, liveRanges);
+ }
+
+ /* do the overlaysegment stuff SDCCmem.c */
+ doOverlays (ebbs, count);
+
+ /* now get back the chain */
+ ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
+
+ gen51Code (ic);
+
+ /* free up any _G.stackSpil locations allocated */
+ applyToSet (_G.stackSpil, deallocStackSpil);
+ _G.slocNum = 0;
+ setToNull ((void *) &_G.stackSpil);
+ setToNull ((void *) &_G.spiltSet);
+ /* mark all registers as free */
+ freeAllRegs ();
+
+ return;
+}
diff --git a/src/mcs51/ralloc.h b/src/mcs51/ralloc.h
new file mode 100644
index 0000000..10b86e1
--- /dev/null
+++ b/src/mcs51/ralloc.h
@@ -0,0 +1,81 @@
+/*-------------------------------------------------------------------------
+
+ SDCCralloc.h - header file register allocation
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+#include "SDCCicode.h"
+#include "SDCCBBlock.h"
+#ifndef SDCCRALLOC_H
+#define SDCCRALLOC_H 1
+
+enum
+{
+ R7_IDX = 0, R6_IDX, R5_IDX, R4_IDX,
+ R3_IDX, R2_IDX, R1_IDX, R0_IDX,
+ B0_IDX, B1_IDX, B2_IDX, B3_IDX,
+ B4_IDX, B5_IDX, B6_IDX, B7_IDX,
+ X8_IDX, X9_IDX, X10_IDX, X11_IDX,
+ X12_IDX, CND_IDX,
+ DPL_IDX, DPH_IDX, B_IDX, A_IDX,
+ END_IDX
+};
+
+
+#define REG_PTR 0x01
+#define REG_GPR 0x02
+#define REG_CND 0x04
+#define REG_BIT 0x08
+/* definition for the registers */
+typedef struct reg_info
+{
+ short type; /* can have value
+ REG_GPR, REG_BIT, REG_PTR or REG_CND */
+ short rIdx; /* index into register table */
+ short otype;
+ char *name; /* name */
+ char *dname; /* name when direct access needed */
+ char *base; /* base address */
+ short offset; /* offset from the base */
+ unsigned isFree:1; /* is currently unassigned */
+
+ struct
+ {
+ unsigned valueKnown:1;
+ unsigned char value; /* only valid when valueKnown is set */
+ char *symbol; /* holds symbol if value is known by symbol */
+ }
+ rtrack;
+}
+reg_info;
+
+extern reg_info regs8051[];
+
+reg_info *mcs51_regWithIdx (int);
+
+bitVect *mcs51_rUmaskForOp (operand * op);
+bitVect *mcs51_allBitregs (void);
+bitVect *mcs51_allBankregs (void);
+
+extern int mcs51_ptrRegReq;
+extern int mcs51_nRegs;
+
+#endif
diff --git a/src/mcs51/rtrack.c b/src/mcs51/rtrack.c
new file mode 100644
index 0000000..13fc5b2
--- /dev/null
+++ b/src/mcs51/rtrack.c
@@ -0,0 +1,1200 @@
+/*-------------------------------------------------------------------------
+ rtrack.c - tracking content of registers on an mcs51
+
+ Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ Status:
+ - passes regression test suite, still bugs are likely
+ - only active if environment variable SDCC_REGTRACK is set
+
+ Missed opportunities:
+ - does not track offsets to symbols as in "mov dptr,#(_my_int + 2)"
+ - only used for moves to acc or dptr so chances to use:
+ "inc r2", "mov r2,a" would not be taken
+ - a label causes loss of tracking (no handling of information of blocks
+ known to follow/preceed the current block)
+ - not used in aopGet or genRet
+ - SFRX (__xdata volatile unsigned char __at(addr)) not handled as value
+ - does not track which registers are known to be unchanged within
+ a function (would not have to be saved when calling the function)
+-------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include "SDCCglobl.h"
+
+#include "common.h"
+#include "ralloc.h"
+#include "gen.h"
+#include "rtrack.h"
+
+
+#define D(x) do if (options.verboseAsm) {x;} while(0)
+#define DD(x) do if (options.verboseAsm && enableextraverbose) {x;} while(0)
+
+
+/* move this (or rtrackGetLit() and rtrackMoveALit()
+ elsewhere? stealing emitcode from gen.c */
+void emitcode (const char *inst, const char *fmt,...);
+
+
+static int enable = +1;
+static int enableextraverbose = -1;
+
+
+static unsigned int rx_num_to_idx (const unsigned int num)
+{
+ const unsigned int regidx[8] =
+ { R7_IDX, R6_IDX, R5_IDX, R4_IDX, R3_IDX, R2_IDX, R1_IDX, R0_IDX };
+
+ assert( 7 >= num );
+
+ return regidx [num & 0x7];
+}
+
+
+static void rtrack_data_unset (const unsigned int idx)
+{
+ assert (idx >= 0);
+ assert (idx < END_IDX);
+
+ if (regs8051[idx].rtrack.symbol || regs8051[idx].rtrack.valueKnown)
+ {
+ DD(emitcode (";", "\t%s=?", regs8051[idx].name););
+ }
+
+ if (regs8051[idx].rtrack.symbol)
+ {
+ Safe_free (regs8051[idx].rtrack.symbol);
+ }
+
+ memset (&regs8051[idx].rtrack, 0, sizeof regs8051[idx].rtrack);
+}
+
+
+static void rtrack_data_set_val (const unsigned int idx, const unsigned char value)
+{
+ assert (idx >= 0);
+ assert (idx < END_IDX);
+
+ regs8051[idx].rtrack.value = value;
+ regs8051[idx].rtrack.valueKnown = 1;
+
+ /* in case it was set by symbol, unset symbol */
+ if (regs8051[idx].rtrack.symbol)
+ {
+ Safe_free (regs8051[idx].rtrack.symbol);
+ regs8051[idx].rtrack.symbol = NULL;
+ }
+
+ DD(emitcode (";", "\t%s=#0x%02x",
+ regs8051[idx].name,
+ regs8051[idx].rtrack.value););
+}
+
+
+static void rtrack_data_set_symbol (const unsigned int idx, const char * const symbol)
+{
+ assert (idx >= 0);
+ assert (idx < END_IDX);
+
+ /* in case it was set by value, unset value */
+ regs8051[idx].rtrack.value = 0;
+ regs8051[idx].rtrack.valueKnown = 0;
+
+ /* eventually free a previous symbol */
+ if (regs8051[idx].rtrack.symbol)
+ {
+ Safe_free (regs8051[idx].rtrack.symbol);
+ }
+ regs8051[idx].rtrack.symbol = Safe_strdup(symbol);
+
+ DD(emitcode (";", "\t%s=#%s",
+ regs8051[idx].name,
+ regs8051[idx].rtrack.symbol););
+}
+
+
+static int rtrack_data_is_same (const unsigned int idxdst, const unsigned int idxsrc)
+{
+ return ((regs8051[idxdst].rtrack.valueKnown && regs8051[idxsrc].rtrack.valueKnown) &&
+ (regs8051[idxdst].rtrack.value == regs8051[idxsrc].rtrack.value)) ||
+ ((regs8051[idxdst].rtrack.symbol && regs8051[idxsrc].rtrack.symbol) &&
+ !strcmp (regs8051[idxdst].rtrack.symbol, regs8051[idxsrc].rtrack.symbol));
+}
+
+
+static void rtrack_data_copy_dst_src (const unsigned int idxdst, const unsigned int idxsrc)
+{
+ assert (idxdst >= 0);
+ assert (idxdst < END_IDX);
+ assert (idxsrc >= 0);
+ assert (idxsrc < END_IDX);
+
+ DD
+ (
+ if ((NULL != regs8051[idxsrc].rtrack.symbol) || regs8051[idxsrc].rtrack.valueKnown)
+ {
+ emitcode (";", "\t%s=%s", regs8051[idxdst].name, regs8051[idxsrc].name);
+ }
+ else if (regs8051[idxdst].rtrack.symbol || regs8051[idxdst].rtrack.valueKnown)
+ {
+ emitcode (";", "\t%s=*",regs8051[idxdst].name);
+ }
+
+ if (rtrack_data_is_same (idxdst, idxsrc))
+ {
+ emitcode (";", "genFromRTrack redundant?");
+ }
+ );
+
+ /* mov a, acc */
+ if (idxsrc == idxdst)
+ return;
+
+ regs8051[idxdst].rtrack.valueKnown = regs8051[idxsrc].rtrack.valueKnown;
+ regs8051[idxdst].rtrack.value = regs8051[idxsrc].rtrack.value;
+
+ if (regs8051[idxdst].rtrack.symbol)
+ {
+ Safe_free (regs8051[idxdst].rtrack.symbol);
+ regs8051[idxdst].rtrack.symbol = NULL;
+ }
+
+ memcpy (&regs8051[idxdst].rtrack, &regs8051[idxsrc].rtrack, sizeof regs8051[idxdst].rtrack);
+
+ if (regs8051[idxsrc].rtrack.symbol)
+ {
+ regs8051[idxdst].rtrack.symbol = Safe_strdup(regs8051[idxsrc].rtrack.symbol);
+ }
+}
+
+
+static void dumpAll()
+{
+ DD
+ (
+ unsigned int i;
+ unsigned int column = 0;
+ char s[512];
+
+ s[0] = 0;
+ for (i = 0; i < END_IDX; i++)
+ {
+ if (regs8051[i].rtrack.valueKnown)
+ {
+ column += sprintf(s + column, "%s%s:#0x%02x",
+ column?" ":"", regs8051[i].name, regs8051[i].rtrack.value);
+ }
+ if (NULL != regs8051[i].rtrack.symbol)
+ {
+ column += sprintf(s + column, "%s%s:#%s",
+ column?" ":"", regs8051[i].name, regs8051[i].rtrack.symbol);
+ }
+ if (column>160)
+ {
+ strcpy (&s[157], "...");
+ break;
+ }
+ }
+ emitcode (";", "\t%s", s);
+ );
+}
+
+
+static void invalidateAllRx()
+{
+ unsigned int i;
+ for (i = 0; i <= 7; i++)
+ {
+ rtrack_data_unset (rx_num_to_idx (i));
+ }
+}
+
+
+static void invalidateAll()
+{
+ invalidateAllRx();
+
+ rtrack_data_unset (DPL_IDX);
+ rtrack_data_unset (DPH_IDX);
+ rtrack_data_unset (B_IDX);
+ rtrack_data_unset (A_IDX);
+}
+
+
+static int regidxfromregname (const char* const s)
+{
+ unsigned int i;
+
+ for (i = 0; i < END_IDX; i++)
+ {
+ if (regs8051[i].name)
+ if (!strncmp (s, regs8051[i].name, strlen(regs8051[i].name)))
+ return i;
+
+ if (regs8051[i].dname)
+ if (!strncmp (s, regs8051[i].dname, strlen(regs8051[i].dname)))
+ return i;
+ }
+
+ return -1;
+}
+
+
+static int valuefromliteral (const char* const s)
+{
+ char* tmp = NULL;
+ int value;
+
+ if (strncmp (s, "0x", 2))
+ return -1;
+
+ value = strtol (s + 2, &tmp, 16);
+ if (s != tmp)
+ return value;
+
+ return -1;
+}
+
+
+/* tracking values within registers by looking
+ at the line passed to the assembler.
+ Tries to keep regs8051[] up to date */
+bool _mcs51_rtrackUpdate (const char *line)
+{
+ bool modified = false;
+
+ if (enable == -1)
+ enable = (NULL != getenv("SDCC_REGTRACK"));
+
+ if (enableextraverbose == -1)
+ enableextraverbose = (NULL != getenv("SDCC_REGTRACK_VERBOSE"));
+
+ if (!enable ||
+ *line == ';' || /* comment */
+ (NULL != strstr( line, "==."))) /* dirty check for _G.debugLine */
+ return false; /* nothing to do */
+
+ dumpAll ();
+
+ if (!strncmp (line, "mov", 3))
+ {
+ if (!strncmp (line, "movc\ta", 6) ||
+ !strncmp (line, "movx\ta", 6))
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+
+ /* mov to register (r0..r7, dpl, dph, a, b)*/
+ if (!strncmp (line, "mov\t", 4))
+ {
+ int regIdx = regidxfromregname (line + 4);
+
+ if (0 <= regIdx)
+ {
+ char *argument = strstr (line, ",") + 1;
+ char *s;
+ int value;
+
+ value = strtol (argument + 1, &s, 16);
+
+ /* check literal mov to register */
+ if ((s != argument + 1) && !strncmp (argument, "#0x", 3))
+ {
+ D
+ (
+ if (regs8051[regIdx].rtrack.valueKnown && (value == regs8051[regIdx].rtrack.value))
+ {
+ emitcode (";", "genFromRTrack removed\t%s", line);
+ modified = true;
+ }
+ if (regs8051[A_IDX].rtrack.valueKnown && (value == regs8051[A_IDX].rtrack.value) &&
+ (regIdx != A_IDX) && (regIdx != DPL_IDX) && (regIdx != DPH_IDX))
+ /* ignore DPL/DPH for now as peephole rule for MOV DPTR is much better */
+ {
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode ("mov", "%s,a", regs8051[regIdx].dname);
+ modified = true;
+ }
+ else if (regs8051[regIdx].rtrack.valueKnown && (value == regs8051[regIdx].rtrack.value + 1) &&
+ ((regIdx != A_IDX) || (0xff != regs8051[regIdx].rtrack.value)))
+ {
+ /* does not occur in regression test mcs51-small */
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode ("inc", "%s", regs8051[regIdx].name);
+ modified = true;
+ }
+ else if (regs8051[regIdx].rtrack.valueKnown && (value == regs8051[regIdx].rtrack.value - 1) &&
+ ((regIdx != A_IDX) || (0x01 != regs8051[regIdx].rtrack.value)))
+ {
+ /* does not occur in regression test mcs51-small */
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode ("dec", "%s", regs8051[regIdx].name);
+ modified = true;
+ }
+ );
+
+ rtrack_data_set_val (regIdx, (unsigned char) value);
+ }
+ /* check literal mov of symbol to register */
+ else if (!strncmp (argument, "#", 1))
+ {
+ rtrack_data_set_symbol (regIdx, argument + 1);
+ }
+ /* check mov from register to register */
+ else if (0 <= regidxfromregname (argument))
+ {
+ rtrack_data_copy_dst_src (regIdx, regidxfromregname (argument));
+ }
+ else
+ {
+ /* mov acc.7,c and the likes */
+ rtrack_data_unset (regIdx);
+ }
+ return modified;
+ }
+ }
+
+ /* mov to psw can change register bank */
+ if (!strncmp (line, "mov\tpsw,", 8))
+ {
+ invalidateAllRx ();
+ return false;
+ }
+
+ /* tracking dptr */
+ /* literal number 16 bit */
+ if (!strncmp (line, "mov\tdptr,#0x", 12))
+ {
+ char* s;
+ int value = strtol (line + 10, &s, 16);
+ if( s != line + 10 )
+ {
+ if (options.verboseAsm)
+ {
+ bool foundshortcut = 0;
+
+ if ( regs8051[DPH_IDX].rtrack.valueKnown &&
+ regs8051[DPL_IDX].rtrack.valueKnown &&
+ (regs8051[DPH_IDX].rtrack.value == (value >> 8)) &&
+ (regs8051[DPL_IDX].rtrack.value == (value & 0xff)))
+ {
+ emitcode (";", "genFromRTrack removed\t%s", line);
+ foundshortcut = 1;
+ modified = true;
+ }
+
+ if (!foundshortcut &&
+ regs8051[DPH_IDX].rtrack.valueKnown &&
+ regs8051[DPL_IDX].rtrack.valueKnown)
+ {
+ /* some instructions are shorter than mov dptr,#0xabcd */
+ const struct
+ {
+ int offset;
+ const char* inst;
+ const char* parm;
+ } reachable[6] =
+ {
+ { 1, "inc", "dptr"},
+ { 256, "inc", "dph"},
+ {-256, "dec", "dph"},
+ {-255, "inc", "dpl"}, /* if overflow */
+ { -1, "dec", "dpl"}, /* if no overflow */
+ { 255, "dec", "dpl"} /* if overflow */
+ };
+
+ unsigned int dptr = (regs8051[DPH_IDX].rtrack.value << 8 ) |
+ regs8051[DPL_IDX].rtrack.value;
+ unsigned int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ if (dptr + reachable[i].offset == value)
+ {
+ /* check if an overflow would occur */
+ if ((i == 3) && ((dptr & 0xff) != 0xff)) continue;
+ if ((i == 4) && ((dptr & 0xff) == 0x00)) continue;
+ if ((i == 5) && ((dptr & 0xff) != 0x00)) continue;
+
+ /* does not occur in regression test mcs51-small */
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode (reachable[i].inst, "%s", reachable[i].parm);
+ modified = true;
+ foundshortcut = 1;
+
+ break;
+ }
+ };
+ }
+
+ if (!foundshortcut &&
+ regs8051[DPH_IDX].rtrack.valueKnown &&
+ (regs8051[DPH_IDX].rtrack.value == (value >> 8)))
+ {
+ char s[32];
+ sprintf (s, "#0x%02x", value & 0xff);
+
+ if (s != rtrackGetLit(s))
+ {
+ /* does not occur in regression test mcs51-small */
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode ("mov", "dpl,%s", rtrackGetLit (s));
+ modified = true;
+ foundshortcut = 1;
+ }
+ }
+ if (!foundshortcut &&
+ regs8051[DPL_IDX].rtrack.valueKnown &&
+ (regs8051[DPL_IDX].rtrack.value == (value & 0xff)))
+ {
+ char s[32];
+ sprintf (s, "#0x%02x", value >> 8);
+
+ if (s != rtrackGetLit (s))
+ {
+ /* does not occur in regression test mcs51-small */
+ emitcode (";", "genFromRTrack replaced\t%s", line);
+ emitcode ("mov", "dph,%s", rtrackGetLit (s));
+ modified = true;
+ foundshortcut = 1;
+ }
+ }
+ }
+
+ rtrack_data_set_val (DPH_IDX, (unsigned char) (value >> 8));
+ rtrack_data_set_val (DPL_IDX, (unsigned char) value);
+ return modified;
+ }
+ }
+ /* literal symbol 16 bit */
+ else if (!strncmp (line, "mov\tdptr,#", 10))
+ {
+ char* s = Safe_alloc (strlen (line) + strlen ("( >> 8)"));
+
+ strcat (s, "(");
+ strcat (s, &line[10]);
+ strcat (s, " >> 8)");
+
+ rtrack_data_set_symbol (DPH_IDX, s);
+ rtrack_data_set_symbol (DPL_IDX, &line[10]);
+
+ Safe_free (s);
+ return false;
+ }
+ else if (!strncmp (line, "mov\tdptr", 8))
+ {
+ /* unidentified */
+ rtrack_data_unset (DPH_IDX);
+ rtrack_data_unset (DPL_IDX);
+ return false;
+ }
+
+ /* move direct to symbol */
+ if (!strncmp (line, "mov\t_", 5) ||
+ !strncmp (line, "mov\t(", 5))
+ {
+ char* argument = strstr (line, ",") + 1;
+
+ if (argument && !strncmp (argument, "#0x", 3))
+ {
+ char s[8] = {0};
+
+ strncpy ((void *)&s, argument, strlen ("#0xab"));
+
+ /* could we get it from a, r0..r7? */
+ if (s != rtrackGetLit (s))
+ {
+ int lengthuptoargument = argument - (line + 4);
+ emitcode (";", "1-genFromRTrack replaced\t%s", line);
+ emitcode ("mov", "%.*s%s",
+ lengthuptoargument,
+ line + 4,
+ rtrackGetLit (s));
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /* no tracking of SP, so we do not care */
+ if (!strncmp (line, "mov\tsp,", 7))
+ return false;
+
+ /* mov to xdata or pdata memory does not change registers */
+ if (!strncmp (line, "movx\t@", 6))
+ return false;
+
+ /* mov to idata memory might change registers r0..r7
+ but unless there is a stack problem
+ compiler generated code does not do idata
+ writes to 0x00..0x1f? */
+ if (!strncmp (line, "mov\t@", 5))
+ {
+ /* a little too paranoid? */
+ invalidateAllRx ();
+ return false;
+ }
+ }
+
+ /* no tracking of SP */
+ if (!strncmp (line, "push", 4))
+ return false;
+
+ if (!strncmp (line, "pop\t", 4))
+ {
+ int regIdx = regidxfromregname (line + 4);
+ if (0 <= regIdx)
+ {
+ rtrack_data_unset (regIdx);
+ }
+ return false;
+ }
+
+ if (!strncmp (line, "inc", 3))
+ {
+ if (!strcmp (line, "inc\tdptr"))
+ {
+ if (regs8051[DPH_IDX].rtrack.valueKnown &&
+ regs8051[DPL_IDX].rtrack.valueKnown)
+ {
+ int val = (regs8051[DPH_IDX].rtrack.value << 8) | regs8051[DPL_IDX].rtrack.value;
+ val += 1;
+ rtrack_data_set_val (DPL_IDX, (unsigned char) val);
+ rtrack_data_set_val (DPH_IDX, (unsigned char) (val >> 8));
+ }
+ else
+ {
+ /* not yet handling offset to a symbol. Invalidating. So no inc dptr for:
+ __xdata char array[4]; array[0] = 0; array[1] = 0; array[2] = 0;
+ (If an offset to the respective linker segment would be
+ available then additionally
+ __xdata int a = 123; __xdata int b = 456; __xdata c= 'a';
+ could be 4 bytes shorter) */
+ rtrack_data_unset (DPL_IDX);
+ rtrack_data_unset (DPH_IDX);
+ }
+ return false;
+ }
+ if (!strncmp (line, "inc\t", 4))
+ {
+ int regIdx = regidxfromregname (line + 4);
+ if (0 <= regIdx)
+ {
+ if (regs8051[regIdx].rtrack.valueKnown)
+ rtrack_data_set_val (regIdx, (unsigned char) (regs8051[regIdx].rtrack.value + 1));
+ else
+ /* explicitely unsetting (could be known by symbol).
+ not yet handling offset to a symbol. (idata/pdata) */
+ rtrack_data_unset (regIdx);
+
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /* some bit in acc is cleared
+ MB: I'm too lazy to find out which right now */
+ if (!strncmp (line, "jbc\tacc", 7))
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+
+ /* unfortunately the label typically following these
+ will cause loss of tracking */
+ if (!strncmp (line, "jc\t", 3) ||
+ !strncmp (line, "jnc\t", 4) ||
+ !strncmp (line, "jb\t", 3) ||
+ !strncmp (line, "jnb\t", 4) ||
+ !strncmp (line, "jbc\t", 4))
+ return false;
+
+ /* if branch not taken in "cjne r2,#0x08,somewhere"
+ r2 is known to be 8 */
+ if (!strncmp (line, "cjne\t", 5))
+ {
+ int regIdx = regidxfromregname (line + 5);
+ if (0 <= regIdx)
+ {
+ char *argument = strstr (line, ",") + 1;
+ char *s;
+ int value;
+
+ value = strtol (argument + 1, &s, 16);
+
+ /* check literal compare to register */
+ if ((s != argument + 1) && !strncmp (argument, "#0x", 3))
+ {
+ rtrack_data_set_val (regIdx, (unsigned char) value);
+ return false;
+ }
+ rtrack_data_unset (regIdx);
+ }
+ return false;
+ }
+
+ /* acc eventually known to be zero */
+ if (!strncmp (line, "jz\t", 3))
+ return false;
+
+ /* acc eventually known to be zero */
+ if (!strncmp (line, "jnz\t", 4))
+ {
+ rtrack_data_set_val (A_IDX, 0x00); // branch not taken
+ return false;
+ }
+
+ if (!strncmp (line, "djnz\t", 5))
+ {
+ int regIdx = regidxfromregname (line + 5);
+ if (0 <= regIdx)
+ {
+ rtrack_data_set_val (regIdx, 0x00); // branch not taken
+ return false;
+ }
+ }
+
+ /* only carry bit, so we do not care */
+ if (!strncmp (line, "setb\tc", 6) ||
+ !strncmp (line, "clr\tc", 5) ||
+ !strncmp (line, "cpl\tc", 5))
+ return false;
+
+ /* operations on acc which depend on PSW */
+ if (!strncmp (line, "addc\ta,", 7)||
+ !strncmp (line, "subb\ta,", 7)||
+ !strncmp (line, "da\ta", 4) ||
+ !strncmp (line, "rlc\ta", 5) ||
+ !strncmp (line, "rrc\ta", 5))
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+
+ /* bitwise operations on acc */
+ if (!strncmp (line, "setb\ta", 6) ||
+ !strncmp (line, "clrb\ta", 6))
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+
+ /* other operations on acc that can be tracked */
+ if (!strncmp (line, "add\ta,", 6) ||
+ !strncmp (line, "anl\ta,", 6) ||
+ !strncmp (line, "orl\ta,", 6) ||
+ !strncmp (line, "xrl\ta,", 6) ||
+ !strcmp (line, "cpl\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown)
+ {
+ if (!strncmp (line, "add\ta,", 6))
+ {
+ int regIdx = regidxfromregname (line + 6);
+
+ if (0 <= regIdx && regs8051[regIdx].rtrack.valueKnown)
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value + regs8051[regIdx].rtrack.value));
+ return false;
+ }
+ else if (('#' == line[6]) && (0 <= valuefromliteral (line + 7)))
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value + valuefromliteral (line + 7)));
+ return false;
+ }
+ }
+
+ if (!strncmp (line, "anl\ta,", 6))
+ {
+ int regIdx = regidxfromregname (line + 6);
+
+ if (0 <= regIdx && regs8051[regIdx].rtrack.valueKnown)
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value & regs8051[regIdx].rtrack.value));
+ return false;
+ }
+ else if (('#' == line[6]) && (0 <= valuefromliteral (line + 7)))
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value & valuefromliteral (line + 7)));
+ return false;
+ }
+ }
+
+ if (!strncmp (line, "orl\ta,", 6))
+ {
+ int regIdx = regidxfromregname (line + 6);
+
+ if (0 <= regIdx && regs8051[regIdx].rtrack.valueKnown)
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value | regs8051[regIdx].rtrack.value));
+ return false;
+ }
+ else if (('#' == line[6]) && (0 <= valuefromliteral (line + 7)))
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value | valuefromliteral (line + 7)));
+ return false;
+ }
+ }
+
+ if (!strncmp (line, "xrl\ta,", 6))
+ {
+ int regIdx = regidxfromregname (line + 6);
+
+ if (0 <= regIdx && regs8051[regIdx].rtrack.valueKnown)
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value ^ regs8051[regIdx].rtrack.value));
+ return false;
+ }
+ else if (('#' == line[6]) && (0 <= valuefromliteral (line + 7)))
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value ^ valuefromliteral (line + 7)));
+ return false;
+ }
+ }
+
+ if (!strcmp (line, "cpl\ta"))
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value ^ 0xff));
+ return false;
+ }
+
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ else
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ }
+
+ if (!strncmp (line, "dec\t", 4))
+ {
+ int regIdx = regidxfromregname (line + 4);
+ if (0 <= regIdx)
+ {
+ if (regs8051[regIdx].rtrack.valueKnown)
+ rtrack_data_set_val (regIdx, (unsigned char) (regs8051[regIdx].rtrack.value - 1));
+
+ /* not handling offset to a symbol. invalidating if needed */
+ if (NULL != regs8051[regIdx].rtrack.symbol)
+ rtrack_data_unset (regIdx);
+
+ return false;
+ }
+ return false;
+ }
+
+ if (!strcmp (line, "clr\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown && (0 == regs8051[A_IDX].rtrack.value))
+ {
+ emitcode (";", "genFromRTrack removed\t%s", line);
+ modified = true;
+ }
+ rtrack_data_set_val (A_IDX, 0);
+ return modified;
+ }
+
+ if (!strcmp (line, "cpl\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown)
+ rtrack_data_set_val (A_IDX, (unsigned char) (~regs8051[A_IDX].rtrack.value));
+ else
+ /* in case a holds a symbol */
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ if (!strcmp (line, "rl\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown)
+ rtrack_data_set_val (A_IDX, (unsigned char) ((regs8051[A_IDX].rtrack.value<<1) |
+ (regs8051[A_IDX].rtrack.value>>7)));
+ else
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ if (!strcmp (line, "rr\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown)
+ rtrack_data_set_val (A_IDX, (unsigned char) ((regs8051[A_IDX].rtrack.value>>1) |
+ (regs8051[A_IDX].rtrack.value<<7)));
+ else
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ if (!strcmp (line, "swap\ta"))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown)
+ rtrack_data_set_val (A_IDX, (unsigned char) ((regs8051[A_IDX].rtrack.value>>4) |
+ (regs8051[A_IDX].rtrack.value<<4)));
+ else
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+
+ if (!strncmp (line, "mul\t", 4))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown && regs8051[B_IDX].rtrack.valueKnown)
+ {
+ unsigned int value = (unsigned int)regs8051[A_IDX].rtrack.value *
+ (unsigned int)regs8051[B_IDX].rtrack.value;
+
+ rtrack_data_set_val (A_IDX, (unsigned char) value);
+ rtrack_data_set_val (B_IDX, (unsigned char) (value >> 8));
+ }
+ else
+ {
+ rtrack_data_unset (A_IDX);
+ rtrack_data_unset (B_IDX);
+ }
+ return false;
+ }
+
+ if (!strncmp (line, "div\t", 4))
+ {
+ if (regs8051[A_IDX].rtrack.valueKnown && regs8051[B_IDX].rtrack.valueKnown)
+ {
+ rtrack_data_set_val (A_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value / regs8051[B_IDX].rtrack.value));
+ rtrack_data_set_val (B_IDX, (unsigned char) (regs8051[A_IDX].rtrack.value % regs8051[B_IDX].rtrack.value));
+ }
+ else
+ {
+ rtrack_data_unset (A_IDX);
+ rtrack_data_unset (B_IDX);
+ }
+ return false;
+ }
+
+ /* assuming these library functions have no side-effects */
+ if (!strncmp (line, "lcall", 5))
+ {
+ if (!strcmp (line, "lcall\t__gptrput"))
+ {
+ /* invalidate R0..R7 because they might have been changed */
+ /* MB: too paranoid ? */
+ //invalidateAllRx();
+ return false;
+ }
+ if (!strcmp (line, "lcall\t__gptrget"))
+ {
+ rtrack_data_unset (A_IDX);
+ return false;
+ }
+ if (!strcmp (line, "lcall\t__decdptr"))
+ {
+ if (regs8051[DPH_IDX].rtrack.valueKnown &&
+ regs8051[DPL_IDX].rtrack.valueKnown)
+ {
+ int val = (regs8051[DPH_IDX].rtrack.value << 8) | regs8051[DPL_IDX].rtrack.value;
+ val -= 1;
+ rtrack_data_set_val (DPL_IDX, (unsigned char) val);
+ rtrack_data_set_val (DPH_IDX, (unsigned char) (val >> 8));
+ }
+ else
+ {
+ rtrack_data_unset (DPL_IDX);
+ rtrack_data_unset (DPH_IDX);
+ }
+ return false;
+ }
+ /* if callee_saves */
+ }
+
+ if (!strncmp (line, "xch\ta,", 6))
+ {
+ /* handle xch from register (r0..r7, dpl, dph, b) */
+ int regIdx = regidxfromregname (line + 6);
+ if (0 <= regIdx)
+ {
+ void* swap = Safe_malloc (sizeof regs8051[A_IDX].rtrack);
+
+ memcpy (swap, &regs8051[A_IDX].rtrack, sizeof regs8051[A_IDX].rtrack);
+ memcpy (&regs8051[A_IDX ].rtrack, &regs8051[regIdx].rtrack, sizeof regs8051[A_IDX].rtrack);
+ memcpy (&regs8051[regIdx].rtrack, swap, sizeof regs8051[A_IDX].rtrack);
+
+ Safe_free (swap);
+ return false;
+ }
+ }
+
+ /* all others unrecognized, invalidate */
+ invalidateAll();
+ return false;
+}
+
+
+/* expects f.e. "#0x01" and returns either "#0x01"
+ if the value is not known to be within registers
+ or "a" or "r0".."r7".
+ (mov a,r7 or add a,r7 need one byte whereas
+ mov a,#0x01 or add a,#0x01 would take two
+ */
+char * rtrackGetLit(const char *x)
+{
+ unsigned int i;
+
+ char *s;
+
+ if (enable != 1)
+ return (char *)x;
+
+ /* was it a numerical literal? */
+ if (*x == '#')
+ {
+ int val = strtol (x+1, &s, 16);
+ if (x+1 != s)
+ {
+ /* try to get from acc */
+ reg_info *r = &regs8051[A_IDX];
+ if (r->rtrack.valueKnown &&
+ r->rtrack.value == val)
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==%s", val, r->name));
+ return r->name;
+ }
+ /* try to get from register R0..R7 */
+ for (i = 0; i < 8; i++)
+ {
+ reg_info *r = &regs8051[rx_num_to_idx(i)];
+ if (r->rtrack.valueKnown &&
+ r->rtrack.value == val)
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==%s", val, r->name));
+ return r->name;
+ }
+ }
+ }
+ else
+ {
+ /* probably a symbolic literal as in "mov r3,#(_i+1)",
+ not handled... */
+ }
+ }
+
+ return (char *)x;
+}
+
+/* Similar to the above function
+ As the destination is the accumulator try harder yet and
+ try to generate the result with arithmetic operations */
+int rtrackMoveALit (const char *x)
+{
+
+ if (enable != 1)
+ return 0;
+
+ /* if it is a literal mov try to get it cheaper */
+ if ( *x == '#' )
+ {
+ reg_info *a = &regs8051[A_IDX];
+
+ char *s;
+ int val = strtol (x+1, &s, 16);
+
+ /* was it a numerical literal? */
+ if (x+1 != s)
+ {
+ /* prefer mov a,#0x00 */
+ if (val == 0 &&
+ ((a->rtrack.valueKnown && a->rtrack.value != 0) ||
+ !a->rtrack.valueKnown))
+ {
+ /* peepholes convert to clr a */
+ /* (regression test suite is slightly larger if "clr a" is used here) */
+ emitcode ("mov", "a,#0x00");
+ return 1;
+ }
+
+ if (a->rtrack.valueKnown)
+ {
+ /* already there? */
+ if (val == a->rtrack.value)
+ {
+ D(emitcode (";", "genFromRTrack acc==0x%02x", a->rtrack.value));
+ return 1;
+ }
+
+ /* can be calculated with an instruction
+ that does not change flags from acc itself? */
+ if (val == ((a->rtrack.value+1) & 0xff) )
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==0x%02x+1", val, a->rtrack.value));
+ emitcode ("inc", "a");
+ return 1;
+ }
+ if (val == ((a->rtrack.value-1) & 0xff) )
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==0x%02x-1", val, a->rtrack.value));
+ emitcode ("dec", "a");
+ return 1;
+ }
+ if (val == ((~a->rtrack.value) & 0xff) )
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==~0x%02x", val, a->rtrack.value));
+ emitcode ("cpl", "a");
+ return 1;
+ }
+ if (val == (((a->rtrack.value>>1) |
+ (a->rtrack.value<<7)) & 0xff))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==rr(0x%02x)", val, a->rtrack.value));
+ emitcode ("rr", "a");
+ return 1;
+ }
+ if (val == (((a->rtrack.value<<1) |
+ (a->rtrack.value>>7)) & 0xff ))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==rl(0x%02x)", val, a->rtrack.value));
+ emitcode ("rl", "a");
+ return 1;
+ }
+ if (val == ( ((a->rtrack.value & 0x0f)<<4) |
+ ((a->rtrack.value & 0xf0)>>4) ))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==swap(0x%02x)", val, a->rtrack.value));
+ emitcode ("swap", "a");
+ return 1;
+ }
+ /* Decimal Adjust Accumulator (da a) changes flags so not used */
+ }
+
+
+ {
+ unsigned int i;
+ char *ptr= rtrackGetLit(x);
+
+ if (x != ptr)
+ {
+ /* could get from register, fine */
+ emitcode ("mov", "a,%s", ptr);
+ return 1;
+ }
+
+ /* not yet giving up - try to calculate from register R0..R7 */
+ for (i = 0; i < 8; i++)
+ {
+ reg_info *r = &regs8051[rx_num_to_idx(i)];
+
+ if (a->rtrack.valueKnown && r->rtrack.valueKnown)
+ {
+ /* calculate with a single byte instruction from R0..R7? */
+ if (val == (a->rtrack.value | r->rtrack.value))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==0x%02x|0x%02x",
+ val, a->rtrack.value, r->rtrack.value));
+ emitcode ("orl", "a,%s",r->name);
+ return 1;
+ }
+ if (val == (a->rtrack.value & r->rtrack.value))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==0x%02x&0x%02x",
+ val, a->rtrack.value, r->rtrack.value));
+ emitcode ("anl", "a,%s", r->name);
+ return 1;
+ }
+ if (val == (a->rtrack.value ^ r->rtrack.value))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x==0x%02x^0x%02x",
+ val, a->rtrack.value, r->rtrack.value));
+ emitcode ("xrl", "a,%s", r->name);
+ return 1;
+ }
+ /* changes flags (does that matter?)
+ if (val == (a->rtrack.value + r->rtrack.value))
+ {
+ D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+%0x02x",
+ val, a->rtrack.value, r->rtrack.value));
+ emitcode ("add", "a,%s",r->name);
+ return 1;
+ }
+ so not used */
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Loads dptr with symbol (if needed)
+ */
+void rtrackLoadDptrWithSym (const char *x)
+{
+ if (enable != 1)
+ {
+ emitcode ("mov", "dptr,#%s", x);
+ return;
+ }
+
+ if (regs8051[DPL_IDX].rtrack.symbol &&
+ regs8051[DPH_IDX].rtrack.symbol)
+ {
+ /* rtrack.symbol for dph should look like "(something >> 8)" */
+ if ((!strcmp (x, regs8051[DPL_IDX].rtrack.symbol) &&
+ !strncmp (x, regs8051[DPH_IDX].rtrack.symbol + 1, strlen (x) ) &&
+ !strncmp (" >> 8)", regs8051[DPH_IDX].rtrack.symbol + 1 + strlen (x), 6)))
+ {
+ /* dptr already holds the symbol */
+ D(emitcode (";", "genFromRTrack dptr==#%s",x));
+ return;
+ }
+ }
+
+ emitcode ("mov", "dptr,#%s", x);
+}
+
+
+#if 0
+/* Loads index registers R0, R1 with symbol (if needed)
+ *
+ * R0, R1 index registers are already handled in gen.c (see AOP_INPREG)
+ */
+void rtrackLoadR0R1WithSym (const char *reg, const char *x)
+{
+ int regNum, regIdx;
+
+ if (enable != 1)
+ {
+ emitcode ("mov", "%s,#%s", reg, x );
+ return;
+ }
+
+ regNum = reg[1] - '0';
+ if (regNum == 0 || regNum == 1)
+ {
+ regIdx = rx_num_to_idx(regNum);
+ if ((NULL != regs8051[regIdx].rtrack.symbol) && !strcmp (x, regs8051[regIdx].rtrack.symbol))
+ {
+ /* register already holds the symbol */
+ D(emitcode (";", "genFromRTrack %s=#%s",reg,x));
+ return;
+ }
+ }
+
+ emitcode ("mov", "%s,#%s", reg, x );
+}
+#endif
diff --git a/src/mcs51/rtrack.h b/src/mcs51/rtrack.h
new file mode 100644
index 0000000..dfad2e0
--- /dev/null
+++ b/src/mcs51/rtrack.h
@@ -0,0 +1,28 @@
+/*-------------------------------------------------------------------------
+ rtrack.h - header file for tracking content of registers on an mcs51
+
+ Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-------------------------------------------------------------------------*/
+
+bool _mcs51_rtrackUpdate (const char *line);
+
+char * rtrackGetLit(const char *x);
+
+int rtrackMoveALit (const char *x);
+
+void rtrackLoadDptrWithSym (const char *x);
+void rtrackLoadR0R1WithSym (const char *reg, const char *x);