--- /dev/null
+/*-------------------------------------------------------------------------
+ gen.c - source file for code generation for the 68HC08
+
+ Hacked for the 68HC08 by Erik Petrich (2003)
+ Adapted from the 8051 code generator by:
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+ and - Jean-Louis VERN.jlvern@writeme.com (1999)
+ 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.
+
+ 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!
+
+-------------------------------------------------------------------------*/
+
+//#define D(x)
+#define D(x) x
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "SDCCglobl.h"
+#include "newalloc.h"
+
+#include "common.h"
+#include "SDCCpeeph.h"
+#include "ralloc.h"
+#include "gen.h"
+
+char *aopLiteral (value * val, int offset);
+char *aopLiteralLong (value * val, int offset, int size);
+extern int allocInfo;
+
+static char *zero = "#0x00";
+static char *one = "#0x01";
+static char *spname;
+
+char *fReturnhc08[] =
+{"a", "x", "_ret2", "_ret3"};
+unsigned fReturnSizeHC08 = 4; /* shared with ralloc.c */
+char **fReturn2 = fReturnhc08;
+
+
+static struct
+ {
+ short hxPushed;
+ short iyPushed;
+ short accInUse;
+ short inLine;
+ short debugLine;
+ short nRegsSaved;
+ int stackOfs;
+ int stackPushes;
+ short regsinuse;
+ set *sendSet;
+ }
+_G;
+
+static asmop *hc08_aop_pass[4];
+
+extern int hc08_ptrRegReq;
+extern int hc08_nRegs;
+extern FILE *codeOutFile;
+//static void saveRBank (int, iCode *, bool);
+static bool operandsEqu (operand * op1, operand * op2);
+static void loadRegFromConst (regs *reg, char *c);
+static char *aopName (asmop *aop);
+static asmop * newAsmop (short type);
+static char * aopAdrStr (asmop * aop, int loffset, bool bit16);
+#define RESULTONSTACK(x) \
+ (IC_RESULT(x) && IC_RESULT(x)->aop && \
+ IC_RESULT(x)->aop->type == AOP_STK )
+
+#define IS_AOP_HX(x) \
+ (((x)->type == AOP_REG) \
+ && ((x)->aopu.aop_reg[0] == hc08_reg_x) \
+ && ((x)->aopu.aop_reg[1] == hc08_reg_h) )
+
+#define IS_AOP_XA(x) \
+ (((x)->type == AOP_REG) \
+ && ((x)->aopu.aop_reg[0] == hc08_reg_a) \
+ && ((x)->aopu.aop_reg[1] == hc08_reg_x) )
+
+#define IS_AOP_A(x) \
+ (((x)->type == AOP_REG) \
+ && ((x)->aopu.aop_reg[0] == hc08_reg_a) \
+ && ((x)->size == 1) )
+
+#define IS_AOP_X(x) \
+ (((x)->type == AOP_REG) \
+ && ((x)->aopu.aop_reg[0] == hc08_reg_x) \
+ && ((x)->size == 1) )
+
+#define IS_AOP_H(x) \
+ (((x)->type == AOP_REG) \
+ && ((x)->aopu.aop_reg[0] == hc08_reg_h) \
+ && ((x)->size == 1) )
+
+#define CLRC emitcode("clc","")
+
+static lineNode *lineHead = NULL;
+static lineNode *lineCurr = NULL;
+
+#if 0
+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};
+#endif
+
+#define LSB 0
+#define MSB16 1
+#define MSB24 2
+#define MSB32 3
+
+#define AOP(op) op->aop
+#define AOP_TYPE(op) AOP(op)->type
+#define AOP_SIZE(op) AOP(op)->size
+#define AOP_OP(aop) aop->op
+
+
+/*-----------------------------------------------------------------*/
+/* emitcode - writes the code into a file : for now it is simple */
+/*-----------------------------------------------------------------*/
+static void
+emitcode (char *inst, char *fmt,...)
+{
+ va_list ap;
+ char lb[INITIAL_INLINEASM];
+ char *lbp = lb;
+
+ va_start (ap, fmt);
+
+ if (inst && *inst)
+ {
+ if (fmt && *fmt)
+ sprintf (lb, "%s\t", inst);
+ else
+ sprintf (lb, "%s", inst);
+ vsprintf (lb + (strlen (lb)), fmt, ap);
+ }
+ else
+ vsprintf (lb, fmt, ap);
+
+ while (isspace (*lbp))
+ lbp++;
+
+ if (lbp && *lbp)
+ lineCurr = (lineCurr ?
+ connectLine (lineCurr, newLineNode (lb)) :
+ (lineHead = newLineNode (lb)));
+ lineCurr->isInline = _G.inLine;
+ lineCurr->isDebug = _G.debugLine;
+
+ //printf("%s\n", lb);
+ va_end (ap);
+}
+
+static void
+emitBranch (char *branchop, symbol *tlbl)
+{
+ emitcode (branchop, "%05d$", (tlbl->key + 100));
+}
+
+static void
+emitLabel (symbol *tlbl)
+{
+ emitcode ("", "%05d$:", (tlbl->key +100));
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/* transferRegReg - Transfer from register(s) sreg to register(s) dreg. If */
+/* freesrc is true, sreg is marked free and available for */
+/* reuse. sreg and dreg must be of equal size */
+/*--------------------------------------------------------------------------*/
+static void
+transferRegReg (regs *sreg, regs *dreg, bool freesrc)
+{
+ int srcidx;
+ int dstidx;
+ char error = 0;
+
+ /* Nothing to do if no destination. */
+ if (!dreg)
+ return;
+
+ /* But it's definately an error if there's no source. */
+ if (!sreg)
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "NULL sreg in transferRegReg");
+ return;
+ }
+
+ emitcode ("", "; transferRegReg(%s,%s)",
+ sreg->name, dreg->name);
+
+ srcidx = sreg->rIdx;
+ dstidx = dreg->rIdx;
+
+ if (srcidx==dstidx)
+ return;
+
+ switch (dstidx)
+ {
+ case A_IDX:
+ switch (srcidx)
+ {
+ case H_IDX: /* H to A */
+ emitcode ("pshh", "");
+ emitcode ("pula", "");
+ break;
+ case X_IDX: /* X to A */
+ emitcode ("txa", "");
+ break;
+ default:
+ error=1;
+ }
+ break;
+ case H_IDX:
+ switch (srcidx)
+ {
+ case A_IDX: /* A to H */
+ emitcode ("psha", "");
+ emitcode ("pulh", "");
+ break;
+ case X_IDX: /* X to H */
+ emitcode ("pshx", "");
+ emitcode ("pulh", "");
+ break;
+ default:
+ error=1;
+ }
+ break;
+ case X_IDX:
+ switch (srcidx)
+ {
+ case A_IDX: /* A to X */
+ emitcode ("tax", "");
+ break;
+ case H_IDX: /* H to X */
+ emitcode ("pshh", "");
+ emitcode ("pulx", "");
+ break;
+ default:
+ error=1;
+ }
+ break;
+ case HX_IDX:
+ switch (srcidx)
+ {
+ case XA_IDX: /* XA to HX */
+ emitcode ("pshx", "");
+ emitcode ("pulh", "");
+ emitcode ("tax", "");
+ break;
+ default:
+ error=1;
+ }
+ break;
+ case XA_IDX:
+ switch (srcidx)
+ {
+ case HX_IDX: /* HX to XA */
+ emitcode ("txa", "");
+ emitcode ("pshh", "");
+ emitcode ("pulx", "");
+ break;
+ default:
+ error=1;
+ }
+ break;
+ default:
+ error=1;
+ }
+
+ wassertl (!error, "bad combo in transferRegReg");
+
+ if (freesrc)
+ hc08_freeReg(sreg);
+
+ dreg->aop = sreg->aop;
+ dreg->aopofs = sreg->aopofs;
+ dreg->isFree = FALSE;
+ hc08_useReg(dreg);
+}
+
+/*--------------------------------------------------------------------------*/
+/* pushReg - Push register reg onto the stack. If freereg is true, reg is */
+/* marked free and available for reuse. */
+/*--------------------------------------------------------------------------*/
+static int
+pushReg (regs *reg, bool freereg)
+{
+ int regidx = reg->rIdx;
+
+ switch (regidx)
+ {
+ case A_IDX:
+ emitcode ("psha", "");
+ _G.stackPushes++;
+ break;
+ case X_IDX:
+ emitcode ("pshx", "");
+ _G.stackPushes++;
+ break;
+ case H_IDX:
+ emitcode ("pshh", "");
+ _G.stackPushes++;
+ break;
+ case HX_IDX:
+ emitcode ("pshx", "");
+ emitcode ("pshh", "");
+ _G.stackPushes += 2;
+ break;
+ case XA_IDX:
+ emitcode ("psha", "");
+ emitcode ("pshx", "");
+ _G.stackPushes += 2;
+ break;
+ default:
+ break;
+ }
+ if (freereg)
+ hc08_freeReg(reg);
+ return -_G.stackOfs-_G.stackPushes;
+}
+
+/*--------------------------------------------------------------------------*/
+/* pullReg - Pull register reg off the stack. */
+/*--------------------------------------------------------------------------*/
+static void
+pullReg (regs *reg)
+{
+ int regidx = reg->rIdx;
+
+ switch (regidx)
+ {
+ case A_IDX:
+ emitcode ("pula", "");
+ _G.stackPushes--;
+ break;
+ case X_IDX:
+ emitcode ("pulx", "");
+ _G.stackPushes--;
+ break;
+ case H_IDX:
+ emitcode ("pulh", "");
+ _G.stackPushes--;
+ break;
+ case HX_IDX:
+ emitcode ("pulx", "");
+ emitcode ("pulh", "");
+ _G.stackPushes -= 2;
+ break;
+ case XA_IDX:
+ emitcode ("pula", "");
+ emitcode ("pulx", "");
+ _G.stackPushes -= 2;
+ break;
+ default:
+ break;
+ }
+ hc08_useReg(reg);
+ hc08_dirtyReg(reg, FALSE);
+}
+
+/*--------------------------------------------------------------------------*/
+/* pullNull - Discard n bytes off the top of the stack */
+/*--------------------------------------------------------------------------*/
+static void
+pullNull (int n)
+{
+ if (n)
+ {
+ emitcode("ais","#%d",n);
+ _G.stackPushes -= n;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* pushRegIfUsed - Push register reg if marked in use. Returns true if the */
+/* push was performed, false otherwise. */
+/*--------------------------------------------------------------------------*/
+static bool
+pushRegIfUsed (regs *reg)
+{
+ if (!reg->isFree)
+ {
+ pushReg (reg, TRUE);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/*--------------------------------------------------------------------------*/
+/* pullOrFreeReg - If needpull is true, register reg is pulled from the */
+/* stack. Otherwise register reg is marked as free. */
+/*--------------------------------------------------------------------------*/
+static void
+pullOrFreeReg (regs *reg, bool needpull)
+{
+ if (needpull)
+ pullReg (reg);
+ else
+ hc08_freeReg (reg);
+}
+
+/*--------------------------------------------------------------------------*/
+/* adjustStack - Adjust the stack pointer by n bytes. */
+/*--------------------------------------------------------------------------*/
+static void
+adjustStack (int n)
+{
+ _G.stackPushes -= n;
+ while (n)
+ {
+ if (n>127)
+ {
+ emitcode ("ais","#127");
+ n -= 127;
+ }
+ else if (n<-128)
+ {
+ emitcode ("ais","#-128");
+ n += 128;
+ }
+ else
+ {
+ emitcode ("ais", "#%d", n);
+ n = 0;
+ }
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* aopName - Return a string with debugging information about an asmop. */
+/*--------------------------------------------------------------------------*/
+static char *
+aopName (asmop *aop)
+{
+ static char buffer[256];
+ char *buf = buffer;
+
+ if (!aop)
+ return "(asmop*)NULL";
+
+ switch (aop->type)
+ {
+ case AOP_IMMD:
+ sprintf (buf,"IMMD(%s)", aop->aopu.aop_immd.aop_immd1);
+ return buf;
+ case AOP_LIT:
+ sprintf (buf,"LIT(%s)", aopLiteral (aop->aopu.aop_lit, 0));
+ return buf;
+ case AOP_DIR:
+ sprintf (buf,"DIR(%s)", aop->aopu.aop_dir);
+ return buf;
+ case AOP_EXT:
+ sprintf (buf,"EXT(%s)", aop->aopu.aop_dir);
+ return buf;
+ case AOP_SOF:
+ sprintf (buf,"SOF(%s)", OP_SYMBOL (aop->op)->name);
+ return buf;
+ case AOP_REG:
+ sprintf (buf, "REG(%s,%s,%s,%s)",
+ aop->aopu.aop_reg[3] ? aop->aopu.aop_reg[3]->name : "-",
+ aop->aopu.aop_reg[2] ? aop->aopu.aop_reg[2]->name : "-",
+ aop->aopu.aop_reg[1] ? aop->aopu.aop_reg[1]->name : "-",
+ aop->aopu.aop_reg[0] ? aop->aopu.aop_reg[0]->name : "-");
+ return buf;
+ case AOP_STK:
+ return "STK";
+ case AOP_STR:
+ return "STR";
+ default:
+ sprintf (buf,"?%d", aop->type);
+ return buf;
+ }
+
+ return "?";
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* loadRegFromAop - Load register reg from logical offset loffset of aop. */
+/*--------------------------------------------------------------------------*/
+static void
+loadRegFromAop (regs *reg, asmop *aop, int loffset)
+{
+ int regidx = reg->rIdx;
+
+ if (aop->stacked && aop->stk_aop[loffset])
+ {
+ loadRegFromAop (reg, aop->stk_aop[loffset], 0);
+ return;
+ }
+
+#if 0
+ printf("loadRegFromAop called\n");
+ if (!reg)
+ {
+ printf(" reg = NULL\n");
+ return;
+ }
+ printf(" reg = %s\n", reg->name);
+ if (!aop)
+ {
+ printf(" aop = NULL\n");
+ return;
+ }
+ printf(" aop->type = %d\n", aop->type);
+ printf(" loffset = %d\n", loffset);
+
+ if (aop->op)
+ printf(" aop has operand link\n");
+ else
+ printf(" aop missing operand link\n");
+ if (reg->aop)
+ printf(" reg has operand link\n");
+ else
+ printf(" reg missing operand link\n");
+#endif
+
+ emitcode ("", "; loadRegFromAop (%s, %s, %d)",
+ reg->name, aopName (aop), loffset);
+
+ /* If operand is volatile, we cannot optimize. */
+ if (!aop->op || isOperandVolatile (aop->op, FALSE))
+ goto forceload;
+
+
+ /* If this register already has this offset of the operand
+ then we need only mark it as in use. */
+ if (reg->aop && reg->aop->op && aop->op
+ && operandsEqu(reg->aop->op,aop->op)
+ && (reg->aopofs == loffset))
+ {
+ hc08_useReg(reg);
+ emitcode ("","; already had correct value for %s", reg->name);
+ return;
+ }
+
+ /* TODO: check to see if we can transfer from another register */
+
+ if (hc08_reg_h->aop && hc08_reg_h->aop->op && aop->op
+ && operandsEqu(hc08_reg_h->aop->op,aop->op)
+ && (hc08_reg_h->aopofs == loffset))
+ {
+ emitcode ("","; found correct value for %s in h", reg->name);
+ transferRegReg (hc08_reg_h, reg, FALSE);
+ hc08_useReg (reg);
+ return;
+ }
+
+
+ if (hc08_reg_x->aop && hc08_reg_x->aop->op && aop->op
+ && operandsEqu(hc08_reg_x->aop->op,aop->op)
+ && (hc08_reg_x->aopofs == loffset))
+ {
+ emitcode ("","; found correct value for %s in x", reg->name);
+ transferRegReg (hc08_reg_x, reg, FALSE);
+ hc08_useReg (reg);
+ return;
+ }
+
+ if (hc08_reg_a->aop && hc08_reg_a->aop->op && aop->op
+ && operandsEqu(hc08_reg_a->aop->op,aop->op)
+ && (hc08_reg_a->aopofs == loffset))
+ {
+ emitcode ("","; found correct value for %s in a", reg->name);
+ transferRegReg (hc08_reg_a, reg, FALSE);
+ hc08_useReg (reg);
+ return;
+ }
+
+forceload:
+
+ switch (regidx)
+ {
+ case A_IDX:
+ if (aop->type == AOP_REG)
+ {
+ if (loffset < aop->size)
+ transferRegReg(aop->aopu.aop_reg[loffset], reg, FALSE);
+ else
+ emitcode ("clra", ""); /* TODO: handle sign extension */
+ }
+ else
+ emitcode ("lda","%s", aopAdrStr (aop, loffset, FALSE));
+ break;
+ case X_IDX:
+ if (aop->type == AOP_REG)
+ {
+ if (loffset < aop->size)
+ transferRegReg(aop->aopu.aop_reg[loffset], reg, FALSE);
+ else
+ emitcode ("clrx", ""); /* TODO: handle sign extension */
+ }
+ else
+ emitcode ("ldx","%s", aopAdrStr (aop, loffset, FALSE));
+ break;
+ case H_IDX:
+ if (hc08_reg_a->isFree)
+ {
+ loadRegFromAop (hc08_reg_a, aop, loffset);
+ transferRegReg (hc08_reg_a, hc08_reg_h, TRUE);
+ }
+ else if (hc08_reg_x->isFree)
+ {
+ loadRegFromAop (hc08_reg_x, aop, loffset);
+ transferRegReg (hc08_reg_x, hc08_reg_h, TRUE);
+ }
+ else
+ {
+ pushReg (hc08_reg_a, TRUE);
+ loadRegFromAop (hc08_reg_a, aop, loffset);
+ transferRegReg (hc08_reg_a, hc08_reg_h, TRUE);
+ pullReg (hc08_reg_a);
+ }
+ break;
+ case HX_IDX:
+ if (IS_AOP_HX(aop))
+ break;
+ else if (IS_AOP_XA(aop))
+ transferRegReg (hc08_reg_xa, hc08_reg_hx, FALSE);
+ else if ((aop->type == AOP_DIR))
+ {
+ if (aop->size>(loffset+1))
+ emitcode ("ldhx","%s", aopAdrStr (aop, loffset+1, TRUE));
+ else
+ {
+ loadRegFromAop (hc08_reg_x, aop, loffset);
+ loadRegFromConst (hc08_reg_h, zero);
+ }
+ }
+ else if ((aop->type == AOP_LIT) || (aop->type == AOP_IMMD))
+ {
+ emitcode ("ldhx","%s", aopAdrStr (aop, loffset, TRUE));
+ }
+ else
+ {
+ bool needpula;
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, aop, loffset+1);
+ loadRegFromAop (hc08_reg_x, aop, loffset);
+ transferRegReg (hc08_reg_a, hc08_reg_h, TRUE);
+ pullOrFreeReg (hc08_reg_a, needpula);
+ }
+ break;
+ case XA_IDX:
+ if (IS_AOP_XA(aop))
+ break;
+ else if (IS_AOP_HX(aop))
+ transferRegReg (hc08_reg_hx, hc08_reg_xa, FALSE);
+ else
+ {
+ loadRegFromAop (hc08_reg_a, aop, loffset);
+ loadRegFromAop (hc08_reg_x, aop, loffset+1);
+ }
+ break;
+ }
+
+// ignore caching for now
+#if 0
+ reg->aop = aop;
+ reg->aopofs = loffset;
+#endif
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* forceStackedAop - Reserve space on the stack for asmop aop; when */
+/* freeAsmop is called with aop, the stacked data will */
+/* be copied to the original aop location and */
+/*--------------------------------------------------------------------------*/
+static asmop *
+forceStackedAop (asmop *aop)
+{
+ int loffset;
+ asmop *newaop = newAsmop (aop->type);
+ memcpy (newaop, aop, sizeof(*newaop));
+
+ emitcode("", "; forcedStackAop %s", aopName(aop));
+ for (loffset=0; loffset < newaop->size; loffset++)
+ {
+ asmop *aopsof = newAsmop (AOP_SOF);
+ aopsof->size = 1;
+ aopsof->aopu.aop_stk = pushReg (hc08_reg_a, FALSE);
+ aopsof->op = aop->op;
+ newaop->stk_aop[loffset] = aopsof;
+ }
+ newaop->stacked = 1;
+ return newaop;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* storeRegToAop - Store register reg to logical offset loffset of aop. */
+/*--------------------------------------------------------------------------*/
+static void
+storeRegToAop (regs *reg, asmop *aop, int loffset)
+{
+ int regidx = reg->rIdx;
+ #if 0
+ regs *otherreg;
+ int otheridx;
+ #endif
+
+ emitcode ("", "; storeRegToAop (%s, %s, %d), stacked=%d, isaddr=%d",
+ reg->name, aopName (aop), loffset, aop->stacked, aop->isaddr);
+
+ if ((reg->rIdx == HX_IDX) && aop->stacked
+ && (aop->stk_aop[loffset] || aop->stk_aop[loffset+1]))
+ {
+ storeRegToAop (hc08_reg_h, aop, loffset+1);
+ storeRegToAop (hc08_reg_x, aop, loffset);
+ return;
+ }
+
+ if ((reg->rIdx == XA_IDX) && aop->stacked
+ && (aop->stk_aop[loffset] || aop->stk_aop[loffset+1]))
+ {
+ storeRegToAop (hc08_reg_x, aop, loffset+1);
+ storeRegToAop (hc08_reg_a, aop, loffset);
+ return;
+ }
+
+ if (aop->stacked && aop->stk_aop[loffset])
+ {
+ storeRegToAop (reg, aop->stk_aop[loffset], 0);
+ return;
+ }
+
+ if (aop->type == AOP_STR)
+ {
+ if (loffset==0)
+ transferRegReg (reg, hc08_reg_x, FALSE);
+ else if (loffset==1)
+ transferRegReg (reg, hc08_reg_h, FALSE);
+ return;
+ }
+
+ switch (regidx)
+ {
+ case A_IDX:
+ if ((aop->type == AOP_REG) && (loffset < aop->size))
+ transferRegReg(reg, aop->aopu.aop_reg[loffset], FALSE);
+ else
+ emitcode ("sta","%s", aopAdrStr (aop, loffset, FALSE));
+ break;
+ case X_IDX:
+ if ((aop->type == AOP_REG) && (loffset < aop->size))
+ transferRegReg(reg, aop->aopu.aop_reg[loffset], FALSE);
+ else
+ emitcode ("stx","%s", aopAdrStr (aop, loffset, FALSE));
+ break;
+ case H_IDX:
+ if (hc08_reg_a->isFree)
+ {
+ transferRegReg (hc08_reg_h, hc08_reg_a, FALSE);
+ storeRegToAop (hc08_reg_a, aop, loffset);
+ hc08_freeReg (hc08_reg_a);
+ }
+ else if (hc08_reg_x->isFree)
+ {
+ transferRegReg (hc08_reg_h, hc08_reg_x, FALSE);
+ storeRegToAop (hc08_reg_x, aop, loffset);
+ hc08_freeReg (hc08_reg_x);
+ }
+ else
+ {
+ pushReg (hc08_reg_a, TRUE);
+ transferRegReg (hc08_reg_h, hc08_reg_a, FALSE);
+ storeRegToAop (hc08_reg_a, aop, loffset);
+ pullReg (hc08_reg_a);
+ }
+ break;
+ case HX_IDX:
+ if ((aop->type == AOP_DIR) )
+ {
+ emitcode("sthx","%s", aopAdrStr (aop, loffset+1, TRUE));
+ }
+ else if (IS_AOP_XA(aop))
+ transferRegReg(reg, hc08_reg_xa, FALSE);
+ else if (IS_AOP_HX(aop))
+ break;
+ else
+ {
+ bool needpula;
+ needpula = pushRegIfUsed (hc08_reg_a);
+ transferRegReg (hc08_reg_h, hc08_reg_a, FALSE);
+ storeRegToAop (hc08_reg_a, aop, loffset+1);
+ storeRegToAop (hc08_reg_x, aop, loffset);
+ pullOrFreeReg (hc08_reg_a, needpula);
+ }
+ break;
+ case XA_IDX:
+ if (IS_AOP_HX(aop))
+ transferRegReg(reg, hc08_reg_hx, FALSE);
+ else if (IS_AOP_XA(aop))
+ break;
+ else
+ {
+ storeRegToAop (hc08_reg_a, aop, loffset);
+ storeRegToAop (hc08_reg_x, aop, loffset+1);
+ }
+ break;
+ }
+
+/* Disable the register tracking for now */
+#if 0
+ //if (!reg->aop || (reg->aop && (reg->aop != aop)))
+ {
+ //if (reg->aop!=aop)
+ for (otheridx=0;otheridx<hc08_nRegs;otheridx++)
+ {
+ otherreg=hc08_regWithIdx(otheridx);
+ if (otherreg && otherreg->aop
+ && otherreg->aop->op && aop->op
+ && operandsEqu(otherreg->aop->op,aop->op)
+ && (otherreg->aopofs == loffset))
+ {
+ emitcode("","; marking %s stale", otherreg->name);
+ otherreg->aop=NULL;
+ }
+ }
+ if ((!hc08_reg_x->aop || !hc08_reg_h->aop) && hc08_reg_hx->aop)
+ {
+ hc08_reg_hx->aop = NULL;
+ emitcode("","; marking hx stale");
+ }
+ if ((!hc08_reg_x->aop || !hc08_reg_a->aop) && hc08_reg_xa->aop)
+ {
+ hc08_reg_xa->aop = NULL;
+ emitcode("","; marking xa stale");
+ }
+
+ reg->aop = aop;
+ reg->aopofs = loffset;
+ }
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* loadRegFromConst - Load register reg from constant c. */
+/*--------------------------------------------------------------------------*/
+static void
+loadRegFromConst (regs *reg, char *c)
+{
+ switch (reg->rIdx)
+ {
+ case A_IDX:
+ if (!strcmp(c,zero))
+ emitcode ("clra", "");
+ else
+ emitcode ("lda", "%s", c);
+ break;
+ case X_IDX:
+ if (!strcmp(c,zero))
+ emitcode ("clrx", "");
+ else
+ emitcode ("ldx", "%s", c);
+ break;
+ case H_IDX:
+ if (!strcmp(c,zero))
+ emitcode ("clrh", "");
+ else if (hc08_reg_a->isFree)
+ {
+ loadRegFromConst (hc08_reg_a, c);
+ transferRegReg (hc08_reg_a, hc08_reg_h, TRUE);
+ }
+ else if (hc08_reg_x->isFree)
+ {
+ loadRegFromConst (hc08_reg_x, c);
+ transferRegReg (hc08_reg_x, hc08_reg_h, TRUE);
+ }
+ else
+ {
+ pushReg (hc08_reg_a, TRUE);
+ loadRegFromConst (hc08_reg_a, c);
+ transferRegReg (hc08_reg_a, hc08_reg_h, TRUE);
+ pullReg (hc08_reg_a);
+ }
+ break;
+ case HX_IDX:
+ emitcode ("ldhx", "%s", c);
+ break;
+ case XA_IDX:
+ emitcode ("lda", "%s", c);
+ emitcode ("ldx", "%s >> 8", c);
+ break;
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "Bad rIdx in loadRegFromConst");
+ return;
+ }
+ hc08_useReg (reg);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* storeConstToAop- Store constant c to logical offset loffset of asmop aop.*/
+/*--------------------------------------------------------------------------*/
+static void
+storeConstToAop (char *c, asmop *aop, int loffset)
+{
+ if (aop->stacked && aop->stk_aop[loffset])
+ {
+ storeConstToAop (c, aop->stk_aop[loffset], 0);
+ return;
+ }
+
+ switch (aop->type)
+ {
+ case AOP_DIR:
+ if (!strcmp(c,zero))
+ emitcode ("clr", "%s", aopAdrStr (aop, loffset, FALSE));
+ else
+ emitcode ("mov", "%s,%s", c, aopAdrStr (aop, loffset, FALSE));
+ break;
+ case AOP_REG:
+ if (loffset>(aop->size-1))
+ break;
+ loadRegFromConst (aop->aopu.aop_reg[loffset], c);
+ break;
+ default:
+ if (hc08_reg_a->isFree)
+ {
+ loadRegFromConst (hc08_reg_a, c);
+ storeRegToAop( hc08_reg_a, aop, loffset);
+ hc08_freeReg (hc08_reg_a);
+ }
+ else if (hc08_reg_x->isFree)
+ {
+ loadRegFromConst (hc08_reg_x, c);
+ storeRegToAop( hc08_reg_x, aop, loffset);
+ hc08_freeReg (hc08_reg_x);
+ }
+ else
+ {
+ pushReg (hc08_reg_a, TRUE);
+ loadRegFromConst (hc08_reg_a, c);
+ storeRegToAop( hc08_reg_a, aop, loffset);
+ pullReg (hc08_reg_a);
+ }
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* storeRegSignToUpperAop - If isSigned is true, the sign bit of register */
+/* reg is extended to fill logical offsets loffset */
+/* and above of asmop aop. Otherwise, logical */
+/* offsets loffset and above of asmop aop are */
+/* zeroed. reg must be an 8-bit register. */
+/*--------------------------------------------------------------------------*/
+static void
+storeRegSignToUpperAop (regs *reg, asmop *aop, int loffset, bool isSigned)
+{
+// int regidx = reg->rIdx;
+ int size = aop->size;
+
+ if (size<=loffset)
+ return;
+
+ if (!isSigned)
+ {
+ /* Unsigned case */
+ while (loffset<size)
+ storeConstToAop(zero, aop, loffset++);
+ }
+ else
+ {
+ /* Signed case */
+ transferRegReg (reg, hc08_reg_a, FALSE);
+ emitcode ("rola","");
+ emitcode ("clra","");
+ emitcode ("sbc", "#0");
+ hc08_useReg (hc08_reg_a);
+ while (loffset<size)
+ storeRegToAop (hc08_reg_a, aop, loffset++);
+ hc08_freeReg (hc08_reg_a);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* storeRegToFullAop - Store register reg to asmop aop with appropriate */
+/* padding and/or truncation as needed. If isSigned is */
+/* true, sign extension will take place in the padding. */
+/*--------------------------------------------------------------------------*/
+static void
+storeRegToFullAop (regs *reg, asmop *aop, bool isSigned)
+{
+ int regidx = reg->rIdx;
+ int size = aop->size;
+
+ switch (regidx)
+ {
+ case A_IDX:
+ case X_IDX:
+ case H_IDX:
+ storeRegToAop (reg, aop, 0);
+ storeRegSignToUpperAop (reg, aop, 1, isSigned);
+ break;
+ case HX_IDX:
+ if (size==1)
+ {
+ storeRegToAop (hc08_reg_x, aop, 0);
+ }
+ else
+ {
+ storeRegToAop (reg, aop, 0);
+ storeRegSignToUpperAop (hc08_reg_h, aop, 2, isSigned);
+ }
+ break;
+ case XA_IDX:
+ if (size==1)
+ {
+ storeRegToAop (hc08_reg_a, aop, 0);
+ }
+ else
+ {
+ storeRegToAop (reg, aop, 0);
+ storeRegSignToUpperAop (hc08_reg_x, aop, 2, isSigned);
+ }
+ break;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* transferAopAop - Transfer the value at logical offset srcofs of asmop */
+/* srcaop to logical offset dstofs of asmop dstofs. */
+/*--------------------------------------------------------------------------*/
+static void
+transferAopAop (asmop *srcaop, int srcofs, asmop *dstaop, int dstofs)
+{
+ bool needpula = FALSE;
+ regs *reg = NULL;
+ int regIdx;
+ bool keepreg = FALSE;
+
+ if (srcaop->stacked && srcaop->stk_aop[srcofs])
+ {
+ transferAopAop (srcaop->stk_aop[srcofs], 0, dstaop, dstofs);
+ return;
+ }
+
+ if (dstaop->stacked && dstaop->stk_aop[srcofs])
+ {
+ transferAopAop (srcaop, srcofs, dstaop->stk_aop[dstofs], 0);
+ return;
+ }
+
+// emitcode ("", "; transferAopAop (%s, %d, %s, %d)",
+// aopName (srcaop), srcofs, aopName (dstaop), dstofs);
+// emitcode ("", "; srcaop->type = %d", srcaop->type);
+// emitcode ("", "; dstaop->type = %d", dstaop->type);
+
+ if (dstofs >= dstaop->size)
+ return;
+
+ if ((dstaop->type == AOP_DIR)
+ && ((srcaop->type == AOP_DIR) || (srcaop->type == AOP_LIT)) )
+ {
+ emitcode("mov", "%s,%s", aopAdrStr(srcaop, srcofs, FALSE),
+ aopAdrStr(dstaop, dstofs, FALSE));
+ return;
+ }
+
+ if (dstaop->type == AOP_REG)
+ {
+ regIdx = dstaop->aopu.aop_reg[dstofs]->rIdx;
+ if ((regIdx == A_IDX) || (regIdx == X_IDX))
+ {
+ reg = dstaop->aopu.aop_reg[dstofs];
+ keepreg = TRUE;
+ }
+ }
+
+ if ((srcaop->type == AOP_REG) && (srcaop->aopu.aop_reg[srcofs]))
+ {
+ regIdx = srcaop->aopu.aop_reg[srcofs]->rIdx;
+ if ((regIdx == A_IDX) || (regIdx == X_IDX))
+ {
+ reg = srcaop->aopu.aop_reg[srcofs];
+ keepreg = TRUE;
+ }
+ }
+
+ if (!reg)
+ {
+ if (hc08_reg_a->isFree)
+ reg = hc08_reg_a;
+ else if (hc08_reg_x->isFree)
+ reg = hc08_reg_x;
+ else
+ {
+ pushReg (hc08_reg_a, TRUE);
+ needpula = TRUE;
+ reg = hc08_reg_a;
+ }
+ }
+
+ loadRegFromAop (reg, srcaop, srcofs);
+ storeRegToAop (reg, dstaop, dstofs);
+
+ if (!keepreg)
+ pullOrFreeReg (hc08_reg_a, needpula);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* accopWithMisc - Emit accumulator modifying instruction accop with the */
+/* parameter param. */
+/*--------------------------------------------------------------------------*/
+static void
+accopWithMisc (char *accop, char *param)
+{
+ emitcode (accop, "%s", param);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+}
+
+/*--------------------------------------------------------------------------*/
+/* accopWithAop - Emit accumulator modifying instruction accop with the */
+/* byte at logical offset loffset of asmop aop. */
+/* Supports: adc, add, and, bit, cmp, eor, ora, sbc, sub */
+/*--------------------------------------------------------------------------*/
+static void
+accopWithAop (char *accop, asmop *aop, int loffset)
+{
+ if (aop->stacked && aop->stk_aop[loffset])
+ {
+ accopWithAop (accop, aop->stk_aop[loffset], 0);
+ return;
+ }
+
+ if (aop->type == AOP_REG)
+ {
+ pushReg (aop->aopu.aop_reg[loffset], FALSE);
+ emitcode (accop, "1,s");
+ pullNull (1);
+ }
+ else
+ emitcode (accop, "%s", aopAdrStr (aop, loffset, FALSE));
+
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* rmwWithReg - Emit read/modify/write instruction rmwop with register reg. */
+/* byte at logical offset loffset of asmop aop. Register reg */
+/* must be 8-bit. */
+/* Supports: com, dec, inc, lsl, lsr, neg, rol, ror */
+/*--------------------------------------------------------------------------*/
+static void
+rmwWithReg (char *rmwop, regs *reg)
+{
+ char rmwbuf[10];
+ char *rmwaop = rmwbuf;
+
+ if (reg->rIdx == A_IDX)
+ {
+ sprintf(rmwaop,"%sa", rmwop);
+ emitcode (rmwaop, "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ }
+ else if (reg->rIdx == X_IDX)
+ {
+ sprintf(rmwaop,"%sx", rmwop);
+ emitcode (rmwaop, "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ }
+ else if (hc08_reg_a->isFree)
+ {
+ transferRegReg(reg, hc08_reg_a, FALSE);
+ sprintf(rmwaop,"%sa", rmwop);
+ emitcode (rmwaop, "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ transferRegReg(hc08_reg_a, reg, TRUE);
+ }
+ else
+ {
+ pushReg (reg, FALSE);
+ emitcode (rmwop, "1,s");
+ pullReg (reg);
+ hc08_dirtyReg (reg, FALSE);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* accopWithAop - Emit read/modify/write instruction rmwop with the byte at */
+/* logical offset loffset of asmop aop. */
+/* Supports: com, dec, inc, lsl, lsr, neg, rol, ror */
+/*--------------------------------------------------------------------------*/
+static void
+rmwWithAop (char *rmwop, asmop *aop, int loffset)
+{
+ bool needpula = FALSE;
+
+ if (aop->stacked && aop->stk_aop[loffset])
+ {
+ rmwWithAop (rmwop, aop->stk_aop[loffset], 0);
+ return;
+ }
+
+ switch (aop->type)
+ {
+ case AOP_REG:
+ rmwWithReg (rmwop, aop->aopu.aop_reg[loffset]);
+ break;
+ case AOP_EXT:
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, aop, loffset);
+ rmwWithReg (rmwop, hc08_reg_a);
+ storeRegToAop (hc08_reg_a, aop, loffset);
+ pullOrFreeReg (hc08_reg_a, needpula);
+ break;
+ default:
+ emitcode (rmwop, "%s", aopAdrStr (aop, loffset, FALSE));
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* newAsmop - creates a new asmOp */
+/*-----------------------------------------------------------------*/
+static asmop *
+newAsmop (short type)
+{
+ asmop *aop;
+
+ aop = Safe_calloc (1, sizeof (asmop));
+ aop->type = type;
+ aop->op = NULL;
+ return aop;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* pointerCode - returns the code for a pointer type */
+/*-----------------------------------------------------------------*/
+static int
+pointerCode (sym_link * etype)
+{
+
+ return PTR_TYPE (SPEC_OCLS (etype));
+
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* aopForSym - for a true symbol */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForSym (iCode * ic, symbol * sym, bool result)
+{
+ asmop *aop;
+ memmap *space;
+
+ wassertl (ic != NULL, "Got a null iCode");
+ wassertl (sym != NULL, "Got a null symbol");
+
+// printf("in aopForSym for symbol %s\n", sym->name);
+
+ space = SPEC_OCLS (sym->etype);
+
+ /* if already has one */
+ if (sym->aop)
+ {
+ return sym->aop;
+ }
+
+ /* special case for a function */
+ if (IS_FUNC (sym->type))
+ {
+ sym->aop = aop = newAsmop (AOP_IMMD);
+ aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
+ strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
+ aop->size = FPTRSIZE;
+ return aop;
+ }
+
+ /* if it is in direct space */
+ if (IN_DIRSPACE (space))
+ {
+ sym->aop = aop = newAsmop (AOP_DIR);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ return aop;
+ }
+
+ /* if it is in far space */
+ if (IN_FARSPACE (space))
+ {
+ sym->aop = aop = newAsmop (AOP_EXT);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ return aop;
+ }
+
+ if (IN_STACK (sym->etype))
+ {
+ sym->aop = aop = newAsmop (AOP_SOF);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ aop->aopu.aop_stk = sym->stack;
+ return aop;
+ }
+
+
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "aopForSym should never reach here");
+
+ exit(1);
+
+ /* if it is in code space */
+ if (IN_CODESPACE (space))
+ aop->code = 1;
+
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForRemat - rematerialzes an object */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForRemat (symbol * sym)
+{
+ iCode *ic = sym->rematiCode;
+ asmop *aop = newAsmop (AOP_IMMD);
+ int ptr_type=0;
+ int val = 0;
+
+ for (;;)
+ {
+ if (ic->op == '+')
+ val += (int) operandLitValue (IC_RIGHT (ic));
+ else if (ic->op == '-')
+ val -= (int) operandLitValue (IC_RIGHT (ic));
+ else if (IS_CAST_ICODE(ic)) {
+ sym_link *from_type = operandType(IC_RIGHT(ic));
+ aop->aopu.aop_immd.from_cast_remat = 1;
+ ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
+ ptr_type = DCL_TYPE(from_type);
+ if (ptr_type == IPOINTER) {
+ // bug #481053
+ ptr_type = POINTER;
+ }
+ continue ;
+ } else break;
+
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ }
+
+ if (val)
+ sprintf (buffer, "(%s %c 0x%04x)",
+ OP_SYMBOL (IC_LEFT (ic))->rname,
+ val >= 0 ? '+' : '-',
+ abs (val) & 0xffff);
+ else
+ strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
+
+ aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
+ strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
+ /* set immd2 field if required */
+ if (aop->aopu.aop_immd.from_cast_remat) {
+ sprintf(buffer,"#0x%02x",ptr_type);
+ aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
+ strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
+ }
+
+ 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 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 (strcmp (sym1->rname, sym2->rname) == 0)
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* sameRegs - two asmops have the same registers */
+/*-----------------------------------------------------------------*/
+static bool
+sameRegs (asmop * aop1, asmop * aop2)
+{
+ int i;
+
+ if (aop1 == aop2)
+ return TRUE;
+
+// if (aop1->size != aop2->size)
+// return FALSE;
+
+ if (aop1->type == aop2->type)
+ {
+ switch (aop1->type)
+ {
+ case AOP_REG:
+ for (i = 0; i < aop1->size; i++)
+ if (aop1->aopu.aop_reg[i] !=
+ aop2->aopu.aop_reg[i])
+ return FALSE;
+ return TRUE;
+ case AOP_SOF:
+ return (aop1->aopu.aop_stk == aop2->aopu.aop_stk);
+ case AOP_DIR:
+ case AOP_EXT:
+ return (!strcmp (aop1->aopu.aop_dir, aop2->aopu.aop_dir));
+ }
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopOp - allocates an asmop for an operand : */
+/*-----------------------------------------------------------------*/
+static void
+aopOp (operand * op, iCode * ic, bool result)
+{
+ asmop *aop = NULL;
+ symbol *sym;
+ int i;
+
+ if (!op)
+ return;
+
+ // Is this a pointer set result?
+ //
+ if ((op==IC_RESULT (ic)) && POINTER_SET (ic))
+ {
+ }
+
+// printf("checking literal\n");
+ /* if this a literal */
+ if (IS_OP_LITERAL (op))
+ {
+ op->aop = aop = newAsmop (AOP_LIT);
+ aop->aopu.aop_lit = op->operand.valOperand;
+ aop->size = getSize (operandType (op));
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ return;
+ }
+
+// printf("checking pre-existing\n");
+ /* if already has a asmop then continue */
+ if (op->aop )
+ {
+ op->aop->op = op;
+ op->aop->isaddr = op->isaddr;
+ return;
+ }
+
+// printf("checking underlying sym\n");
+ /* if the underlying symbol has a aop */
+ if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
+ {
+ op->aop = aop = Safe_calloc(1, sizeof(*aop));
+ memcpy (aop, OP_SYMBOL (op)->aop, sizeof(*aop));
+ //op->aop = aop = OP_SYMBOL (op)->aop;
+ aop->size = getSize( operandType (op));
+ //printf ("reusing underlying symbol %s\n",OP_SYMBOL (op)->name);
+ //printf (" with size = %d\n", aop->size);
+
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ /* if (aop->isaddr & IS_ITEMP (op))
+ {
+ aop->psize=aop->size;
+ aop->size = getSize( operandType (op)->next);
+ } */
+ return;
+ }
+
+// printf("checking true sym\n");
+ /* if this is a true symbol */
+ if (IS_TRUE_SYMOP (op))
+ {
+ op->aop = aop = aopForSym (ic, OP_SYMBOL (op), result);
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ //printf ("new symbol %s\n", OP_SYMBOL (op)->name);
+ //printf (" with size = %d\n", aop->size);
+ return;
+ }
+
+ /* this is a temporary : this has
+ only four choices :
+ a) register
+ b) spillocation
+ c) rematerialize
+ d) conditional
+ e) can be a return use only */
+
+ sym = OP_SYMBOL (op);
+
+// printf("checking conditional\n");
+ /* if the type is a conditional */
+ if (sym->regType == REG_CND)
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_CRY);
+ aop->size = 0;
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ return;
+ }
+
+// printf("checking spilt\n");
+ /* if it is spilt then two situations
+ a) is rematerialize
+ b) has a spill location */
+ if (sym->isspilt || sym->nRegs == 0)
+ {
+
+// printf("checking remat\n");
+ /* rematerialize it NOW */
+ if (sym->remat)
+ {
+ sym->aop = op->aop = aop =
+ aopForRemat (sym);
+ aop->size = getSize (sym->type);
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ /* if (aop->isaddr & IS_ITEMP (op))
+ {
+ aop->psize=aop->size;
+ aop->size = getSize( operandType (op)->next);
+ } */
+ return;
+ }
+
+// printf("checking accuse\n");
+ if (sym->accuse)
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_REG);
+ aop->size = getSize (sym->type);
+ switch (sym->accuse)
+ {
+ case ACCUSE_XA:
+ aop->aopu.aop_reg[0] = hc08_reg_a;
+ aop->aopu.aop_reg[1] = hc08_reg_x;
+ break;
+ case ACCUSE_HX:
+ aop->aopu.aop_reg[0] = hc08_reg_x;
+ aop->aopu.aop_reg[1] = hc08_reg_h;
+ break;
+ }
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ return;
+ }
+
+// printf("checking ruonly\n");
+#if 1
+ if (sym->ruonly)
+ {
+ unsigned i;
+
+ aop = op->aop = sym->aop = newAsmop (AOP_STR);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < fReturnSizeHC08; i++)
+ aop->aopu.aop_str[i] = fReturn2[i];
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ return;
+ }
+#endif
+ /* else spill location */
+// printf("checking spill loc\n");
+// if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
+ if (sym->usl.spillLoc && sym->usl.spillLoc->aop
+ && sym->usl.spillLoc->aop->size != getSize (sym->type))
+ {
+ /* force a new aop if sizes differ */
+ sym->usl.spillLoc->aop = NULL;
+ //printf ("forcing new aop\n");
+ }
+ sym->aop = op->aop = aop =
+ aopForSym (ic, sym->usl.spillLoc, result);
+ aop->size = getSize (sym->type);
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+ //printf ("spill symbol %s\n", OP_SYMBOL (op)->name);
+ //printf (" with size = %d\n", aop->size);
+ /* if (aop->isaddr & IS_ITEMP (op))
+ {
+ aop->psize=aop->size;
+ aop->size = getSize( operandType (op)->next);
+ } */
+ return;
+ }
+
+// printf("assuming register\n");
+ /* 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];
+ aop->op = op;
+ aop->isaddr = op->isaddr;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAsmop - free up the asmop given to an operand */
+/*----------------------------------------------------------------*/
+static void
+freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
+{
+ asmop *aop;
+
+ if (!op)
+ aop = aaop;
+ else
+ aop = op->aop;
+
+ if (!aop)
+ return;
+
+ if (aop->freed)
+ goto dealloc;
+
+ aop->freed = 1;
+
+ if (aop->stacked)
+ {
+ int stackAdjust;
+ int loffset;
+
+ emitcode ("","; freeAsmop restoring stacked %s", aopName(aop));
+ aop->stacked = 0;
+ stackAdjust = 0;
+ for (loffset=0; loffset<aop->size; loffset++)
+ if (aop->stk_aop[loffset])
+ {
+ transferAopAop (aop->stk_aop[loffset], 0, aop, loffset);
+ stackAdjust++;
+ }
+ pullNull (stackAdjust);
+ }
+
+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;
+ }
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* aopDerefAop - treating the aop parameter as a pointer, return */
+/* an asmop for the object it references */
+/*-----------------------------------------------------------------*/
+asmop *
+aopDerefAop (asmop *aop)
+{
+ int adr;
+ char *s = buffer;
+ char *rs;
+ asmop *newaop = NULL;
+ sym_link *type, *etype;
+ int p_type;
+
+ emitcode ("", "; aopDerefAop(%s)", aopName(aop));
+ if (aop->op)
+ {
+
+ type = operandType (aop->op);
+ etype = getSpec (type);
+ /* if op 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));
+ }
+ }
+ else
+ p_type = UPOINTER;
+
+ switch (aop->type)
+ {
+ case AOP_IMMD:
+ if (p_type == POINTER)
+ newaop = newAsmop (AOP_DIR);
+ else
+ newaop = newAsmop (AOP_EXT);
+ newaop->aopu.aop_dir = aop->aopu.aop_immd.aop_immd1;
+ break;
+ case AOP_LIT:
+ adr = (int) floatFromVal (aop->aopu.aop_lit);
+ if (p_type == POINTER)
+ adr &= 0xff;
+
+ if (adr<0x100)
+ {
+ newaop = newAsmop (AOP_DIR);
+ sprintf (s, "0x%02x",adr);
+ }
+ else
+ {
+ newaop = newAsmop (AOP_EXT);
+ sprintf (s, "0x%04x",adr);
+ }
+ rs = Safe_calloc (1, strlen (s) + 1);
+ strcpy (rs, s);
+ newaop->aopu.aop_dir = rs;
+ break;
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "unsupported asmop");
+ return NULL;
+ }
+
+
+ return newaop;
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* aopAdrStr - for referencing the address of the aop */
+/*-----------------------------------------------------------------*/
+static char *
+aopAdrStr (asmop * aop, int loffset, bool bit16)
+{
+ char *s = buffer;
+ char *rs;
+ int offset = aop->size - 1 - loffset;
+
+
+ /* offset is greater than
+ size then zero */
+ if (loffset > (aop->size - 1) &&
+ aop->type != AOP_LIT)
+ return zero;
+
+ /* depending on type */
+ switch (aop->type)
+ {
+
+ case AOP_IMMD:
+ if (aop->aopu.aop_immd.from_cast_remat && (loffset == (aop->size-1))) {
+ sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
+ } else if (bit16)
+ sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
+ else if (loffset)
+ {
+ if (loffset!=1)
+ sprintf (s, "#(%s >> %d)",
+ aop->aopu.aop_immd.aop_immd1,
+ loffset * 8);
+ else
+ sprintf (s, "#>%s",
+ aop->aopu.aop_immd.aop_immd1);
+ }
+ else
+ sprintf (s, "#%s",
+ aop->aopu.aop_immd.aop_immd1);
+ rs = Safe_calloc (1, strlen (s) + 1);
+ strcpy (rs, s);
+ return rs;
+
+ case AOP_DIR:
+ if (offset)
+ sprintf (s, "*(%s + %d)",
+ aop->aopu.aop_dir,
+ offset);
+ else
+ sprintf (s, "*%s", aop->aopu.aop_dir);
+ rs = Safe_calloc (1, strlen (s) + 1);
+ strcpy (rs, s);
+ return rs;
+
+ case AOP_EXT:
+ if (offset)
+ sprintf (s, "(%s + %d)",
+ aop->aopu.aop_dir,
+ offset);
+ else
+ sprintf (s, "%s", aop->aopu.aop_dir);
+ rs = Safe_calloc (1, strlen (s) + 1);
+ strcpy (rs, s);
+ return rs;
+
+ case AOP_REG:
+ return aop->aopu.aop_reg[loffset]->name;
+
+ case AOP_LIT:
+ if (bit16)
+ return aopLiteralLong (aop->aopu.aop_lit, loffset, 2);
+ else
+ return aopLiteral (aop->aopu.aop_lit, loffset);
+
+ case AOP_STR:
+ aop->coff = offset;
+ return aop->aopu.aop_str[loffset];
+
+ case AOP_SOF:
+ sprintf (s, "%d,s", _G.stackOfs + _G.stackPushes + aop->aopu.aop_stk
+ + offset + 1);
+ rs = Safe_calloc (1, strlen (s) + 1);
+ strcpy (rs, s);
+ return rs;
+
+ }
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "aopAdrStr got unsupported aop->type");
+ exit (1);
+}
+
+
+
+
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* opIsGptr: returns non-zero if the passed operand is */
+/* a generic pointer type. */
+/*-----------------------------------------------------------------*/
+static int
+opIsGptr (operand * op)
+{
+ sym_link *type = operandType (op);
+
+ if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
+ {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* getDataSize - get the operand data size */
+/*-----------------------------------------------------------------*/
+static int
+getDataSize (operand * op)
+{
+ int size;
+ size = AOP_SIZE (op);
+ return size;
+}
+
+/*-----------------------------------------------------------------*/
+/* outAcc - output Acc */
+/*-----------------------------------------------------------------*/
+static void
+outAcc (operand * result)
+{
+ int size, offset;
+ size = getDataSize (result);
+ if (size)
+ {
+ storeRegToAop (hc08_reg_a, AOP (result), 0);
+ size--;
+ offset = 1;
+ /* unsigned or positive */
+ while (size--)
+ {
+ storeConstToAop (zero, AOP (result), offset++);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitC - output a bit C */
+/*-----------------------------------------------------------------*/
+static void
+outBitC (operand * result)
+{
+
+#if 0
+ /* if the result is bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ aopPut (AOP (result), "c", 0);
+ else
+#endif
+ {
+ emitcode ("clra", "");
+ emitcode ("rola", "");
+ outAcc (result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitNV - output a bit N^V */
+/*-----------------------------------------------------------------*/
+static void
+outBitNV (operand * result)
+{
+ symbol *tlbl, *tlbl1;
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ emitBranch ("blt", tlbl);
+ loadRegFromConst (hc08_reg_a, zero);
+ emitBranch ("bra", tlbl1);
+ emitLabel (tlbl);
+ loadRegFromConst (hc08_reg_a, one);
+ emitLabel (tlbl1);
+ outAcc (result);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* asmopToBool - Emit code to convert an asmop to a boolean. */
+/* Result left in A (0=FALSE, 1=TRUE) if ResultInA, */
+/* otherwise result left in Z flag (1=FALSE, 0=TRUE) */
+/*-----------------------------------------------------------------*/
+static void
+asmopToBool (asmop *aop, bool resultInA)
+{
+ symbol *tlbl, *tlbl1;
+ int size = aop->size;
+ bool needpula = FALSE;
+ bool flagsonly = TRUE;
+ int offset = 0;
+
+
+ if (resultInA)
+ hc08_freeReg(hc08_reg_a);
+
+ switch (aop->type)
+ {
+ case AOP_REG:
+ if (IS_AOP_A(aop))
+ {
+ emitcode ("tsta", "");
+ flagsonly = FALSE;
+ }
+ else if (IS_AOP_X(aop))
+ emitcode ("tstx", "");
+ else if (IS_AOP_H(aop))
+ {
+ if (hc08_reg_a->isFree)
+ {
+ transferRegReg (hc08_reg_h,hc08_reg_a, FALSE);
+ emitcode ("tsta", "");
+ flagsonly = FALSE;
+ hc08_freeReg(hc08_reg_a);
+ }
+ else if (hc08_reg_x->isFree)
+ {
+ transferRegReg (hc08_reg_h,hc08_reg_x, FALSE);
+ emitcode ("tstx", "");
+ hc08_freeReg(hc08_reg_x);
+ }
+ else
+ {
+ emitcode ("pshh", "");
+ emitcode ("tst", "1,s");
+ emitcode ("ais", "#1");
+ }
+ }
+ else if (IS_AOP_HX(aop))
+ emitcode ("cphx", zero);
+ else if (IS_AOP_XA(aop))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ emitcode ("tsta", "");
+ emitcode ("bne", "%05d$", (tlbl->key + 100));
+ emitcode ("tstx", "");
+ emitcode ("", "%05d$:", (tlbl->key + 100));
+ }
+ else
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "Bad rIdx in asmToBool");
+ return;
+ case AOP_EXT:
+ if (resultInA)
+ needpula = FALSE;
+ else
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, aop, 0);
+ for (offset=1; offset<size; offset++)
+ accopWithAop ("ora", aop, offset);
+ if (needpula)
+ pullReg (hc08_reg_a);
+ else
+ {
+ hc08_freeReg (hc08_reg_a);
+ flagsonly = FALSE;
+ }
+ break;
+ default:
+ if (size==1)
+ {
+ if (resultInA)
+ {
+ loadRegFromAop (hc08_reg_a, aop, 0);
+ hc08_freeReg (hc08_reg_a);
+ flagsonly = FALSE;
+ }
+ else
+ emitcode ("tst", "%s", aopAdrStr (aop, 0, FALSE));
+ break;
+ }
+ else if (size==2)
+ {
+ if (hc08_reg_a->isFree)
+ {
+ loadRegFromAop (hc08_reg_a, aop, 0);
+ accopWithAop ("ora", aop, 1);
+ hc08_freeReg (hc08_reg_a);
+ flagsonly = FALSE;
+ }
+ else
+ {
+ tlbl = newiTempLabel (NULL);
+ emitcode ("tst", "%s", aopAdrStr (aop, 0, FALSE));
+ emitcode ("bne", "%05d$", (tlbl->key + 100));
+ emitcode ("tst", "%s", aopAdrStr (aop, 1, FALSE));
+ emitcode ("", "%05d$:", (tlbl->key + 100));
+ break;
+ }
+ }
+ else
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, aop, 0);
+ for (offset=1; offset<size; offset++)
+ accopWithAop ("ora", aop, offset);
+ if (needpula)
+ pullReg (hc08_reg_a);
+ else
+ {
+ hc08_freeReg (hc08_reg_a);
+ flagsonly = FALSE;
+ }
+ }
+ }
+
+ if (resultInA)
+ {
+ tlbl = newiTempLabel (NULL);
+
+ if (flagsonly)
+ {
+ tlbl1 = newiTempLabel (NULL);
+ emitBranch ("bne", tlbl1);
+ loadRegFromConst (hc08_reg_a, zero);
+ emitBranch ("bra", tlbl);
+ emitLabel (tlbl1);
+ loadRegFromConst (hc08_reg_a, one);
+ }
+ else
+ {
+ emitBranch ("beq", tlbl);
+ loadRegFromConst (hc08_reg_a, one);
+ }
+ emitLabel (tlbl);
+ hc08_useReg (hc08_reg_a);
+ }
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* genNot - generate code for ! operation */
+/*-----------------------------------------------------------------*/
+static void
+genNot (iCode * ic)
+{
+ D(emitcode ("; genNot",""));
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ asmopToBool ( AOP (IC_LEFT (ic)), TRUE);
+ emitcode ("eor", one);
+ storeRegToFullAop (hc08_reg_a, AOP (IC_RESULT (ic)), FALSE);
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genCpl - generate code for complement */
+/*-----------------------------------------------------------------*/
+static void
+genCpl (iCode * ic)
+{
+ int offset = 0;
+ int size;
+ regs* reg = hc08_reg_a;
+
+// symbol *tlbl;
+
+ D(emitcode ("; genCpl",""));
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ size = AOP_SIZE (IC_RESULT (ic));
+ while (size--)
+ {
+ loadRegFromAop (reg, AOP (IC_LEFT (ic)), offset);
+ rmwWithReg ("com", reg);
+ hc08_useReg (reg);
+ storeRegToAop (reg, AOP (IC_RESULT (ic)), offset);
+ hc08_freeReg (reg);
+ }
+
+ /* release the aops */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+ int size, offset = 0;
+ bool needpula;
+
+ D(emitcode ("; genUminusFloat",""));
+
+ /* for this we just copy and then flip the bit */
+
+ size = AOP_SIZE (op) - 1;
+
+ while (size--)
+ {
+ if (!size)
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, AOP (op), offset);
+ emitcode ("eor", "#0x80");
+ hc08_useReg (hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), offset);
+ pullOrFreeReg (hc08_reg_a, needpula);
+ }
+ else
+ transferAopAop (AOP (op), offset, AOP (result), offset);
+ offset++;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminus - unary minus code generation */
+/*-----------------------------------------------------------------*/
+static void
+genUminus (iCode * ic)
+{
+ int offset, size;
+ sym_link *optype, *rtype;
+ char *sub;
+ bool needpula;
+
+ D(emitcode ("; genUminus",""));
+
+ /* assign asmops */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ optype = operandType (IC_LEFT (ic));
+ rtype = operandType (IC_RESULT (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;
+
+ if (size == 1)
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, AOP( IC_LEFT (ic)), 0);
+ emitcode ("nega", "");
+ hc08_freeReg (hc08_reg_a);
+ storeRegToFullAop (hc08_reg_a, AOP( IC_RESULT (ic)),
+ SPEC_USIGN (operandType (IC_LEFT (ic))));
+ pullOrFreeReg (hc08_reg_a, needpula);
+ }
+ else
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ sub="sub";
+ while (size--)
+ {
+ loadRegFromConst (hc08_reg_a, zero);
+ accopWithAop (sub, AOP( IC_LEFT (ic)), offset);
+ storeRegToAop (hc08_reg_a, AOP( IC_RESULT (ic)), offset++);
+ sub = "sbc";
+ }
+ storeRegSignToUpperAop (hc08_reg_a, AOP( IC_RESULT (ic)), offset,
+ SPEC_USIGN (operandType (IC_LEFT (ic))));
+ pullOrFreeReg (hc08_reg_a, needpula);
+ }
+
+
+
+release:
+ /* release the aops */
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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)) &&
+ (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
+ IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
+ return;
+
+ /* safe the registers in use at this time but skip the
+ ones for the result */
+ rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
+ hc08_rUmaskForOp (IC_RESULT(ic)));
+
+ ic->regsSaved = 1;
+ for (i = 0; i < hc08_nRegs; i++)
+ {
+ if (bitVectBitValue (rsave, i))
+ pushReg ( hc08_regWithIdx (i), FALSE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaveRegisters - pop the pushed registers */
+/*-----------------------------------------------------------------*/
+static void
+unsaveRegisters (iCode * ic)
+{
+ int i;
+ bitVect *rsave;
+
+ /* restore the registers in use at this time but skip the
+ ones for the result */
+ rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
+ hc08_rUmaskForOp (IC_RESULT(ic)));
+
+ for (i = hc08_nRegs; i >= 0; i--)
+ {
+ if (bitVectBitValue (rsave, i))
+ pullReg ( hc08_regWithIdx (i));
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* pushSide - */
+/*-----------------------------------------------------------------*/
+static void
+pushSide (operand * oper, int size)
+{
+ int offset = 0;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (oper), offset++);
+ pushReg ( hc08_reg_a, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignResultValue - */
+/*-----------------------------------------------------------------*/
+static void
+assignResultValue (operand * oper)
+{
+ int size = AOP_SIZE (oper);
+ int offset = 0;
+ while (size--)
+ {
+ transferAopAop(hc08_aop_pass[offset], 0, AOP (oper), offset);
+ if (hc08_aop_pass[offset]->type == AOP_REG)
+ hc08_freeReg (hc08_aop_pass[offset]->aopu.aop_reg[0]);
+ offset++;
+ }
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* genIpush - genrate code for pushing this gets a little complex */
+/*-----------------------------------------------------------------*/
+static void
+genIpush (iCode * ic)
+{
+ int size, offset = 0;
+// char *l;
+
+ 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));
+ offset = 0;
+ /* push it on the stack */
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (IC_LEFT (ic)), offset++);
+ pushReg ( hc08_reg_a, TRUE);
+ }
+
+ return;
+ }
+
+ /* this is a paramter push: in this case we call
+ the routine to find the call and save those
+ registers that need to be saved */
+ saveRegisters (ic);
+
+ /* 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));
+ offset = 0;
+
+// l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, TRUE);
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
+ {
+ if ((size==2) && hc08_reg_hx->isFree)
+ {
+ loadRegFromAop (hc08_reg_hx, AOP (IC_LEFT (ic)), 0);
+ pushReg (hc08_reg_hx, TRUE);
+ goto release;
+ }
+ }
+
+ while (size--)
+ {
+// printf("loading %d\n", offset);
+ loadRegFromAop (hc08_reg_a, AOP (IC_LEFT (ic)), offset++);
+// printf("pushing \n");
+ pushReg (hc08_reg_a, TRUE);
+ }
+
+release:
+ 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--)
+ {
+ pullReg (hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (IC_LEFT (ic)), offset--);
+ }
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genSend - gen code for SEND */
+/*-----------------------------------------------------------------*/
+static void genSend(set *sendSet)
+{
+ iCode *sic;
+
+ for (sic = setFirstItem (_G.sendSet); sic;
+ sic = setNextItem (_G.sendSet)) {
+ int size, offset = 0;
+ aopOp (IC_LEFT (sic), sic, FALSE);
+ size = AOP_SIZE (IC_LEFT (sic));
+
+ if (sic->argreg) {
+ offset = size-1;
+ while (size--) {
+ transferAopAop( AOP (IC_LEFT (sic)), offset,
+ hc08_aop_pass[offset+(sic->argreg-1)], 0);
+ offset--;
+ }
+ }
+ freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCall - generates a call statement */
+/*-----------------------------------------------------------------*/
+static void
+genCall (iCode * ic)
+{
+ sym_link *dtype;
+// bool restoreBank = FALSE;
+// bool swapBanks = FALSE;
+
+ D(emitcode("; genCall",""));
+
+ dtype = operandType (IC_LEFT (ic));
+ /* if send set is not empty the 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 caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters (ic);
+
+
+ /* make the call */
+ emitcode ("jsr", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
+ OP_SYMBOL (IC_LEFT (ic))->rname :
+ OP_SYMBOL (IC_LEFT (ic))->name));
+
+
+ /* if we need assign a result value */
+ if ((IS_ITEMP (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));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* adjust the stack for parameters if
+ required */
+ if (ic->parmBytes)
+ {
+ pullNull (ic->parmBytes);
+ }
+
+ /* if we had saved some registers then unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
+ unsaveRegisters (ic);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* -10l - generates a call by pointer statement */
+/*-----------------------------------------------------------------*/
+static void
+genPcall (iCode * ic)
+{
+ sym_link *dtype;
+ symbol *rlbl = newiTempLabel (NULL);
+ symbol *tlbl = newiTempLabel (NULL);
+// bool restoreBank=FALSE;
+// bool swapBanks = FALSE;
+
+ D(emitcode("; genPCall",""));
+
+ /* 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 */
+ dtype = operandType (IC_LEFT (ic))->next;
+
+ /* now push the calling address */
+ emitBranch ("bsr", tlbl);
+ emitBranch ("bra", rlbl);
+ emitLabel (tlbl);
+
+ /* Push the function's address */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ pushSide (IC_LEFT (ic), FPTRSIZE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+ /* if send set is not empty the assign */
+ if (_G.sendSet)
+ {
+ genSend(reverseSet(_G.sendSet));
+ _G.sendSet = NULL;
+ }
+
+
+ /* make the call */
+ emitcode ("rts", "");
+
+ emitLabel (rlbl);
+
+
+ /* if we need assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
+ OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
+ IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+
+ assignResultValue (IC_RESULT (ic));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* adjust the stack for parameters if
+ required */
+ if (ic->parmBytes)
+ {
+ pullNull (ic->parmBytes);
+ }
+
+ /* if we hade saved some registers then
+ unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
+ unsaveRegisters (ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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;
+}
+
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
+/*-----------------------------------------------------------------*/
+/* 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* genFunction - generated code for function entry */
+/*-----------------------------------------------------------------*/
+static void
+genFunction (iCode * ic)
+{
+ symbol *sym;
+ sym_link *ftype;
+ int calleesaves_saved_register = -1;
+
+ _G.nRegsSaved = 0;
+ _G.stackPushes = 0;
+ /* create the function header */
+ emitcode (";", "-----------------------------------------");
+ emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
+ emitcode (";", "-----------------------------------------");
+
+ emitcode ("", "%s:", sym->rname);
+ ftype = operandType (IC_LEFT (ic));
+
+ if (IFFUNC_ISNAKED(ftype))
+ {
+ emitcode(";", "naked function: no prologue.");
+ return;
+ }
+
+
+
+ /* if this is an interrupt service routine then
+ save h */
+ if (IFFUNC_ISISR (sym->type))
+ {
+
+ if (!inExcludeList ("h"))
+ emitcode ("pshh", "");
+ }
+ else
+ {
+ /* if callee-save to be used for this function
+ then save the registers being used in this function */
+ if (IFFUNC_CALLEESAVES(sym->type))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ /* 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;
+ pushReg (hc08_regWithIdx (i), FALSE);
+ _G.nRegsSaved++;
+ }
+ }
+ }
+ }
+ }
+
+ if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
+ {
+
+ }
+
+ /* adjust the stack for the function */
+ if (sym->stack)
+ {
+
+ int i = sym->stack;
+// if (i > 256)
+// werror (W_STACK_OVERFLOW, sym->name);
+
+ adjustStack (-i);
+ }
+ _G.stackOfs = sym->stack;
+ _G.stackPushes = 0;
+
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ if (IFFUNC_ARGS (ftype))
+ {
+ /* Function was passed parameters, so make sure A is preserved */
+ pushReg (hc08_reg_a, FALSE);
+ pushReg (hc08_reg_a, FALSE);
+ emitcode ("tpa", "");
+ emitcode ("sta", "2,s");
+ emitcode ("sei", "");
+ pullReg (hc08_reg_a);
+ }
+ else
+ {
+ /* No passed parameters, so A can be freely modified */
+ emitcode ("tpa", "");
+ pushReg (hc08_reg_a, TRUE);
+ emitcode ("sei", "");
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndFunction - generates epilogue for functions */
+/*-----------------------------------------------------------------*/
+static void
+genEndFunction (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+
+ if (IFFUNC_ISNAKED(sym->type))
+ {
+ emitcode(";", "naked function: no epilogue.");
+ return;
+ }
+
+ if (IFFUNC_ISCRITICAL (sym->type))
+ {
+ if (!IS_VOID(sym->type->next))
+ {
+ /* Function has return value, so make sure A is preserved */
+ pushReg (hc08_reg_a, FALSE);
+ emitcode ("lda", "2,s");
+ emitcode ("tap", "");
+ pullReg (hc08_reg_a);
+ pullNull (1);
+ }
+ else
+ {
+ /* Function returns void, so A can be freely modified */
+ pullReg (hc08_reg_a);
+ emitcode ("tap", "");
+ }
+ }
+
+ if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
+ {
+ }
+
+ if (sym->stack)
+ {
+ _G.stackPushes += sym->stack;
+ adjustStack (sym->stack);
+ }
+
+
+ if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
+ {
+ }
+
+ if (IFFUNC_ISISR (sym->type))
+ {
+
+ if (!inExcludeList ("h"))
+ emitcode ("pulh", "");
+
+
+ /* if debug then send end of function */
+ if (options.debug && currFunc)
+ {
+ _G.debugLine = 1;
+ emitcode ("", "C$%s$%d$%d$%d ==.",
+ FileBaseName (ic->filename), currFunc->lastLine,
+ ic->level, ic->block);
+ if (IS_STATIC (currFunc->etype))
+ emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
+ else
+ emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
+ _G.debugLine = 0;
+ }
+
+ emitcode ("rti", "");
+ }
+ else
+ {
+ if (IFFUNC_CALLEESAVES(sym->type))
+ {
+ 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) ||
+ (hc08_ptrRegReq && (i == HX_IDX || i == HX_IDX)))
+ emitcode ("pop", "%s", hc08_regWithIdx (i)->dname);
+ }
+ }
+
+ }
+
+ /* if debug then send end of function */
+ if (options.debug && currFunc)
+ {
+ _G.debugLine = 1;
+ emitcode ("", "C$%s$%d$%d$%d ==.",
+ FileBaseName (ic->filename), currFunc->lastLine,
+ ic->level, ic->block);
+ if (IS_STATIC (currFunc->etype))
+ emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
+ else
+ emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
+ _G.debugLine = 0;
+ }
+
+ emitcode ("rts", "");
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genRet - generate code for return statement */
+/*-----------------------------------------------------------------*/
+static void
+genRet (iCode * ic)
+{
+ int size, offset = 0;
+// int pushed = 0;
+
+ 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 1
+ offset = size - 1;
+ while (size--)
+ {
+ transferAopAop (AOP (IC_LEFT (ic)), offset, hc08_aop_pass[offset], 0);
+ offset--;
+ }
+#else
+ switch (size)
+ {
+ case 4:
+ /* 4 byte return: store value in the global return variable */
+ offset = size-1;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (IC_LEFT (ic)), offset);
+ STA (fReturn2[offset--], FALSE);
+ hc08_freeReg (hc08_reg_a);
+ }
+ break;
+ case 2:
+ /* 2 byte return: store value in x:a */
+ loadRegFromAop (hc08_reg_xa, AOP (IC_LEFT (ic)), 0);
+ hc08_freeReg (hc08_reg_xa);
+ break;
+ case 1:
+ /* 1 byte return: store value in a */
+ loadRegFromAop (hc08_reg_a, AOP (IC_LEFT (ic)), 0);
+ hc08_freeReg (hc08_reg_a);
+ break;
+ }
+#endif
+
+ 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 ("jmp", "%05d$", (returnLabel->key + 100));
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genLabel - generates a label */
+/*-----------------------------------------------------------------*/
+static void
+genLabel (iCode * ic)
+{
+ int i;
+ regs *reg;
+
+ /* For the high level labels we cannot depend on any */
+ /* register's contents. Amnesia time. */
+ for (i=A_IDX;i<=XA_IDX;i++)
+ {
+ reg = hc08_regWithIdx(i);
+ if (reg)
+ reg->aop = NULL;
+ }
+
+ /* special case never generate */
+ if (IC_LABEL (ic) == entryLabel)
+ return;
+
+ emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genGoto - generates a jmp */
+/*-----------------------------------------------------------------*/
+static void
+genGoto (iCode * ic)
+{
+ emitcode ("jmp", "%05d$", (IC_LABEL (ic)->key + 100));
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* findLabelBackwards: walks back through the iCode chain looking */
+/* for the given label. Returns number of iCode instructions */
+/* between that label and given ic. */
+/* Returns zero if label not found. */
+/*-----------------------------------------------------------------*/
+static int
+findLabelBackwards (iCode * ic, int key)
+{
+ int count = 0;
+
+ while (ic->prev)
+ {
+ ic = ic->prev;
+ count++;
+
+ /* If we have any pushes or pops, we cannot predict the distance.
+ I don't like this at all, this should be dealt with in the
+ back-end */
+ if (ic->op == IPUSH || ic->op == IPOP) {
+ return 0;
+ }
+
+ if (ic->op == LABEL && IC_LABEL (ic)->key == key)
+ {
+ return count;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* genPlusIncr :- does addition with increment if possible */
+/*-----------------------------------------------------------------*/
+static bool
+genPlusIncr (iCode * ic)
+{
+ int icount;
+ operand *left;
+ operand *result;
+ bool needpulx;
+ bool needpulh;
+ bool needpula;
+ unsigned int size = getDataSize (IC_RESULT (ic));
+ int offset;
+ symbol *tlbl = NULL;
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* 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) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+
+ emitcode ("", "; IS_AOP_HX = %d", IS_AOP_HX (AOP (left)));
+
+ if ((IS_AOP_HX (AOP (left)) ||
+ ( (AOP_TYPE (left) == AOP_DIR) && (AOP_TYPE (result) == AOP_DIR) )
+ )
+ && (icount>=-128) && (icount<=127) && (size==2))
+ {
+ needpulx = pushRegIfUsed (hc08_reg_x);
+ needpulh = pushRegIfUsed (hc08_reg_h);
+ loadRegFromAop (hc08_reg_hx, AOP(left), 0);
+ emitcode ("aix","#%d", icount);
+ hc08_dirtyReg (hc08_reg_hx, FALSE);
+ storeRegToAop (hc08_reg_hx, AOP(result), 0);
+ pullOrFreeReg (hc08_reg_h, needpulh);
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ return TRUE;
+ }
+
+ emitcode ("", "; icount = %d, sameRegs=%d", icount,
+ sameRegs (AOP (left), AOP (result)));
+
+ if ((icount > 255) || (icount<0))
+ return FALSE;
+
+ if (!sameRegs (AOP (left), AOP (result)))
+ return FALSE;
+
+ D(emitcode ("; genPlusIncr",""));
+
+ if (size>1)
+ tlbl = newiTempLabel (NULL);
+
+ if (icount==1)
+ {
+ needpula = FALSE;
+ rmwWithAop ("inc", AOP (result), 0);
+ if (1<size)
+ emitBranch ("bne", tlbl);
+ }
+ else
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, AOP (result), 0);
+ accopWithAop ("add", AOP (IC_RIGHT (ic)), 0);
+ hc08_useReg (hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), 0);
+ hc08_freeReg (hc08_reg_a);
+ if (1<size)
+ emitBranch ("bcc", tlbl);
+ }
+ for (offset=1; offset<size; offset++)
+ {
+ rmwWithAop ("inc", AOP (result), offset);
+ if ((offset+1)<size)
+ emitBranch ("bne", tlbl);
+ }
+
+ if (size>1)
+ emitLabel (tlbl);
+
+ pullOrFreeReg (hc08_reg_a, needpula);
+
+ return TRUE;
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* genPlus - generates code for addition */
+/*-----------------------------------------------------------------*/
+static void
+genPlus (iCode * ic)
+{
+ int size, offset = 0;
+ char *add;
+ asmop *leftOp, *rightOp;
+
+ /* special cases :- */
+
+ D(emitcode ("; genPlus",""));
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RIGHT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* we want registers on the left and literals on the right */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
+ (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG))
+ {
+ operand *t = IC_RIGHT (ic);
+ IC_RIGHT (ic) = IC_LEFT (ic);
+ IC_LEFT (ic) = t;
+ }
+
+
+ /* if I can do an increment instead
+ of add then GOOD for ME */
+ if (genPlusIncr (ic) == TRUE)
+ goto release;
+
+ emitcode("","; left size = %d", getDataSize (IC_LEFT(ic)));
+ emitcode("","; right size = %d", getDataSize (IC_RIGHT(ic)));
+ emitcode("","; result size = %d", getDataSize (IC_RESULT(ic)));
+
+ size = getDataSize (IC_RESULT (ic));
+
+ leftOp = AOP(IC_LEFT(ic));
+ rightOp = AOP(IC_RIGHT(ic));
+ add = "add";
+
+ offset = 0;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, leftOp, offset);
+ accopWithAop(add, rightOp, offset);
+ storeRegToAop (hc08_reg_a, AOP (IC_RESULT (ic)), offset++);
+ hc08_freeReg (hc08_reg_a);
+ add = "adc"; /* further adds must propagate carry */
+ }
+
+
+// adjustArithmeticResult (ic);
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinusDec :- does subtraction with deccrement if possible */
+/*-----------------------------------------------------------------*/
+static bool
+genMinusDec (iCode * ic)
+{
+ unsigned int icount;
+ operand *left;
+ operand *result;
+ bool needpulx;
+ bool needpulh;
+ unsigned int size = getDataSize (IC_RESULT (ic));
+// int offset;
+// symbol *tlbl;
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* 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) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
+
+ if ((AOP_TYPE (left) == AOP_DIR) && (AOP_TYPE (result) == AOP_DIR)
+ && (icount>=-127) && (icount<=128) && (size==2))
+ {
+ needpulx = pushRegIfUsed (hc08_reg_x);
+ needpulh = pushRegIfUsed (hc08_reg_h);
+ loadRegFromAop (hc08_reg_hx, AOP(left), 0);
+ emitcode ("aix","#%d", -icount);
+ hc08_dirtyReg (hc08_reg_hx, FALSE);
+ storeRegToAop (hc08_reg_hx, AOP(result), 0);
+ pullOrFreeReg (hc08_reg_h, needpulh);
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ return TRUE;
+ }
+
+ if ((icount > 1) || (icount<0))
+ return FALSE;
+
+ if (!sameRegs (AOP (left), AOP (result)))
+ return FALSE;
+
+ if (size!=1)
+ return FALSE;
+
+ D(emitcode ("; genMinusDec",""));
+
+ rmwWithAop ("dec", AOP (result), 0);
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* addSign - complete with sign */
+/*-----------------------------------------------------------------*/
+static void
+addSign (operand * result, int offset, int sign)
+{
+ int size = (getDataSize (result) - offset);
+ if (size > 0)
+ {
+ if (sign)
+ {
+ emitcode ("rola", "");
+ emitcode ("clra", "");
+ emitcode ("sbc", zero);
+ while (size--)
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ }
+ else
+ while (size--)
+ storeConstToAop (zero, AOP (result), offset++);
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMinus - generates code for subtraction */
+/*-----------------------------------------------------------------*/
+static void
+genMinus (iCode * ic)
+{
+ char *sub;
+ 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 I can do an decrement instead
+ of subtract then GOOD for ME */
+ if (genMinusDec (ic) == TRUE)
+ goto release;
+
+ size = getDataSize (IC_RESULT (ic));
+
+ asmop *leftOp, *rightOp;
+
+ leftOp = AOP(IC_LEFT(ic));
+ rightOp = AOP(IC_RIGHT(ic));
+
+ sub = "sub";
+ offset = 0;
+ while (size--)
+ {
+ loadRegFromAop ( hc08_reg_a, leftOp, offset);
+ accopWithAop(sub, rightOp, offset);
+ storeRegToAop (hc08_reg_a, AOP (IC_RESULT (ic)), offset++);
+ sub = "sbc";
+ }
+
+
+// adjustArithmeticResult (ic);
+
+release:
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* genMultOneByte : 8*8=8/16 bit multiplication */
+/*-----------------------------------------------------------------*/
+static void
+genMultOneByte (operand * left,
+ operand * right,
+ operand * result)
+{
+ sym_link *opetype = operandType (result);
+ symbol *tlbl1, *tlbl2, *tlbl3, *tlbl4;
+ int size=AOP_SIZE(result);
+ bool negLiteral = FALSE;
+
+ 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 (1);
+ }
+
+ /* (if two literals: the value is computed before) */
+ /* if one literal, literal on the right */
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ //emitcode (";", "swapped left and right");
+ }
+
+ if (SPEC_USIGN(opetype))
+ {
+ // just an unsigned 8*8=8/16 multiply
+ //emitcode (";","unsigned");
+
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitcode ("mul", "");
+ hc08_dirtyReg (hc08_reg_xa, FALSE);
+ storeRegToFullAop (hc08_reg_xa, AOP (result), TRUE);
+ hc08_freeReg (hc08_reg_xa);
+
+ return;
+ }
+
+ // we have to do a signed multiply
+
+
+ //emitcode (";", "signed");
+ adjustStack (-1);
+ emitcode ("clr", "1,s");
+
+ tlbl1 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ emitcode ("tsta","");
+ emitBranch ("bpl", tlbl1);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_a);
+ emitLabel (tlbl1);
+
+ if (AOP_TYPE(right)==AOP_LIT)
+ {
+ signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
+ /* AND literal negative */
+ if (val < 0) {
+ emitcode ("ldx", "#0x%02x", -val);
+ negLiteral = TRUE;
+ } else {
+ emitcode ("ldx", "#0x%02x", val);
+ }
+ hc08_useReg (hc08_reg_x);
+ }
+ else
+ {
+ tlbl2 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitcode ("tstx", "");
+ emitBranch ("bpl", tlbl2);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_x);
+ emitLabel (tlbl2);
+ }
+
+ emitcode ("mul", "");
+ hc08_dirtyReg (hc08_reg_xa, FALSE);
+
+ tlbl3 = newiTempLabel (NULL);
+ emitcode ("dec", "1,s");
+ if (negLiteral)
+ emitBranch ("bne", tlbl3);
+ else
+ emitBranch ("beq", tlbl3);
+
+ rmwWithReg ("neg", hc08_reg_a);
+ if (size>1)
+ {
+ tlbl4 = newiTempLabel (NULL);
+ emitBranch ("bcc", tlbl4);
+ rmwWithReg ("inc", hc08_reg_x);
+ emitLabel (tlbl4);
+ rmwWithReg ("neg", hc08_reg_x);
+ }
+
+ emitLabel (tlbl3);
+ adjustStack (1);
+ storeRegToFullAop (hc08_reg_xa, AOP (result), TRUE);
+ hc08_freeReg (hc08_reg_xa);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* if both are of size == 1 */
+// if (getSize(operandType(left)) == 1 &&
+// getSize(operandType(right)) == 1)
+ if (AOP_SIZE (left) == 1 &&
+ AOP_SIZE (right) == 1)
+ {
+ 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));
+ fprintf (stderr, "left: %d right: %d\n", AOP_SIZE (left),
+ AOP_SIZE (right));
+ assert (0);
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivOneByte : 8 bit division */
+/*-----------------------------------------------------------------*/
+static void
+genDivOneByte (operand * left,
+ operand * right,
+ operand * result)
+{
+ sym_link *opetype = operandType (result);
+// char *l;
+ symbol *tlbl1, *tlbl2, *tlbl3, *tlbl4;
+ int size;
+ bool negLiteral = FALSE;
+
+ D(emitcode ("; genDivOneByte",""));
+
+ size = AOP_SIZE (result);
+ /* signed or unsigned */
+ if (SPEC_USIGN (opetype))
+ {
+ /* unsigned is easy */
+ loadRegFromAop (hc08_reg_h, AOP (left), 1);
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitcode ("div", "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ hc08_dirtyReg (hc08_reg_h, FALSE);
+ storeRegToFullAop (hc08_reg_a, AOP (result), FALSE);
+ hc08_freeReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_x);
+ hc08_freeReg (hc08_reg_h);
+ return;
+ }
+
+ /* signed is a little bit more difficult */
+
+ adjustStack (-1);
+ emitcode ("clr", "1,s");
+
+ tlbl1 = newiTempLabel (NULL);
+ tlbl2 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ loadRegFromAop (hc08_reg_x, AOP (left), 1);
+ emitBranch ("bpl", tlbl1);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_a);
+ emitBranch ("bcc", tlbl2);
+ rmwWithReg ("inc", hc08_reg_x);
+ emitLabel (tlbl2);
+ rmwWithReg ("neg", hc08_reg_x);
+ transferRegReg (hc08_reg_x, hc08_reg_h, TRUE);
+ emitLabel (tlbl1);
+
+ if (AOP_TYPE(right)==AOP_LIT)
+ {
+ signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
+ /* AND literal negative */
+ if (val < 0) {
+ emitcode ("ldx", "#0x%02x", -val);
+ negLiteral = TRUE;
+ } else {
+ emitcode ("ldx", "#0x%02x", val);
+ }
+ hc08_useReg (hc08_reg_x);
+ }
+ else
+ {
+ tlbl3 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitBranch ("bpl", tlbl3);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_x);
+ emitLabel (tlbl3);
+ }
+
+ emitcode ("div", "");
+ hc08_dirtyReg (hc08_reg_x, FALSE);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ hc08_dirtyReg (hc08_reg_h, FALSE);
+
+ tlbl4 = newiTempLabel (NULL);
+ emitcode ("dec", "1,s");
+ if (negLiteral)
+ emitBranch ("bne", tlbl4);
+ else
+ emitBranch ("beq", tlbl4);
+ rmwWithReg ("neg", hc08_reg_a);
+
+ emitLabel (tlbl4);
+ adjustStack (1);
+ storeRegToFullAop (hc08_reg_a, AOP (result), TRUE);
+ hc08_freeReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_x);
+ hc08_freeReg (hc08_reg_h);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) <= 2 &&
+ AOP_SIZE (right) == 1)
+ {
+ genDivOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genModOneByte : 8 bit modulus */
+/*-----------------------------------------------------------------*/
+static void
+genModOneByte (operand * left,
+ operand * right,
+ operand * result)
+{
+ sym_link *opetype = operandType (result);
+// symbol *lbl;
+ symbol *tlbl1, *tlbl2, *tlbl3, *tlbl4;
+ int size;
+ bool negLiteral = FALSE;
+
+ D(emitcode ("; genModOneByte",""));
+
+ size = AOP_SIZE (result);
+ /* signed or unsigned */
+ if (SPEC_USIGN (opetype))
+ {
+ /* unsigned is easy */
+ loadRegFromAop (hc08_reg_h, AOP (left), 1);
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitcode ("div", "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ hc08_dirtyReg (hc08_reg_h, FALSE);
+ storeRegToFullAop (hc08_reg_h, AOP (result), FALSE);
+ hc08_freeReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_x);
+ hc08_freeReg (hc08_reg_h);
+ return;
+ }
+
+ /* signed is a little bit more difficult */
+
+ adjustStack (-1);
+ emitcode ("clr", "1,s");
+
+ tlbl1 = newiTempLabel (NULL);
+ tlbl2 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ loadRegFromAop (hc08_reg_x, AOP (left), 1);
+ emitBranch ("bpl", tlbl1);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_a);
+ emitBranch ("bcc", tlbl2);
+ rmwWithReg ("inc", hc08_reg_x);
+ emitLabel (tlbl2);
+ rmwWithReg ("neg", hc08_reg_x);
+ transferRegReg (hc08_reg_x, hc08_reg_h, TRUE);
+ emitLabel (tlbl1);
+
+ if (AOP_TYPE(right)==AOP_LIT)
+ {
+ signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
+ /* AND literal negative */
+ if (val < 0) {
+ emitcode ("ldx", "#0x%02x", -val);
+ negLiteral = TRUE;
+ } else {
+ emitcode ("ldx", "#0x%02x", val);
+ }
+ hc08_useReg (hc08_reg_x);
+ }
+ else
+ {
+ tlbl3 = newiTempLabel (NULL);
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitBranch ("bpl", tlbl3);
+ emitcode ("inc", "1,s");
+ rmwWithReg ("neg", hc08_reg_x);
+ emitLabel (tlbl3);
+ }
+
+ emitcode ("div", "");
+ hc08_dirtyReg (hc08_reg_x, FALSE);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ hc08_dirtyReg (hc08_reg_h, FALSE);
+
+ tlbl4 = newiTempLabel (NULL);
+ transferRegReg (hc08_reg_h, hc08_reg_a, TRUE);
+ emitcode ("dec", "1,s");
+ if (negLiteral)
+ emitBranch ("bne", tlbl4);
+ else
+ emitBranch ("beq", tlbl4);
+ rmwWithReg ("neg", hc08_reg_a);
+
+ emitLabel (tlbl4);
+ adjustStack (1);
+ storeRegToFullAop (hc08_reg_a, AOP (result), TRUE);
+ hc08_freeReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_x);
+ hc08_freeReg (hc08_reg_h);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) <= 2 &&
+ AOP_SIZE (right) == 1)
+ {
+ genModOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfxJump :- will create a jump depending on the ifx */
+/*-----------------------------------------------------------------*/
+static void
+genIfxJump (iCode * ic, char *jval)
+{
+ symbol *jlbl;
+ symbol *tlbl = newiTempLabel (NULL);
+ char *inst;
+
+ D(emitcode ("; genIfxJump",""));
+
+ /* if true label then we jump if condition
+ supplied is true */
+ if (IC_TRUE (ic))
+ {
+ jlbl = IC_TRUE (ic);
+ if (!strcmp (jval, "a"))
+ inst = "beq";
+ else if (!strcmp (jval, "c"))
+ inst = "bcc";
+ else
+ inst = "bge";
+ }
+ else
+ {
+ /* false label is present */
+ jlbl = IC_FALSE (ic);
+ if (!strcmp (jval, "a"))
+ inst = "bne";
+ else if (!strcmp (jval, "c"))
+ inst = "bcs";
+ else
+ inst = "blt";
+ }
+ emitBranch (inst, tlbl);
+ emitBranch ("jmp", jlbl);
+ 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 lit = 0L;
+ char *sub;
+ bool needpula = FALSE;
+
+ D(emitcode ("; genCmp",""));
+
+ /* 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 (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ /* optimize if(x < 0) or if(x >= 0) */
+ if (lit == 0L)
+ {
+ if (!sign)
+ {
+ CLRC;
+ }
+ else
+ {
+ needpula = pushRegIfUsed (hc08_reg_a);
+ loadRegFromAop (hc08_reg_a, AOP (left), AOP_SIZE (left) -1);
+ emitcode ("rola", "");
+ hc08_useReg (hc08_reg_a);
+ }
+ sign = 0;
+ goto release;
+ }
+ }
+
+ if ((size==2)
+ && ((AOP_TYPE (right) == AOP_LIT) ||
+ ((AOP_TYPE (right) == AOP_DIR) && (AOP_SIZE (right) == 2)) )
+ && hc08_reg_hx->isFree)
+ {
+ loadRegFromAop (hc08_reg_hx, AOP (left), 0);
+ emitcode ("cphx","%s", aopAdrStr (AOP (right), 1, TRUE));
+ hc08_freeReg (hc08_reg_hx);
+ goto release;
+ }
+
+ offset = 0;
+ if (size==1)
+ sub="cmp";
+ else
+ sub="sub";
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ accopWithAop (sub, AOP (right), offset);
+ hc08_freeReg (hc08_reg_a);
+ offset++;
+ sub="sbc";
+ }
+
+release:
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, 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)
+ {
+ pullOrFreeReg(hc08_reg_a,needpula);
+ genIfxJump (ifx, sign ? "s" : "c");
+ }
+ else
+ if (!sign)
+ outBitC (result);
+ else
+ outBitNV (result);
+ pullOrFreeReg(hc08_reg_a,needpula);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpGt :- greater than comparison */
+/*-----------------------------------------------------------------*/
+static void
+genCmpGt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign;
+
+ D(emitcode ("; genCmpGt",""));
+
+ result = IC_RESULT (ic);
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ 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;
+
+ D(emitcode ("; genCmpLt",""));
+
+ result = IC_RESULT (ic);
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ genCmp (left, right, result, ifx, sign,ic);
+
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* - compare and branch if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencbneshort (operand * left, operand * right, symbol * lbl)
+{
+ int size = max (AOP_SIZE (left), AOP_SIZE (right));
+ int offset = 0;
+ unsigned long lit = 0L;
+
+ /* if the left side is a literal or
+ if the right is in a pointer register and left
+ is not */
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ accopWithAop ("cmp", AOP (right), offset);
+ hc08_useReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_a);
+ emitBranch ("bne", lbl);
+ offset++;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjne - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void
+gencjne (operand * left, operand * right, symbol * lbl)
+{
+ symbol *tlbl = newiTempLabel (NULL);
+
+ gencbneshort (left, right, lbl);
+
+ loadRegFromConst (hc08_reg_a, one);
+ emitBranch ("bra", tlbl);
+ emitLabel (lbl);
+ loadRegFromConst (hc08_reg_a, zero);
+ emitLabel (tlbl);
+
+ hc08_useReg(hc08_reg_a);
+ hc08_freeReg(hc08_reg_a);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpEq - generates code for equal to */
+/*-----------------------------------------------------------------*/
+static void
+genCmpEq (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+
+ 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 (IC_LEFT (ic)) == AOP_LIT)
+ {
+ operand *t = IC_RIGHT (ic);
+ IC_RIGHT (ic) = IC_LEFT (ic);
+ IC_LEFT (ic) = t;
+ }
+
+ if (ifx && !AOP_SIZE (result))
+ {
+ symbol *tlbl;
+ tlbl = newiTempLabel (NULL);
+ gencbneshort (left, right, tlbl);
+ if (IC_TRUE (ifx))
+ {
+ emitBranch ("jmp", IC_TRUE (ifx));
+ emitLabel (tlbl);
+ }
+ else
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ emitBranch ("bra", lbl);
+ emitLabel (tlbl);
+ emitBranch ("jmp", IC_FALSE (ifx));
+ emitLabel (lbl);
+ }
+
+ /* mark the icode as generated */
+ ifx->generated = 1;
+ goto release;
+ }
+
+ gencjne (left, right, newiTempLabel (NULL));
+ if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
+ {
+ storeRegToAop (hc08_reg_a, AOP (result), 0);
+ goto release;
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, "a");
+ goto release;
+ }
+ /* if the result is used in an arithmetic operation
+ then put the result in place */
+ if (AOP_TYPE (result) != AOP_CRY)
+ outAcc (result);
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* ifxForOp - returns the icode containing the ifx for operand */
+/*-----------------------------------------------------------------*/
+static iCode *
+ifxForOp (operand * op, iCode * ic)
+{
+ /* if true symbol then needs to be assigned */
+ if (IS_TRUE_SYMOP (op))
+ return NULL;
+
+ /* if this has register type condition and
+ the next instruction is ifx with the same operand
+ and live to of the operand is upto the ifx only then */
+ if (ic->next &&
+ ic->next->op == IFX &&
+ IC_COND (ic->next)->key == op->key &&
+ OP_SYMBOL (op)->liveTo <= ic->next->seq)
+ return ic->next;
+
+ return NULL;
+}
+
+static bool
+genPointerGetSetOfs (iCode *ic)
+{
+ iCode *lic = ic->next;
+ bool pset, pget;
+ int offset, size;
+ symbol *sym;
+ asmop *derefaop;
+
+ /* Make sure we have a next iCode */
+ emitcode("","; checking lic");
+ if (!lic)
+ return FALSE;
+
+ /* Make sure the result of the addition is an iCode */
+ emitcode("","; checking IS_ITEMP");
+ if (!IS_ITEMP (IC_RESULT (ic)))
+ return FALSE;
+
+ /* Make sure the next iCode is a pointer set or get */
+ pset = POINTER_SET(lic);
+ pget = POINTER_GET(lic);
+ emitcode("","; pset=%d, pget=%d",pset,pget);
+ if (!pset && !pget)
+ return FALSE;
+
+ emitcode("", "; checking pset operandsEqu");
+ if (pset & !operandsEqu (IC_RESULT (ic), IC_RESULT (lic)))
+ return FALSE;
+
+ emitcode("", "; checking pget operandsEqu");
+ if (pget & !operandsEqu (IC_RESULT (ic), IC_LEFT (lic)))
+ return FALSE;
+
+ emitcode("", "; checking IS_SYMOP");
+ if (!IS_SYMOP (IC_LEFT (ic)))
+ return FALSE;
+
+ emitcode("", "; checking !IS_TRUE_SYMOP");
+ if (IS_TRUE_SYMOP (IC_LEFT (ic)))
+ return FALSE;
+
+ sym = OP_SYMBOL (IC_LEFT (ic));
+
+ emitcode("", "; checking remat");
+ if (!sym->remat)
+ return FALSE;
+
+ if (pget)
+ {
+ D(emitcode ("; genPointerGetOfs",""));
+ aopOp (IC_LEFT(ic), ic, FALSE);
+ derefaop = aopDerefAop (AOP (IC_LEFT (ic)));
+ freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
+
+ aopOp (IC_RIGHT(ic), ic, FALSE);
+ aopOp (IC_RESULT(lic), lic, FALSE);
+
+
+ loadRegFromAop (hc08_reg_hx, AOP (IC_RIGHT (ic)), 0);
+ size = AOP_SIZE (IC_RESULT(lic));
+ derefaop->size = size;
+ offset=0;
+
+ while (size--)
+ {
+ emitcode ("lda", "%s,x",
+ aopAdrStr (derefaop, offset, TRUE));
+ hc08_useReg (hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (IC_RESULT (lic)), offset++);
+ hc08_freeReg (hc08_reg_a);
+ }
+
+ lic->generated = 1;
+ hc08_freeReg (hc08_reg_hx);
+
+ freeAsmop (NULL, derefaop, ic, TRUE);
+ freeAsmop (IC_RIGHT(ic), NULL, ic, TRUE);
+ freeAsmop (IC_RESULT(lic), NULL, lic, TRUE);
+
+ return TRUE;
+ }
+
+ if (pset)
+ {
+ D(emitcode ("; genPointerSetOfs",""));
+ aopOp (IC_LEFT(ic), ic, FALSE);
+ derefaop = aopDerefAop (AOP (IC_LEFT (ic)));
+ freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
+
+ aopOp (IC_RIGHT(ic), ic, FALSE);
+ aopOp (IC_RIGHT(lic), lic, FALSE);
+
+
+ loadRegFromAop (hc08_reg_hx, AOP (IC_RIGHT (ic)), 0);
+ size = AOP_SIZE (IC_RIGHT(lic));
+ derefaop->size = size;
+ offset=0;
+
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (IC_RIGHT (lic)), offset);
+ emitcode ("sta", "%s,x",
+ aopAdrStr (derefaop, offset, TRUE));
+ hc08_freeReg (hc08_reg_a);
+ offset++;
+ }
+
+ lic->generated = 1;
+ hc08_freeReg (hc08_reg_hx);
+
+ freeAsmop (NULL, derefaop, ic, TRUE);
+ freeAsmop (IC_RIGHT(ic), NULL, ic, TRUE);
+ freeAsmop (IC_RIGHT(lic), NULL, lic, TRUE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* 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) || (unsigned) 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, *tlbl0;
+
+ 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);
+
+ tlbl = newiTempLabel (NULL);
+ tlbl0 = newiTempLabel (NULL);
+
+ asmopToBool (AOP (left), FALSE);
+ emitBranch ("beq", tlbl0);
+ asmopToBool (AOP (right), FALSE);
+ emitBranch ("beq", tlbl0);
+ loadRegFromConst (hc08_reg_a,one);
+ emitBranch ("bra", tlbl);
+ emitLabel (tlbl0);
+ loadRegFromConst (hc08_reg_a,zero);
+ emitLabel (tlbl);
+
+ hc08_useReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_a);
+
+ storeRegToFullAop (hc08_reg_a, AOP (result), FALSE);
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genOrOp - for || operation */
+/*-----------------------------------------------------------------*/
+static void
+genOrOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl, *tlbl0;
+
+ 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);
+
+ tlbl = newiTempLabel (NULL);
+ tlbl0 = newiTempLabel (NULL);
+
+ asmopToBool (AOP (left), FALSE);
+ emitBranch ("bne", tlbl0);
+ asmopToBool (AOP (right), FALSE);
+ emitBranch ("bne", tlbl0);
+ loadRegFromConst (hc08_reg_a,zero);
+ emitBranch ("bra", tlbl);
+ emitLabel (tlbl0);
+ loadRegFromConst (hc08_reg_a,one);
+ emitLabel (tlbl);
+
+ hc08_useReg (hc08_reg_a);
+ hc08_freeReg (hc08_reg_a);
+
+ storeRegToFullAop (hc08_reg_a, AOP (result), FALSE);
+
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* isLiteralBit - test if lit == 2^n */
+/*-----------------------------------------------------------------*/
+static int
+isLiteralBit (unsigned long lit)
+{
+ unsigned long pw[32] =
+ {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
+ 0x100L, 0x200L, 0x400L, 0x800L,
+ 0x1000L, 0x2000L, 0x4000L, 0x8000L,
+ 0x10000L, 0x20000L, 0x40000L, 0x80000L,
+ 0x100000L, 0x200000L, 0x400000L, 0x800000L,
+ 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
+ 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
+ int idx;
+
+ for (idx = 0; idx < 32; idx++)
+ if (lit == pw[idx])
+ return idx + 1;
+ return 0;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* continueIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+continueIfTrue (iCode * ic)
+{
+ if (IC_TRUE (ic))
+ emitBranch ("jmp", IC_TRUE (ic));
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+jumpIfTrue (iCode * ic)
+{
+ if (!IC_TRUE (ic))
+ emitBranch ("jmp", IC_FALSE (ic));
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse - */
+/*-----------------------------------------------------------------*/
+static void
+jmpTrueOrFalse (iCode * ic, symbol * tlbl)
+{
+ // ugly but optimized by peephole
+ if (IC_TRUE (ic))
+ {
+ symbol *nlbl = newiTempLabel (NULL);
+ emitBranch ("bra", nlbl);
+ emitLabel (tlbl);
+ emitBranch ("jmp", IC_TRUE (ic));
+ emitLabel (nlbl);
+ }
+ else
+ {
+ emitBranch ("jmp", IC_FALSE (ic));
+ emitLabel (tlbl);
+ }
+ ic->generated = 1;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* genAnd - code for and */
+/*-----------------------------------------------------------------*/
+static void
+genAnd (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ unsigned long litinv;
+
+
+// int bytelit = 0;
+// char buffer[10];
+
+ 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)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if left is accumulator & right is not then exchange them */
+ if (AOP_TYPE (right) == AOP_REG && AOP_TYPE (left) != AOP_REG)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ litinv = (~lit) & (((unsigned int)0xffffffff) >> (8*(4-size))) ;
+
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+ (AOP_TYPE (left) == AOP_DIR) && isLiteralBit(litinv))
+ {
+ int bitpos = isLiteralBit(litinv)-1;
+ emitcode ("bclr","#%d,%s",bitpos & 7,
+ aopAdrStr (AOP (left), bitpos >> 3, FALSE));
+ goto release;
+ }
+ }
+
+ offset = 0;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ if ((AOP_TYPE (right) != AOP_LIT)
+ || (((lit >> (offset*8)) & 0xff) != 0xff))
+ accopWithAop ("and", AOP (right), offset);
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ hc08_freeReg( hc08_reg_a);
+ }
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genOr - code for or */
+/*-----------------------------------------------------------------*/
+static void
+genOr (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+
+ 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)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if left is accumulator & right is not then exchange them */
+ if (AOP_TYPE (right) == AOP_REG && AOP_TYPE (left) != AOP_REG)
+ {
+ 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 = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+ (AOP_TYPE (right) == AOP_LIT) && isLiteralBit(lit) &&
+ (AOP_TYPE (left) == AOP_DIR))
+ {
+ int bitpos = isLiteralBit(lit)-1;
+ emitcode ("bset","#%d,%s",bitpos & 7,
+ aopAdrStr (AOP (left), bitpos >> 3, FALSE));
+ goto release;
+ }
+
+
+
+ offset = 0;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ accopWithAop ("ora", AOP (right), offset);
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ hc08_freeReg( hc08_reg_a);
+ }
+
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, 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;
+
+ 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)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if left is accumulator & right is not then exchange them */
+ if (AOP_TYPE (right) == AOP_REG && AOP_TYPE (left) != AOP_REG)
+ {
+ 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 = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ accopWithAop ("eor", AOP (right), offset);
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ hc08_freeReg( hc08_reg_a);
+ }
+
+
+//release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+static void
+emitinline (iCode * ic, char *inlin)
+{
+ char buffer[512];
+ char *symname;
+ char c;
+ char *bp=buffer;
+ symbol *sym, *tempsym;
+ asmop *aop;
+ char *l;
+
+ while (*inlin)
+ {
+ if (*inlin == '_')
+ {
+ symname = ++inlin;
+ while (isalnum(*inlin) || (*inlin == '_'))
+ inlin++;
+ c = *inlin;
+ *inlin = '\0';
+ //printf("Found possible symbol '%s'\n",symname);
+ tempsym = newSymbol (symname, ic->level);
+ tempsym->block = ic->block;
+ sym = (symbol *) findSymWithLevel(SymbolTab,tempsym);
+ *inlin = c;
+ if (!sym)
+ {
+ *bp++ = '_';
+ inlin = symname;
+ }
+ else
+ {
+ aop = aopForSym (ic, sym, FALSE);
+ l = aopAdrStr (aop, aop->size - 1, TRUE);
+ if (*l=='#')
+ l++;
+ sym->isref = 1;
+ if (!sym->allocreq && !sym->ismyparm)
+ {
+ werror (E_ID_UNDEF, sym->name);
+ werror (W_CONTINUE,
+ " Add 'volatile' to the variable declaration so that it\n"
+ " can be referenced within inline assembly");
+ }
+ //printf("Replacing with '%s'\n",l);
+ while (*l)
+ {
+ *bp++ = *l++;
+ if ((2+bp-buffer)>sizeof(buffer))
+ goto endofline;
+ }
+ }
+ }
+ else
+ {
+ *bp++ = *inlin++;
+ }
+ if ((2+bp-buffer)>sizeof(buffer))
+ goto endofline;
+ }
+
+endofline:
+ *bp = '\0';
+
+ if ((2+bp-buffer)>sizeof(buffer))
+ fprintf(stderr, "Inline assembly buffer overflow\n");
+
+ //printf("%s\n",buffer);
+ emitcode (buffer,"");
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+static void
+genInline (iCode * ic)
+{
+ char *buffer, *bp, *bp1;
+
+ D(emitcode ("; genInline",""));
+
+ _G.inLine += (!options.asmpeep);
+
+ buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
+ strcpy (buffer, IC_INLINE (ic));
+
+ /* emit each line as a code */
+ while (*bp)
+ {
+ if (*bp == '\n')
+ {
+ *bp++ = '\0';
+ /* emitcode (bp1, ""); */
+ emitinline (ic, bp1);
+ bp1 = bp;
+ }
+ else
+ {
+ if (*bp == ':')
+ {
+ bp++;
+ *bp = '\0';
+ bp++;
+ emitcode (bp1, "");
+ bp1 = bp;
+ }
+ else
+ bp++;
+ }
+ }
+ if (bp1 != bp)
+ {
+ /* emitcode (bp1, ""); */
+ emitinline (ic, bp1);
+ }
+ /* emitcode("",buffer); */
+ _G.inLine -= (!options.asmpeep);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRRC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset = 0;
+ bool needpula = FALSE;
+ bool resultInA = FALSE;
+ char *shift;
+
+ D(emitcode ("; genRRC",""));
+
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ if ((AOP_TYPE (result) == AOP_REG)
+ && (AOP (result)->aopu.aop_reg[0]->rIdx == A_IDX))
+ resultInA = TRUE;
+
+ size = AOP_SIZE (result);
+ offset = size-1;
+
+ shift="lsr";
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ while (size--)
+ {
+ rmwWithAop (shift, AOP (result), offset--);
+ shift="ror";
+ }
+ }
+ else
+ {
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ rmwWithReg (shift, hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), offset--);
+ hc08_freeReg (hc08_reg_a);
+ shift="ror";
+ }
+ }
+
+ if ((!hc08_reg_a->isFree) || resultInA)
+ {
+ pushReg (hc08_reg_a, TRUE);
+ needpula = TRUE;
+ }
+
+ /* now we need to put the carry into the
+ highest order byte of the result */
+ offset = AOP_SIZE (result) - 1;
+ emitcode ("clra","");
+ emitcode ("rora","");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ if (resultInA)
+ {
+ emitcode ("ora", "1,s");
+ emitcode ("ais", "#1");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ needpula = FALSE;
+ }
+ else
+ accopWithAop ("ora", AOP (result), offset);
+ storeRegToAop (hc08_reg_a, AOP (result), offset);
+
+ pullOrFreeReg (hc08_reg_a, needpula);
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRLC - generate code for rotate left with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRLC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset = 0;
+ char *shift;
+ bool resultInA = FALSE;
+ bool needpula = FALSE;
+
+ D(emitcode ("; genRLC",""));
+
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ if ((AOP_TYPE (result) == AOP_REG)
+ && (AOP (result)->aopu.aop_reg[0]->rIdx == A_IDX))
+ resultInA = TRUE;
+
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ shift="lsl";
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ while (size--)
+ {
+ rmwWithAop (shift, AOP (result), offset--);
+ shift="rol";
+ }
+ }
+ else
+ {
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), offset);
+ rmwWithReg (shift, hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ hc08_freeReg (hc08_reg_a);
+ shift="rol";
+ }
+ }
+
+ if ((!hc08_reg_a->isFree) || resultInA)
+ {
+ pushReg (hc08_reg_a, TRUE);
+ needpula = TRUE;
+ }
+
+ /* now we need to put the carry into the
+ lowest order byte of the result */
+ offset = 0;
+ emitcode ("clra","");
+ emitcode ("rola","");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ if (resultInA)
+ {
+ emitcode ("ora", "1,s");
+ emitcode ("ais", "#1");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ needpula = FALSE;
+ }
+ else
+ accopWithAop ("ora", AOP (result), offset);
+ storeRegToAop (hc08_reg_a, AOP (result), offset);
+
+ pullOrFreeReg (hc08_reg_a, needpula);
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetHbit - generates code get highest order bit */
+/*-----------------------------------------------------------------*/
+static void
+genGetHbit (iCode * ic)
+{
+ operand *left, *result;
+
+ D(emitcode ("; genGetHbit",""));
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* get the highest order byte into a */
+ loadRegFromAop (hc08_reg_a, AOP (left), AOP_SIZE (left) - 1);
+ emitcode ("rola", "");
+ emitcode ("clra", "");
+ emitcode ("rola", "");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ storeRegToFullAop (hc08_reg_a, AOP (result), FALSE);
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* 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 ("rola", ""); /* 1 cycle */
+ break;
+ case 2:
+ emitcode ("rola", ""); /* 1 cycle */
+ emitcode ("rola", ""); /* 1 cycle */
+ break;
+ case 3:
+ emitcode ("nsa", "");
+ emitcode ("rora", "");
+ break;
+ case 4:
+ emitcode ("nsa", ""); /* 3 cycles */
+ break;
+ case 5:
+ emitcode ("nsa", ""); /* 3 cycles */
+ emitcode ("rola", ""); /* 1 cycle */
+ break;
+ case 6:
+ emitcode ("nsa", ""); /* 3 cycles */
+ emitcode ("rola", ""); /* 1 cycle */
+ emitcode ("rola", ""); /* 1 cycle */
+ break;
+ case 7:
+ emitcode ("nsa", ""); /* 3 cycles */
+ emitcode ("rola", ""); /* 1 cycle */
+ emitcode ("rola", ""); /* 1 cycle */
+ emitcode ("rola", ""); /* 1 cycle */
+ break;
+ }
+}
+#endif
+
+
+/*-----------------------------------------------------------------*/
+/* AccLsh - left shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccLsh (int shCount)
+{
+ int i;
+
+ shCount &= 0x0007; // shCount : 0..7
+
+ /* Shift counts of 4 and 5 are currently optimized for code size. */
+ /* Falling through to the unrolled loop would be optimal for code speed. */
+ /* For shift counts of 6 and 7, the unrolled loop is never optimal. */
+ switch (shCount)
+ {
+ case 4:
+ accopWithMisc ("nsa", "");
+ accopWithMisc ("and", "#0xf0");
+ /* total: 5 cycles, 3 bytes */
+ return;
+ case 5:
+ accopWithMisc ("nsa", "");
+ accopWithMisc ("and", "#0xf0");
+ accopWithMisc ("lsla", "");
+ /* total: 6 cycles, 4 bytes */
+ return;
+ case 6:
+ accopWithMisc ("rora", "");
+ accopWithMisc ("rora", "");
+ accopWithMisc ("rora", "");
+ accopWithMisc ("and", "#0xc0");
+ /* total: 5 cycles, 5 bytes */
+ return;
+ case 7:
+ accopWithMisc ("rora", "");
+ accopWithMisc ("clra", "");
+ accopWithMisc ("rora", "");
+ /* total: 3 cycles, 3 bytes */
+ return;
+ }
+
+ /* lsla is only 1 cycle and byte, so an unrolled loop is often */
+ /* the fastest (shCount<6) and shortest (shCount<4). */
+ for (i=0;i<shCount;i++)
+ accopWithMisc ("lsla", "");
+}
+
+
+/*-----------------------------------------------------------------*/
+/* AccSRsh - signed right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccSRsh (int shCount)
+{
+ int i;
+
+ shCount &= 0x0007; // shCount : 0..7
+
+ if (shCount == 7)
+ {
+ accopWithMisc ("rola", "");
+ accopWithMisc ("clra", "");
+ accopWithMisc ("sbc", zero);
+ /* total: 4 cycles, 4 bytes */
+ return;
+ }
+
+ for (i=0;i<shCount;i++)
+ accopWithMisc ("asra", "");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRsh (int shCount, bool sign)
+{
+ int i;
+
+ if (sign)
+ {
+ AccSRsh (shCount);
+ return;
+ }
+
+ shCount &= 0x0007; // shCount : 0..7
+
+ /* Shift counts of 4 and 5 are currently optimized for code size. */
+ /* Falling through to the unrolled loop would be optimal for code speed. */
+ /* For shift counts of 6 and 7, the unrolled loop is never optimal. */
+ switch (shCount)
+ {
+ case 4:
+ accopWithMisc ("nsa", "");
+ accopWithMisc ("and", "#0x0f");
+ /* total: 5 cycles, 3 bytes */
+ return;
+ case 5:
+ accopWithMisc ("nsa", "");
+ accopWithMisc ("and", "#0x0f");
+ accopWithMisc ("lsra", "");
+ /* total: 6 cycles, 4 bytes */
+ return;
+ case 6:
+ accopWithMisc ("rola", "");
+ accopWithMisc ("rola", "");
+ accopWithMisc ("rola", "");
+ accopWithMisc ("and", "#0x03");
+ /* total: 5 cycles, 5 bytes */
+ return;
+ case 7:
+ accopWithMisc ("rola", "");
+ accopWithMisc ("clra", "");
+ accopWithMisc ("rola", "");
+ /* total: 3 cycles, 3 bytes */
+ return;
+ }
+
+ /* lsra is only 1 cycle and byte, so an unrolled loop is often */
+ /* the fastest (shCount<6) and shortest (shCount<4). */
+ for (i=0;i<shCount;i++)
+ accopWithMisc ("lsra", "");
+}
+
+
+/*-----------------------------------------------------------------*/
+/* XAccLsh - left shift register pair XA by known count */
+/*-----------------------------------------------------------------*/
+static void
+XAccLsh (int shCount)
+{
+ int i;
+
+ shCount &= 0x000f; // shCount : 0..15
+
+ if (shCount>=8)
+ {
+ AccLsh (shCount-8);
+ transferRegReg (hc08_reg_a, hc08_reg_x, FALSE);
+ loadRegFromConst (hc08_reg_a, zero);
+ return;
+ }
+
+ /* if we can beat 2n cycles or bytes for some special case, do it here */
+ switch (shCount)
+ {
+ case 7:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** lsrx 1 1 0abc defg ijkl mnop h
+ ** rora 1 1 0abc defg hijk lmno p
+ ** tax 1 1 hijk lmno hijk lmno p
+ ** clra 1 1 hijk lmno 0000 0000 p
+ ** rora 1 1 hijk lmno p000 0000 0
+ ** total: 5 cycles, 5 bytes (beats 14 cycles, 14 bytes)
+ */
+ rmwWithReg ("lsr", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ transferRegReg (hc08_reg_a, hc08_reg_x, FALSE);
+ loadRegFromConst (hc08_reg_a, zero);
+ rmwWithReg ("ror", hc08_reg_a);
+ return;
+
+ default:
+ ;
+ }
+
+ /* lsla/rolx is only 2 cycles and bytes, so an unrolled loop is often */
+ /* the fastest and shortest. */
+ for (i=0;i<shCount;i++)
+ {
+ rmwWithReg ("lsl", hc08_reg_a);
+ rmwWithReg ("rol", hc08_reg_x);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* XAccSRsh - signed right shift register pair XA by known count */
+/*-----------------------------------------------------------------*/
+static void
+XAccSRsh (int shCount)
+{
+ int i;
+
+ shCount &= 0x000f; // shCount : 0..7
+
+ /* if we can beat 2n cycles or bytes for some special case, do it here */
+ switch (shCount)
+ {
+ case 15:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** lslx 1 1 bcde fgh0 ijkl mnop a
+ ** clra 1 1 bcde fgh0 0000 0000 a
+ ** rola 1 1 bcde fgh0 0000 000a 0
+ ** nega 1 1 bcde fgh0 aaaa aaaa a
+ ** tax 1 1 aaaa aaaa aaaa aaaa a
+ ** total: 5 cycles, 5 bytes
+ */
+ rmwWithReg ("lsl", hc08_reg_x);
+ loadRegFromConst (hc08_reg_a, zero);
+ rmwWithReg ("rol", hc08_reg_a);
+ rmwWithReg ("neg", hc08_reg_a);
+ transferRegReg (hc08_reg_a, hc08_reg_x, FALSE);
+ return;
+
+ case 14:
+ case 13:
+ case 12:
+ case 11:
+ case 10:
+ case 9:
+ case 8:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** txa 1 1 abcd efgh abcd efgh ?
+ ** (AccSRsh) <8 <8 abcd efgh LSBresult ?
+ ** lsla 1 1 abcd efgh ???? ???? a
+ ** clrx 1 1 0000 0000 ???? ???? a
+ ** rolx 1 1 0000 000a ???? ???? 0
+ ** negx 1 1 aaaa aaaa ???? ???? a
+ ** rora 1 1 aaaa aaaa LSBresult 0
+ ** total: n-2 cycles, n-2 bytes (beats 2n cycles, 2n bytes (for n>=8))
+ */
+ transferRegReg (hc08_reg_x, hc08_reg_a, FALSE);
+ AccSRsh (shCount-8);
+ rmwWithReg ("lsl", hc08_reg_a);
+ loadRegFromConst (hc08_reg_x, zero);
+ rmwWithReg ("rol", hc08_reg_x);
+ rmwWithReg ("neg", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ return;
+
+ default:
+ ;
+ }
+
+ /* asrx/rola is only 2 cycles and bytes, so an unrolled loop is often */
+ /* the fastest and shortest. */
+ for (i=0;i<shCount;i++)
+ {
+ rmwWithReg ("asr", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* XAccRsh - right shift register pair XA by known count */
+/*-----------------------------------------------------------------*/
+static void
+XAccRsh (int shCount, bool sign)
+{
+ int i;
+
+ if (sign)
+ {
+ XAccSRsh (shCount);
+ return;
+ }
+
+ shCount &= 0x000f; // shCount : 0..7
+
+ /* if we can beat 2n cycles or bytes for some special case, do it here */
+ switch (shCount)
+ {
+ case 15:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** clra 1 1 abcd efgh 0000 0000 a
+ ** lslx 1 1 bcde fgh0 0000 0000 a
+ ** rola 1 1 bcde fgh0 0000 000a 0
+ ** clrx 1 1 0000 0000 0000 000a 0
+ ** total: 4 cycles, 4 bytes
+ */
+ loadRegFromConst (hc08_reg_x, zero);
+ rmwWithReg ("lsl", hc08_reg_x);
+ rmwWithReg ("rol", hc08_reg_a);
+ loadRegFromConst (hc08_reg_a, zero);
+ return;
+
+ case 14:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** clra 1 1 abcd efgh 0000 0000 a
+ ** lslx 1 1 bcde fgh0 0000 0000 a
+ ** rola 1 1 bcde fgh0 0000 000a 0
+ ** lslx 1 1 cdef gh00 0000 000a b
+ ** rola 1 1 cdef gh00 0000 00ab 0
+ ** clrx 1 1 0000 0000 0000 000a 0
+ ** total: 6 cycles, 6 bytes
+ */
+ loadRegFromConst (hc08_reg_x, zero);
+ rmwWithReg ("lsl", hc08_reg_x);
+ rmwWithReg ("rol", hc08_reg_a);
+ rmwWithReg ("lsl", hc08_reg_x);
+ rmwWithReg ("rol", hc08_reg_a);
+ loadRegFromConst (hc08_reg_a, zero);
+ return;
+
+ case 13:
+ case 12:
+ case 11:
+ case 10:
+ case 9:
+ case 8:
+ transferRegReg (hc08_reg_x, hc08_reg_a, FALSE);
+ AccRsh (shCount-8, FALSE);
+ loadRegFromConst (hc08_reg_x, zero);
+ return;
+
+ case 7:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** lsla 1 1 abcd efgh jklm nop0 i
+ ** txa 1 1 abcd efgh abcd efgh i
+ ** rola 1 1 abcd efgh bcde fghi a
+ ** clrx 1 1 0000 0000 bcde fghi a
+ ** rolx 1 1 0000 000a bcde fghi 0
+ ** total: 5 cycles, 5 bytes (beats 14 cycles, 14 bytes)
+ */
+ rmwWithReg ("lsl", hc08_reg_a);
+ transferRegReg (hc08_reg_x, hc08_reg_a, FALSE);
+ rmwWithReg ("rol", hc08_reg_a);
+ loadRegFromConst (hc08_reg_x, zero);
+ rmwWithReg ("rol", hc08_reg_x);
+ return;
+ case 6:
+ /* bytes cycles reg x reg a carry
+ ** abcd efgh ijkl mnop ?
+ ** lsla 1 1 abcd efgh jklm nop0 i
+ ** rolx 1 1 bcde fghi jklm nop0 a
+ ** rola 1 1 bcde fghi klmn op0a j
+ ** rolx 1 1 cdef ghij klmn op0a b
+ ** rola 1 1 cdef ghij lmno p0ab k
+ ** and #3 2 2 cdef ghij 0000 00ab k
+ ** psha 1 2 cdef ghij 0000 00ab k
+ ** txa 1 1 cdef ghij cdef ghij k
+ ** pula 1 2 0000 00ab cdef ghij k
+ ** total: 12 cycles, 10 bytes (beats 12 bytes)
+ */
+ default:
+ ;
+ }
+
+ /* lslx/rola is only 2 cycles and bytes, so an unrolled loop is often */
+ /* the fastest and shortest. */
+ for (i=0;i<shCount;i++)
+ {
+ rmwWithReg ("lsl", hc08_reg_x);
+ rmwWithReg ("rol", hc08_reg_a);
+ }
+
+}
+
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* shiftR1Left2Result - shift right one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR1Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int sign)
+{
+ loadRegFromAop (hc08_reg_a, AOP (left), offl);
+ /* shift right accumulator */
+ AccRsh (shCount, sign);
+ storeRegToAop (hc08_reg_a, AOP (result), offr);
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* shiftL1Left2Result - shift left one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL1Left2Result (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ loadRegFromAop (hc08_reg_a, AOP (left), offl);
+ /* shift left accumulator */
+ AccLsh (shCount);
+ storeRegToAop (hc08_reg_a, AOP (result), offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* movLeft2Result - move byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+movLeft2Result (operand * left, int offl,
+ operand * result, int offr, int sign)
+{
+ if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
+ {
+ transferAopAop (AOP (left), offl, AOP (result), offr);
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* AccAXRsh1 - right shift 0->a:x->c by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRsh1 (char *x)
+{
+ emitcode ("lsra", "");
+ emitcode ("ror", "%s", x);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* AccAXRshS1 - signed right shift s->a:x->c by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRshS1 (char *x)
+{
+ emitcode ("asra", "");
+ emitcode ("ror", "%s", x);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLrl1 (char *x)
+{
+ emitcode ("rol", "%s", x);
+ emitcode ("rola", "");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh1 - left shift a:x<-0 by 1 */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLsh1 (char *x)
+{
+ emitcode ("lsl", "%s", x);
+ emitcode ("rola", "");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh - left shift a:x by known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXLsh (char *x, int shCount)
+{
+ int i;
+
+ for (i=0;i<shCount;i++) {
+ AccAXLsh1 (x);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRsh - right shift a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRsh (char *x, int shCount)
+{
+ int i;
+
+ for (i=0;i<shCount;i++) {
+ AccAXRsh1 (x);
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRshS - right shift signed a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void
+AccAXRshS (char *x, int shCount)
+{
+ int i;
+
+ for (i=0;i<shCount;i++) {
+ AccAXRshS1 (x);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL2Left2Result - shift left two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL2Left2Result (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ int i;
+ bool needpula = FALSE;
+ bool needpulx = FALSE;
+
+ needpula = pushRegIfUsed (hc08_reg_a);
+ needpulx = pushRegIfUsed (hc08_reg_x);
+
+ loadRegFromAop (hc08_reg_xa, AOP (left), offl);
+
+ switch (shCount)
+ {
+ case 7:
+ rmwWithReg ("lsr", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ transferRegReg (hc08_reg_a, hc08_reg_x, FALSE);
+ rmwWithReg ("clr", hc08_reg_a);
+ rmwWithReg ("ror", hc08_reg_a);
+ break;
+ default:
+ for (i=0; i<shCount; i++)
+ {
+ rmwWithReg ("lsl", hc08_reg_a);
+ rmwWithReg ("rol", hc08_reg_x);
+ }
+ }
+ storeRegToAop (hc08_reg_xa, AOP (result), offl);
+
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ pullOrFreeReg (hc08_reg_a, needpula);
+
+}
+
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* shiftR2Left2Result - shift right two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR2Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int sign)
+{
+ int i;
+ bool needpula = FALSE;
+ bool needpulx = FALSE;
+
+ needpula = pushRegIfUsed (hc08_reg_a);
+ needpulx = pushRegIfUsed (hc08_reg_x);
+
+ loadRegFromAop (hc08_reg_xa, AOP (left), offl);
+ for (i=0; i<shCount; i++)
+ {
+ if (sign)
+ rmwWithReg ("asr", hc08_reg_x);
+ else
+ rmwWithReg ("lsr", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ }
+ storeRegToAop (hc08_reg_xa, AOP (result), offl);
+
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ pullOrFreeReg (hc08_reg_a, needpula);
+}
+#endif
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* shiftLLeftOrResult - shift left one byte from left, or to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftLLeftOrResult (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ loadRegFromAop (hc08_reg_a, AOP (left), offl);
+ /* shift left accumulator */
+ AccLsh (shCount);
+ /* or with result */
+ accopWithAop ("ora", AOP (result), offr);
+ /* back to result */
+ storeRegToAop (hc08_reg_a, AOP (result), offr);
+ hc08_freeReg (hc08_reg_a);
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* shiftRLeftOrResult - shift right one byte from left,or to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftRLeftOrResult (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ loadRegFromAop (hc08_reg_a, AOP (left), offl);
+ /* shift left accumulator */
+ AccRsh (shCount, FALSE);
+ /* or with result */
+ accopWithAop ("ora", AOP (result), offr);
+ /* back to result */
+ storeRegToAop (hc08_reg_a, AOP (result), offr);
+ hc08_freeReg (hc08_reg_a);
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshOne - left shift a one byte quantity by known count */
+/*-----------------------------------------------------------------*/
+static void
+genlshOne (operand * result, operand * left, int shCount)
+{
+ D(emitcode ("; genlshOne",""));
+
+ shiftL1Left2Result (left, LSB, result, LSB, shCount);
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshTwo - left shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genlshTwo (operand * result, operand * left, int shCount)
+{
+ int size;
+
+ D(emitcode ("; genlshTwo",""));
+
+ size = getDataSize (result);
+
+ /* if shCount >= 8 */
+ if (shCount >= 8)
+ {
+ shCount -= 8;
+
+ if (size > 1)
+ {
+ if (shCount)
+ shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+ else
+ movLeft2Result (left, LSB, result, MSB16, 0);
+ }
+ storeConstToAop(zero, AOP (result), LSB);
+ }
+
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ if (size == 1)
+ shiftL1Left2Result (left, LSB, result, LSB, shCount);
+ else
+ shiftL2Left2Result (left, LSB, result, LSB, shCount);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftLLong - shift left one long from left to result */
+/* offl = LSB or MSB16 */
+/*-----------------------------------------------------------------*/
+static void
+shiftLLong (operand * left, operand * result, int offr)
+{
+// char *l;
+// int size = AOP_SIZE (result);
+
+ bool needpula = FALSE;
+ bool needpulx = FALSE;
+
+ needpula = pushRegIfUsed (hc08_reg_a);
+ needpulx = pushRegIfUsed (hc08_reg_x);
+
+ loadRegFromAop (hc08_reg_xa, AOP (left), LSB);
+ rmwWithReg ("lsl", hc08_reg_a);
+ rmwWithReg ("rol", hc08_reg_x);
+ storeRegToAop (hc08_reg_xa, AOP (result), offr);
+
+ if (offr==LSB)
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), MSB24);
+ rmwWithReg ("rol", hc08_reg_a);
+ rmwWithReg ("rol", hc08_reg_x);
+ storeRegToAop (hc08_reg_xa, AOP (result), offr+2);
+ }
+ else if (offr==MSB16)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), MSB24);
+ rmwWithReg ("rol", hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), offr+2);
+ }
+
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ pullOrFreeReg (hc08_reg_a, needpula);
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshFour - shift four byte by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genlshFour (operand * result, operand * left, int shCount)
+{
+ int size;
+
+ D(emitcode ("; genlshFour",""));
+
+ size = AOP_SIZE (result);
+
+ /* TODO: deal with the &result == &left case */
+
+ /* if shifting more that 3 bytes */
+ if (shCount >= 24)
+ {
+ shCount -= 24;
+ if (shCount)
+ /* lowest order of left goes to the highest
+ order of the destination */
+ shiftL1Left2Result (left, LSB, result, MSB32, shCount);
+ else
+ movLeft2Result (left, LSB, result, MSB32, 0);
+ storeConstToAop (zero, AOP (result), LSB);
+ storeConstToAop (zero, AOP (result), MSB16);
+ storeConstToAop (zero, AOP (result), MSB24);
+ return;
+ }
+
+ /* more than two bytes */
+ else if (shCount >= 16)
+ {
+ /* lower order two bytes goes to higher order two bytes */
+ shCount -= 16;
+ /* if some more remaining */
+ if (shCount)
+ shiftL2Left2Result (left, LSB, result, MSB24, shCount);
+ else
+ {
+ movLeft2Result (left, MSB16, result, MSB32, 0);
+ movLeft2Result (left, LSB, result, MSB24, 0);
+ }
+ storeConstToAop (zero, AOP (result), LSB);
+ storeConstToAop (zero, AOP (result), MSB16);
+ return;
+ }
+
+ /* if more than 1 byte */
+ else if (shCount >= 8)
+ {
+ /* lower order three bytes goes to higher order three bytes */
+ shCount -= 8;
+ if (size == 2)
+ {
+ if (shCount)
+ shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+ else
+ movLeft2Result (left, LSB, result, MSB16, 0);
+ }
+ else
+ { /* size = 4 */
+ if (shCount == 0)
+ {
+ movLeft2Result (left, MSB24, result, MSB32, 0);
+ movLeft2Result (left, MSB16, result, MSB24, 0);
+ movLeft2Result (left, LSB, result, MSB16, 0);
+ storeConstToAop (zero, AOP (result), LSB);
+ }
+ else if (shCount == 1)
+ shiftLLong (left, result, MSB16);
+ else
+ {
+ shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
+ shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+ shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
+ storeConstToAop (zero, AOP (result), LSB);
+ }
+ }
+ }
+
+ /* 1 <= shCount <= 7 */
+ else if (shCount <= 2)
+ {
+ shiftLLong (left, result, LSB);
+ if (shCount == 2)
+ shiftLLong (result, result, LSB);
+ }
+ /* 3 <= shCount <= 7, optimize */
+ else
+ {
+ shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
+ shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
+ shiftL2Left2Result (left, LSB, result, LSB, shCount);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShiftLiteral - left shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShiftLiteral (operand * left,
+ operand * right,
+ operand * result,
+ iCode * ic)
+{
+ int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ D(emitcode ("; genLeftShiftLiteral",""));
+
+ freeAsmop (right, NULL, ic, TRUE);
+
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+// size = getSize (operandType (result));
+ size = AOP_SIZE (result);
+
+#if VIEW_SIZE
+ emitcode ("; shift left ", "result %d, left %d", size,
+ AOP_SIZE (left));
+#endif
+
+ if (shCount == 0)
+ {
+ while (size--)
+ transferAopAop( AOP(left), size, AOP(result), size);
+ }
+ else if (shCount >= (size * 8))
+ {
+ while (size--)
+ storeConstToAop (zero, AOP (result), size);
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genlshOne (result, left, shCount);
+ break;
+
+ case 2:
+ genlshTwo (result, left, shCount);
+ break;
+
+ case 4:
+ genlshFour (result, left, shCount);
+ break;
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "*** ack! mystery literal shift!\n");
+ break;
+ }
+ }
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShift - generates code for left shifting */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShift (iCode * ic)
+{
+ operand *left, *right, *result;
+ int size, offset;
+ symbol *tlbl, *tlbl1;
+// int i;
+ char *shift;
+ regs *reg;
+
+ 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 A : 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 ) */
+
+ 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)))
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ transferAopAop (AOP (left), offset, AOP (result), offset);
+ offset++;
+ }
+ }
+ freeAsmop (left, NULL, ic, TRUE);
+
+ tlbl = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = 0;
+ tlbl1 = newiTempLabel (NULL);
+
+ reg = hc08_reg_a;
+
+ loadRegFromAop (reg, AOP (right), 0);
+ freeAsmop (right, NULL, ic, TRUE);
+ emitBranch ("beq", tlbl1);
+ emitLabel (tlbl);
+
+ shift="lsl";
+ for (offset=0;offset<size;offset++)
+ {
+ rmwWithAop (shift, AOP (result), offset);
+ shift="rol";
+ }
+ rmwWithReg ("dec", reg);
+ emitBranch ("bne", tlbl);
+ emitLabel (tlbl1);
+ hc08_freeReg (reg);
+
+ freeAsmop (result, 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",""));
+
+ loadRegFromAop (hc08_reg_a, AOP (left), 0);
+ AccRsh (shCount, sign);
+ storeRegToFullAop (hc08_reg_a, AOP (result), 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)
+ {
+ if (shCount || sign)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), 1);
+ AccRsh (shCount-8, sign);
+ storeRegToFullAop (hc08_reg_a, AOP (result), sign);
+ }
+ else
+ {
+ transferAopAop (AOP (left), 1, AOP (result), 0);
+ storeConstToAop (zero, AOP (result), 1);
+ }
+ }
+
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), 0);
+ XAccRsh (shCount, sign);
+ storeRegToAop (hc08_reg_xa, AOP (result), 0);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRLong - shift right one long from left to result */
+/* offl = LSB or MSB16 */
+/*-----------------------------------------------------------------*/
+static void
+shiftRLong (operand * left, int offl,
+ operand * result, int sign)
+{
+// char *l;
+ // int size = AOP_SIZE (result);
+
+ bool needpula = FALSE;
+ bool needpulx = FALSE;
+
+ needpula = pushRegIfUsed (hc08_reg_a);
+ needpulx = pushRegIfUsed (hc08_reg_x);
+
+ if (offl==LSB)
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), MSB24);
+ if (sign)
+ rmwWithReg ("asr", hc08_reg_x);
+ else
+ rmwWithReg ("lsr", hc08_reg_x);
+ rmwWithReg ("rol", hc08_reg_a);
+ storeRegToAop (hc08_reg_xa, AOP (result), MSB24);
+ }
+ else if (offl==MSB16)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), MSB32);
+ if (sign)
+ rmwWithReg ("asr", hc08_reg_a);
+ else
+ rmwWithReg ("lsr", hc08_reg_a);
+ storeRegToAop (hc08_reg_a, AOP (result), MSB24);
+ }
+
+ loadRegFromAop (hc08_reg_xa, AOP (left), offl);
+ rmwWithReg ("ror", hc08_reg_x);
+ rmwWithReg ("ror", hc08_reg_a);
+ storeRegToAop (hc08_reg_xa, AOP (result), LSB);
+
+
+ pullOrFreeReg (hc08_reg_x, needpulx);
+ pullOrFreeReg (hc08_reg_a, needpula);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshFour - shift four byte by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshFour (operand * result, operand * left,
+ int shCount, int sign)
+{
+ /* TODO: handle cases where left == result */
+
+ D(emitcode ("; genrshFour",""));
+
+ /* if shifting more that 3 bytes */
+ if (shCount >= 24)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (left), 3);
+ AccRsh (shCount-24, sign);
+ storeRegToFullAop (hc08_reg_a, AOP (result), sign);
+ return;
+ }
+ else if (shCount >= 16)
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), 2);
+ XAccRsh (shCount-16, sign);
+ storeRegToFullAop (hc08_reg_xa, AOP (result), sign);
+ return;
+ }
+ else if (shCount >= 8)
+ {
+ if (shCount == 1)
+ shiftRLong (left, MSB16, result, sign);
+ else if (shCount == 8)
+ {
+ transferAopAop (AOP (left), 1, AOP (result), 0);
+ transferAopAop (AOP (left), 2, AOP (result), 1);
+ loadRegFromAop (hc08_reg_a, AOP (left), 3);
+ storeRegToAop (hc08_reg_a, AOP (result), 2);
+ storeRegSignToUpperAop (hc08_reg_a, AOP(result), 3, sign);
+ }
+ else if (shCount == 9)
+ {
+ shiftRLong (left, MSB16, result, sign);
+ }
+ else
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), 1);
+ XAccRsh (shCount-8, FALSE);
+ storeRegToAop (hc08_reg_xa, AOP (result), 0);
+ loadRegFromAop (hc08_reg_x, AOP (left), 3);
+ loadRegFromConst (hc08_reg_a, zero);
+ XAccRsh (shCount-8, sign);
+ accopWithAop ("ora", AOP (result), 1);
+ storeRegToFullAop (hc08_reg_xa, AOP (result), 1);
+ }
+ }
+ else
+ { /* 1 <= shCount <= 7 */
+ if (shCount == 1)
+ {
+ shiftRLong (left, LSB, result, sign);
+ }
+ else
+ {
+ loadRegFromAop (hc08_reg_xa, AOP (left), 0);
+ XAccRsh (shCount, FALSE);
+ storeRegToAop (hc08_reg_xa, AOP (result), 0);
+ loadRegFromAop (hc08_reg_a, AOP (left), 2);
+ AccLsh (8-shCount);
+ accopWithAop ("ora", AOP (result), 1);
+ storeRegToFullAop (hc08_reg_xa, AOP (result), 1);
+ loadRegFromAop (hc08_reg_xa, AOP (left), 2);
+ XAccRsh (shCount, sign);
+ storeRegToAop (hc08_reg_xa, AOP (result), 2);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShiftLiteral - right shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genRightShiftLiteral (operand * left,
+ operand * right,
+ operand * result,
+ iCode * ic,
+ int sign)
+{
+ int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ D(emitcode ("; genRightShiftLiteral",""));
+
+ 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
+
+ size = getDataSize (left);
+ /* test the LEFT size !!! */
+
+ /* I suppose that the left size >= result size */
+ if (shCount == 0)
+ {
+ size = getDataSize (result);
+ while (size--)
+ transferAopAop (AOP (left), size, AOP(result), size);
+ }
+ else if (shCount >= (size * 8))
+ {
+ if (sign) {
+ /* get sign in acc.7 */
+ loadRegFromAop (hc08_reg_a, AOP (left), size -1);
+ }
+ 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:
+ break;
+ }
+ }
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genRightShift - generate code for right shifting */
+/*-----------------------------------------------------------------*/
+static void
+genRightShift (iCode * ic)
+{
+ operand *right, *left, *result;
+ sym_link *retype;
+ int size, offset;
+// char *l;
+ symbol *tlbl, *tlbl1;
+ char *shift;
+ bool sign;
+
+ D(emitcode ("; genRightShift",""));
+
+ /* if signed then we do it the hard way preserve the
+ sign bit moving it inwards */
+ retype = getSpec (operandType (IC_RESULT (ic)));
+ sign = !SPEC_USIGN (retype);
+
+ /* 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, sign);
+ return;
+ }
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in X : 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 ) */
+
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ if (sameRegs(AOP (right), AOP (result)) || IS_AOP_XA (AOP (result)))
+ AOP (result) = forceStackedAop (AOP (result));
+
+ size = AOP_SIZE (result);
+ offset = size-1;
+ while (size--)
+ {
+ transferAopAop (AOP (left), offset, AOP (result), offset);
+ offset--;
+ }
+
+ tlbl = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = 0;
+ tlbl1 = newiTempLabel (NULL);
+
+ loadRegFromAop (hc08_reg_x, AOP (right), 0);
+ emitcode ("tstx", "");
+ emitcode ("beq", "%05d$", tlbl1->key + 100);
+ emitcode ("", "%05d$:", tlbl->key + 100);
+ shift= sign ? "asr" : "lsr";
+ for (offset=size-1;offset>=0;offset--)
+ {
+ rmwWithAop (shift, AOP (result), offset);
+ shift="ror";
+ }
+ rmwWithReg ("dec", hc08_reg_x);
+ emitcode ("bne","%05d$", tlbl->key + 100);
+ emitcode ("", "%05d$:", tlbl1->key + 100);
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits */
+/*-----------------------------------------------------------------*/
+static void
+genUnpackBits (operand * result)
+{
+ int offset = 0; /* result byte offset */
+ int rsize; /* result size */
+ int rlen = 0; /* remaining bitfield length */
+ sym_link *etype; /* bitfield type information */
+ int blen; /* bitfield length */
+ int bstr; /* bitfield starting bit within byte */
+
+ D(emitcode ("; genUnpackBits",""));
+
+ etype = getSpec (operandType (result));
+ rsize = getSize (operandType (result));
+ blen = SPEC_BLEN (etype);
+ bstr = SPEC_BSTR (etype);
+
+ /* If the bitfield length is less than a byte */
+ if (blen < 8)
+ {
+ emitcode ("lda", ",x");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ AccRsh (bstr, FALSE);
+ emitcode ("and", "#0x%02x", ((unsigned char) -1) >> (8 - blen));
+ storeRegToAop (hc08_reg_a, AOP (result), 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)
+ {
+ emitcode ("lda", ",x");
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ if (rlen>8)
+ emitcode ("aix", "#1");
+ }
+
+ /* Handle the partial byte at the end */
+ if (rlen)
+ {
+ emitcode ("lda", ",x");
+ emitcode ("and", "#0x%02x", ((unsigned char) -1) >> (8-rlen));
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ }
+
+finish:
+ if (offset < rsize)
+ {
+ rsize -= offset;
+ while (rsize--)
+ storeConstToAop (zero, AOP (result), offset++);
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerGet - generates code when ptr offset is known */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerGet (operand * left,
+ operand * result,
+ iCode * ic)
+{
+ int size, offset = 0;
+ asmop *derefaop;
+
+ D(emitcode ("; genDataPointerGet",""));
+
+ aopOp (result, ic, TRUE);
+ size = AOP_SIZE (result);
+
+ derefaop = aopDerefAop (AOP (left));
+ freeAsmop (left, NULL, ic, TRUE);
+ derefaop->size = size;
+
+ while (size--)
+ {
+ transferAopAop(derefaop, offset, AOP (result), offset);
+ offset++;
+ }
+
+ freeAsmop (NULL, derefaop, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerGet - emitcode for near pointer fetch */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerGet (operand * left,
+ operand * result,
+ iCode * ic,
+ iCode * pi)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (result));
+
+ D(emitcode ("; genNearPointerGet",""));
+
+ aopOp (left, ic, FALSE);
+
+ /* if left is rematerialisable and
+ result is not bit variable type and
+ the left is pointer to data space i.e
+ lower 128 bytes of space */
+ if ((AOP_TYPE (left) == AOP_IMMD)
+ || (AOP_TYPE (left) == AOP_LIT)
+ /* !IS_BITVAR (retype) */
+ /* && DCL_TYPE (ltype) == POINTER */ )
+ {
+ genDataPointerGet (left, result, ic);
+ return;
+ }
+
+ /* if the operand is already in hx
+ then we do nothing else we move the value to hx */
+ if (AOP_TYPE (left) != AOP_STR)
+ {
+ /* if this is remateriazable */
+ loadRegFromAop (hc08_reg_x, AOP (left), 0);
+ loadRegFromConst (hc08_reg_h, zero);
+ }
+
+ /* so hx now contains the address */
+ aopOp (result, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ genUnpackBits (result);
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = size-1;
+
+ while (size--)
+ {
+ accopWithMisc ("lda", ",x");
+ if (size || pi)
+ {
+ rmwWithReg ("inc", hc08_reg_x);
+ }
+ storeRegToAop (hc08_reg_a, AOP (result), offset--);
+ hc08_freeReg (hc08_reg_a);
+ }
+ }
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+ if (pi /* && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR */) {
+ aopOp (IC_RESULT (pi), pi, FALSE);
+ storeRegToAop (hc08_reg_x, AOP (IC_RESULT (pi)), 0);
+ freeAsmop (IC_RESULT (pi), NULL, pi, TRUE);
+ pi->generated = 1;
+ }
+
+ hc08_freeReg (hc08_reg_hx);
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerGet - get value from far space */
+/*-----------------------------------------------------------------*/
+static void
+genFarPointerGet (operand * left,
+ operand * result, iCode * ic, iCode * pi)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (result));
+
+ D(emitcode ("; genFarPointerGet",""));
+
+ aopOp (left, ic, FALSE);
+
+ /* if left is rematerialisable and
+ result is not bit variable type and
+ the left is pointer to data space i.e
+ lower 128 bytes of space */
+ if (AOP_TYPE (left) == AOP_IMMD &&
+ !IS_BITVAR (retype)
+ /* && DCL_TYPE (ltype) == POINTER */ )
+ {
+ genDataPointerGet (left, result, ic);
+ return;
+ }
+
+ /* if the operand is already in hx
+ then we do nothing else we move the value to hx */
+ if (AOP_TYPE (left) != AOP_STR)
+ {
+ /* if this is remateriazable */
+ loadRegFromAop (hc08_reg_hx, AOP (left), 0);
+ }
+
+ /* so hx now contains the address */
+ aopOp (result, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ genUnpackBits (result);
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = size-1;
+
+ while (size--)
+ {
+ accopWithMisc ("lda", ",x");
+ if (size || pi)
+ {
+ emitcode ("aix", "#1");
+ hc08_dirtyReg (hc08_reg_hx, FALSE);
+ }
+ storeRegToAop (hc08_reg_a, AOP (result), offset--);
+ hc08_freeReg (hc08_reg_a);
+ }
+ }
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+ if (pi /* && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR */) {
+ aopOp (IC_RESULT (pi), pi, FALSE);
+ storeRegToAop (hc08_reg_hx, AOP (IC_RESULT (pi)), 0);
+ freeAsmop (IC_RESULT (pi), NULL, pi, TRUE);
+ pi->generated = 1;
+ }
+
+ hc08_freeReg (hc08_reg_hx);
+
+}
+
+
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void
+genPointerGet (iCode * ic, iCode *pi)
+{
+ operand *left, *result;
+ sym_link *type, *etype;
+ int p_type;
+
+ D(emitcode ("; genPointerGet",""));
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* 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 */
+ if (p_type == GPOINTER && 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:
+#if 0
+ genNearPointerGet (left, result, ic, pi);
+ break;
+#endif
+ case GPOINTER:
+ case CPOINTER:
+ case FPOINTER:
+ genFarPointerGet (left, result, ic, pi);
+ break;
+
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPackBits - generates code for packed bit storage */
+/*-----------------------------------------------------------------*/
+static void
+genPackBits (sym_link * etype,
+ operand * right)
+{
+ int offset = 0; /* source byte offset */
+ int rlen = 0; /* remaining bitfield length */
+ int blen; /* bitfield length */
+ int bstr; /* bitfield starting bit within byte */
+ int litval; /* source literal value (if AOP_LIT) */
+ unsigned char mask; /* bitmask within current byte */
+
+ 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) floatFromVal (AOP (right)->aopu.aop_lit);
+ litval <<= bstr;
+ litval &= (~mask) & 0xff;
+
+ emitcode ("lda", ",x");
+ if ((mask|litval)!=0xff)
+ emitcode ("and","#0x%02x", mask);
+ if (litval)
+ emitcode ("ora","#0x%02x", litval);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ emitcode ("sta", ",x");
+
+ hc08_freeReg (hc08_reg_a);
+ return;
+ }
+
+ /* Case with a bitfield length < 8 and arbitrary source
+ */
+ loadRegFromAop (hc08_reg_a, AOP (right), 0);
+ /* shift and mask source value */
+ AccLsh (bstr);
+ emitcode ("and", "#0x%02x", (~mask) & 0xff);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ pushReg (hc08_reg_a, TRUE);
+
+ emitcode ("lda", ",x");
+ emitcode ("and", "#0x%02x", mask);
+ emitcode ("ora", "1,s");
+ emitcode ("sta", ",x");
+ pullReg (hc08_reg_a);
+
+ hc08_freeReg (hc08_reg_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)
+ {
+ if (AOP (right)->type == AOP_DIR)
+ {
+ emitcode ("mov", "%s,x+", aopAdrStr(AOP (right), offset, FALSE));
+ }
+ else
+ {
+ loadRegFromAop (hc08_reg_a, AOP (right), offset);
+ emitcode ("sta", "%d,x", offset);
+ }
+ offset++;
+ }
+
+ /* If there was a partial byte at the end */
+ if (rlen)
+ {
+ mask = (((unsigned char) -1 << rlen) & 0xff);
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* Case with partial byte and literal source
+ */
+ litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ litval >>= (blen-rlen);
+ litval &= (~mask) & 0xff;
+ emitcode ("lda", "%d,x", offset);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ if ((mask|litval)!=0xff)
+ emitcode ("and","#0x%02x", mask);
+ if (litval)
+ emitcode ("ora","#0x%02x", litval);
+ emitcode ("sta", "%d,x", offset);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ hc08_freeReg (hc08_reg_a);
+ return;
+ }
+
+ /* Case with partial byte and arbitrary source
+ */
+ loadRegFromAop (hc08_reg_a, AOP (right), offset++);
+ emitcode ("and", "#0x%02x", (~mask) & 0xff);
+ hc08_dirtyReg (hc08_reg_a, FALSE);
+ pushReg (hc08_reg_a, TRUE);
+
+ emitcode ("lda", ",x");
+ emitcode ("and", "#0x%02x", mask);
+ emitcode ("ora", "1,s");
+ emitcode ("sta", ",x");
+ }
+
+ hc08_freeReg (hc08_reg_a);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerSet - remat pointer to data space */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerSet (operand * right,
+ operand * result,
+ iCode * ic)
+{
+ int size, offset = 0;
+ asmop *derefaop;
+
+ D(emitcode ("; genDataPointerSet",""));
+
+ aopOp (right, ic, FALSE);
+ size = AOP_SIZE (right);
+
+ derefaop = aopDerefAop (AOP (result));
+ freeAsmop (result, NULL, ic, TRUE);
+ derefaop->size = size;
+
+ while (size--)
+ {
+ transferAopAop (AOP (right), offset, derefaop, offset);
+ offset++;
+ }
+
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (NULL, derefaop, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerSet - emitcode for near pointer put */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerSet (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 ("; genNearPointerSet",""));
+
+ 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 operand is already in hx
+ then we do nothing else we move the value to hx */
+ if (AOP_TYPE (result) != AOP_STR)
+ {
+ loadRegFromAop (hc08_reg_x, AOP (result), 0);
+ loadRegFromConst (hc08_reg_h, zero);
+ }
+ /* so hx now contains the address */
+ aopOp (right, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype) || IS_BITVAR (letype))
+ genPackBits ((IS_BITVAR (retype) ? retype : letype), right);
+ else
+ {
+ size = AOP_SIZE (right);
+ offset = size-1;
+
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (right), offset--);
+ accopWithMisc ("sta", ",x");
+ if (size || pi)
+ {
+ rmwWithReg ("inc", hc08_reg_x);
+ }
+ hc08_freeReg (hc08_reg_a);
+ }
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+
+ if (pi /* && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD */) {
+ aopOp (IC_RESULT (pi), pi, FALSE);
+ storeRegToAop (hc08_reg_x, AOP (IC_RESULT (pi)), 0);
+ freeAsmop (IC_RESULT (pi), NULL, pi, TRUE);
+ pi->generated=1;
+ }
+
+ hc08_freeReg (hc08_reg_hx);
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerSet - set value from 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);
+
+ /* 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 operand is already in hx
+ then we do nothing else we move the value to hx */
+ if (AOP_TYPE (result) != AOP_STR)
+ {
+ loadRegFromAop (hc08_reg_hx, AOP (result), 0);
+ }
+ /* so hx now contains the address */
+ aopOp (right, ic, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype) || IS_BITVAR (letype))
+ genPackBits ((IS_BITVAR (retype) ? retype : letype), right);
+ else
+ {
+ size = AOP_SIZE (right);
+ offset = size-1;
+
+ while (size--)
+ {
+ loadRegFromAop (hc08_reg_a, AOP (right), offset--);
+ accopWithMisc ("sta", ",x");
+ if (size || pi)
+ {
+ emitcode ("aix", "#1");
+ }
+ hc08_freeReg (hc08_reg_a);
+ }
+ }
+
+ freeAsmop (result, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+
+ if (pi /* && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD */) {
+ aopOp (IC_RESULT (pi), pi, FALSE);
+ storeRegToAop (hc08_reg_hx, AOP (IC_RESULT (pi)), 0);
+ freeAsmop (IC_RESULT (pi), NULL, pi, TRUE);
+ pi->generated=1;
+ }
+
+ hc08_freeReg (hc08_reg_hx);
+
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* 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 */
+ if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
+ IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
+ 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:
+#if 0
+ genNearPointerSet (right, result, ic, pi);
+ break;
+#endif
+
+ case GPOINTER:
+ case FPOINTER:
+ genFarPointerSet (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;
+
+ D(emitcode ("; genIfx",""));
+
+ aopOp (cond, ic, FALSE);
+
+ /* get the value into acc */
+ if (AOP_TYPE (cond) != AOP_CRY)
+ asmopToBool (AOP (cond), FALSE);
+ else
+ isbit = 1;
+ /* the result is now in the accumulator */
+ freeAsmop (cond, NULL, ic, TRUE);
+
+ /* if there was something to be popped then do it */
+ if (popIc)
+ genIpop (popIc);
+
+ /* if the condition is a bit variable */
+ if (isbit && IS_ITEMP (cond) &&
+ SPIL_LOC (cond))
+ genIfxJump (ic, SPIL_LOC (cond)->rname);
+ else if (isbit && !IS_ITEMP (cond))
+ genIfxJump (ic, OP_SYMBOL (cond)->rname);
+ else
+ genIfxJump (ic, "a");
+
+ 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)
+ {
+ /* if it has an offset then we need to compute
+ it */
+ hc08_useReg (hc08_reg_hx);
+ emitcode ("tsx", "");
+ emitcode ("aix", "#%d", _G.stackOfs + _G.stackPushes +sym->stack);
+ storeRegToFullAop (hc08_reg_hx, AOP (IC_RESULT (ic)), FALSE);
+ hc08_freeReg (hc08_reg_hx);
+
+ goto release;
+ }
+
+ /* object not on stack then we need the name */
+ size = AOP_SIZE (IC_RESULT (ic));
+ offset = 0;
+
+ while (size--)
+ {
+ char s[SDCC_NAME_MAX+10];
+ switch (offset) {
+ case 0:
+ sprintf (s, "#%s", sym->rname);
+ break;
+ case 1:
+ sprintf (s, "#>%s", sym->rname);
+ break;
+ default:
+ sprintf (s, "#(%s >> %d)",
+ sym->rname,
+ offset * 8);
+ }
+ storeConstToAop(s, AOP (IC_RESULT (ic)), offset++);
+ }
+
+release:
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genAssign - generate code for assignment */
+/*-----------------------------------------------------------------*/
+static void
+genAssign (iCode * ic)
+{
+ operand *result, *right;
+ int size, offset;
+// unsigned long lit = 0L;
+
+ D(emitcode("; genAssign",""));
+
+ result = IC_RESULT (ic);
+ right = IC_RIGHT (ic);
+
+ /* if they are the same */
+ if (operandsEqu (result, right)) {
+ return;
+ }
+
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* if they are the same registers */
+ if (sameRegs (AOP (right), AOP (result)))
+ goto release;
+
+ if ((AOP_TYPE (right) == AOP_LIT)
+ && (IS_AOP_HX(AOP(result))))
+ {
+ loadRegFromAop(hc08_reg_hx, AOP (right), 0);
+ goto release;
+ }
+
+ /* general case */
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ transferAopAop (AOP (right), offset, AOP (result), offset);
+ offset++;
+ }
+
+release:
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genJumpTab - genrates code for jump table */
+/*-----------------------------------------------------------------*/
+static void
+genJumpTab (iCode * ic)
+{
+ symbol *jtab;
+// char *l;
+
+ D(emitcode ("; genJumpTab",""));
+
+ aopOp (IC_JTCOND (ic), ic, FALSE);
+ /* get the condition into accumulator */
+ loadRegFromAop (hc08_reg_a, AOP (IC_JTCOND (ic)), 0);
+ freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
+ /* multiply by three */
+ pushReg (hc08_reg_a, FALSE);
+ emitcode ("lsla", "");
+ emitcode ("add","1,s");
+ transferRegReg (hc08_reg_a, hc08_reg_x, TRUE);
+ loadRegFromConst (hc08_reg_h, zero);
+
+ jtab = newiTempLabel (NULL);
+ emitcode ("jmp", "%05d$,x", jtab->key + 100);
+ emitcode ("", "%05d$:", jtab->key + 100);
+ /* now generate the jump labels */
+ for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
+ jtab = setNextItem (IC_JTLABELS (ic)))
+ emitcode ("jmp", "%05d$", jtab->key + 100);
+
+ hc08_dirtyReg (hc08_reg_a, TRUE);
+ hc08_dirtyReg (hc08_reg_hx, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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;
+
+ 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, FALSE);
+
+
+ /* if they are the same size : or less */
+ if (AOP_SIZE (result) <= AOP_SIZE (right))
+ {
+
+ /* if they are in the same place */
+ #if 0
+ if (sameRegs (AOP (right), AOP (result)))
+ goto release;
+ #endif
+
+ /* if they in different places then copy */
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ transferAopAop(AOP (right), offset, AOP (result), offset);
+ offset++;
+ }
+ goto release;
+ }
+
+
+ /* if the result is of type pointer */
+ if (IS_PTR (ctype))
+ {
+
+ int p_type;
+ sym_link *type = operandType (right);
+ sym_link *etype = getSpec (type);
+
+ /* pointer to generic pointer */
+ if (IS_GENPTR (ctype))
+ {
+ 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--)
+ {
+ transferAopAop(AOP (right), offset, AOP (result), offset);
+ offset++;
+ }
+ /* the last byte depending on type */
+#if 0
+ {
+ int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
+ char gpValStr[10];
+
+ if (gpVal == -1)
+ {
+ // pointerTypeToGPByte will have bitched.
+ exit(1);
+ }
+
+ sprintf(gpValStr, "#0x%d", gpVal);
+ aopPut (AOP (result), gpValStr, GPTRSIZE - 1);
+ }
+#endif
+ goto release;
+ }
+
+ /* just copy the pointers */
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ transferAopAop(AOP (right), offset, AOP (result), 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--)
+ {
+ transferAopAop(AOP (right), offset, AOP (result), 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--)
+ storeConstToAop (zero, AOP (result), offset++);
+ }
+ else
+ {
+ /* we need to extend the sign :{ */
+ loadRegFromAop (hc08_reg_a, AOP (right), AOP_SIZE (right) -1);
+ accopWithMisc ("rola", "");
+ accopWithMisc ("clra", "");
+ accopWithMisc ("sbc", zero);
+ while (size--)
+ storeRegToAop (hc08_reg_a, AOP (result), offset++);
+ }
+
+ /* we are done hurray !!!! */
+
+release:
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genDjnz - generate decrement & jump if not zero instrucion */
+/*-----------------------------------------------------------------*/
+static int
+genDjnz (iCode * ic, iCode * ifx)
+{
+ symbol *lbl, *lbl1;
+ if (!ifx)
+ return 0;
+
+ D(emitcode ("; genDjnz",""));
+
+ /* 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;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ if (AOP_SIZE (IC_RESULT (ic))>1)
+ {
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ return 0;
+ }
+
+ /* otherwise we can save BIG */
+ lbl = newiTempLabel (NULL);
+ lbl1 = newiTempLabel (NULL);
+
+
+ emitcode ("dbnz", "%s,%05d$", aopAdrStr (AOP (IC_RESULT (ic)), 0, FALSE),
+ lbl->key + 100);
+
+ emitBranch ("bra", lbl1);
+ emitLabel (lbl);
+ emitBranch ("jmp", IC_TRUE (ifx));
+ emitLabel (lbl1);
+
+ 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;
+ int offset;
+ D(emitcode ("; genReceive",""));
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_RESULT (ic));
+ offset = 0;
+
+ if (ic->argreg) {
+ while (size--) {
+ transferAopAop( hc08_aop_pass[offset+(ic->argreg-1)], 0,
+ AOP (IC_RESULT (ic)), offset);
+ if (hc08_aop_pass[offset]->type == AOP_REG)
+ hc08_freeReg (hc08_aop_pass[offset]->aopu.aop_reg[0]);
+ offset++;
+ }
+ }
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genhc08Code - generate code for HC08 based controllers */
+/*-----------------------------------------------------------------*/
+void
+genhc08Code (iCode * lic)
+{
+ iCode *ic;
+ int cln = 0;
+
+ lineHead = lineCurr = NULL;
+
+ /* print the allocation information */
+ if (allocInfo && currFunc)
+ printAllocInfo (currFunc, codeOutFile);
+ /* if debug information required */
+ if (options.debug && currFunc)
+ {
+ debugFile->writeFunction(currFunc);
+ _G.debugLine = 1;
+ if (IS_STATIC (currFunc->etype))
+ emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
+ else
+ emitcode ("", "G$%s$0$0 ==.", currFunc->name);
+ _G.debugLine = 0;
+ }
+ /* stack pointer name */
+ if (options.useXstack)
+ spname = "_spx";
+ else
+ spname = "sp";
+
+ hc08_aop_pass[0] = newAsmop (AOP_REG);
+ hc08_aop_pass[0]->size=1;
+ hc08_aop_pass[0]->aopu.aop_reg[0] = hc08_reg_a;
+ hc08_aop_pass[1] = newAsmop (AOP_REG);
+ hc08_aop_pass[1]->size=1;
+ hc08_aop_pass[1]->aopu.aop_reg[0] = hc08_reg_x;
+ hc08_aop_pass[2] = newAsmop (AOP_DIR);
+ hc08_aop_pass[2]->size=1;
+ hc08_aop_pass[2]->aopu.aop_dir = "__ret2";
+ hc08_aop_pass[3] = newAsmop (AOP_DIR);
+ hc08_aop_pass[3]->size=1;
+ hc08_aop_pass[3]->aopu.aop_dir = "__ret3";
+
+ for (ic = lic; ic; ic = ic->next)
+ {
+
+ if (ic->lineno && cln != ic->lineno)
+ {
+ if (options.debug)
+ {
+ _G.debugLine = 1;
+ emitcode ("", "C$%s$%d$%d$%d ==.",
+ FileBaseName (ic->filename), ic->lineno,
+ ic->level, ic->block);
+ _G.debugLine = 0;
+ }
+ if (!options.noCcodeInAsm) {
+ emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
+ printCLine(ic->filename, ic->lineno));
+ }
+ cln = ic->lineno;
+ }
+ if (options.iCodeInAsm) {
+ char regsInUse[80];
+ int i;
+
+ for (i=0; i<6; i++) {
+ sprintf (®sInUse[i],
+ "%c", ic->riu & (1<<i) ? i+'0' : '-');
+ }
+ regsInUse[i]=0;
+ emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
+ }
+ /* 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;
+
+ {
+ int i;
+ regs *reg;
+ symbol *sym;
+
+ for (i=A_IDX;i<=XA_IDX;i++)
+ {
+ reg = hc08_regWithIdx(i);
+ if (reg->aop)
+ emitcode("","; %s = %s offset %d", reg->name,
+ aopName(reg->aop), reg->aopofs);
+ reg->isFree = TRUE;
+ }
+ if (IC_LEFT (ic) && IS_ITEMP (IC_LEFT (ic)))
+ {
+ sym = OP_SYMBOL (IC_LEFT (ic));
+ if (sym->accuse == ACCUSE_HX)
+ {
+ hc08_reg_h->isFree = FALSE;
+ hc08_reg_x->isFree = FALSE;
+ }
+ else if (sym->accuse == ACCUSE_XA)
+ {
+ hc08_reg_a->isFree = FALSE;
+ if (sym->nRegs>1)
+ hc08_reg_x->isFree = FALSE;
+ }
+ }
+ if (IC_RIGHT (ic) && IS_ITEMP (IC_RIGHT (ic)))
+ {
+ sym = OP_SYMBOL (IC_RIGHT (ic));
+ if (sym->accuse == ACCUSE_HX)
+ {
+ hc08_reg_h->isFree = FALSE;
+ hc08_reg_x->isFree = FALSE;
+ }
+ else if (sym->accuse == ACCUSE_XA)
+ {
+ hc08_reg_a->isFree = FALSE;
+ if (sym->nRegs>1)
+ hc08_reg_x->isFree = FALSE;
+ }
+ }
+ }
+
+ /* 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:
+ /* IPOP happens only when trying to restore a
+ spilt live range, if there is an ifx statement
+ following this pop then the if statement might
+ be using some of the registers being popped which
+ would destory the contents of the register so
+ we need to check for this condition and handle it */
+ if (ic->next &&
+ ic->next->op == IFX &&
+ regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
+ genIfx (ic->next, 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 '+':
+ if (!genPointerGetSetOfs (ic))
+ 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
+ during parsing SDCC.y */
+ 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:
+ genGetHbit (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)))));
+ 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;
+
+ default:
+ ic = ic;
+ }
+
+ if (!hc08_reg_a->isFree)
+ emitcode("","; forgot to free a");
+ if (!hc08_reg_x->isFree)
+ emitcode("","; forgot to free x");
+ if (!hc08_reg_h->isFree)
+ emitcode("","; forgot to free h");
+ if (!hc08_reg_hx->isFree)
+ emitcode("","; forgot to free hx");
+ if (!hc08_reg_xa->isFree)
+ emitcode("","; forgot to free xa");
+ }
+
+
+ /* now we are ready to call the
+ peep hole optimizer */
+ if (!options.nopeep)
+ peepHole (&lineHead);
+
+ /* now do the actual printing */
+ printLine (lineHead, codeOutFile);
+ return;
+}
--- /dev/null
+/*------------------------------------------------------------------------
+
+ 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"
+
+/*-----------------------------------------------------------------*/
+/* 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 genhc08Code (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;
+ }
+_G;
+
+/* Shared with gen.c */
+int hc08_ptrRegReq; /* one byte pointer register required */
+
+/* 8051 registers */
+regs regshc08[] =
+{
+
+ {REG_GPR, A_IDX, REG_GPR, "a", "a", "0", 1, NULL, 0, 1},
+ {REG_GPR, X_IDX, REG_GPR, "x", "x", "0", 2, NULL, 0, 1},
+ {REG_GPR, H_IDX, REG_GPR, "h", "h", "0", 4, NULL, 0, 1},
+ {REG_PTR, HX_IDX, REG_PTR, "hx", "hx", "0", 6, NULL, 0, 1},
+ {REG_GPR, XA_IDX, REG_GPR, "xa", "xa", "0", 3, NULL, 0, 1},
+
+ {REG_CND, CND_IDX, REG_CND, "C", "C", "xreg", 0, NULL, 0, 1},
+};
+int hc08_nRegs = 6;
+
+regs *hc08_reg_a;
+regs *hc08_reg_x;
+regs *hc08_reg_h;
+regs *hc08_reg_hx;
+regs *hc08_reg_xa;
+
+static void spillThis (symbol *);
+static void freeAllRegs ();
+
+/*-----------------------------------------------------------------*/
+/* allocReg - allocates register of given type */
+/*-----------------------------------------------------------------*/
+static regs *
+allocReg (short type)
+{
+ return NULL;
+
+ if ((type==REG_PTR) && (regshc08[HX_IDX].isFree))
+ {
+ regshc08[HX_IDX].isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed =
+ bitVectSetBit (currFunc->regsUsed, HX_IDX);
+ return ®shc08[HX_IDX];
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* hc08_regWithIdx - returns pointer to register wit index number */
+/*-----------------------------------------------------------------*/
+regs *
+hc08_regWithIdx (int idx)
+{
+ int i;
+
+ for (i = 0; i < hc08_nRegs; i++)
+ if (regshc08[i].rIdx == idx)
+ return ®shc08[i];
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "regWithIdx not found");
+ exit (1);
+}
+
+/*-----------------------------------------------------------------*/
+/* hc08_freeReg - frees a register */
+/*-----------------------------------------------------------------*/
+void
+hc08_freeReg (regs * reg)
+{
+ if (!reg)
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+ "hc08_freeReg - Freeing NULL register");
+ exit (1);
+ }
+
+ reg->isFree = 1;
+
+ switch (reg->rIdx)
+ {
+ case A_IDX:
+ if (hc08_reg_x->isFree)
+ hc08_reg_xa->isFree = 1;
+ break;
+ case X_IDX:
+ if (hc08_reg_a->isFree)
+ hc08_reg_xa->isFree = 1;
+ if (hc08_reg_h->isFree)
+ hc08_reg_hx->isFree = 1;
+ break;
+ case H_IDX:
+ if (hc08_reg_x->isFree)
+ hc08_reg_hx->isFree = 1;
+ break;
+ case HX_IDX:
+ hc08_reg_h->isFree = 1;
+ hc08_reg_x->isFree = 1;
+ if (hc08_reg_a->isFree)
+ hc08_reg_xa->isFree = 1;
+ break;
+ case XA_IDX:
+ hc08_reg_x->isFree = 1;
+ hc08_reg_a->isFree = 1;
+ if (hc08_reg_h->isFree)
+ hc08_reg_hx->isFree = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* nFreeRegs - returns number of free registers */
+/*-----------------------------------------------------------------*/
+static int
+nFreeRegs (int type)
+{
+ int i;
+ int nfr = 0;
+
+ return 0;
+
+ for (i = 0; i < hc08_nRegs; i++)
+ if (regshc08[i].isFree && regshc08[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);
+}
+
+/*-----------------------------------------------------------------*/
+/* hc08_useReg - marks a register as used */
+/*-----------------------------------------------------------------*/
+void
+hc08_useReg (regs * reg)
+{
+ reg->isFree = 0;
+
+ switch (reg->rIdx)
+ {
+ case A_IDX:
+ hc08_reg_xa->aop = NULL;
+ hc08_reg_xa->isFree = 0;
+ break;
+ case X_IDX:
+ hc08_reg_xa->aop = NULL;
+ hc08_reg_xa->isFree = 0;
+ hc08_reg_hx->aop = NULL;
+ hc08_reg_hx->isFree = 0;
+ break;
+ case H_IDX:
+ hc08_reg_hx->aop = NULL;
+ hc08_reg_hx->isFree = 0;
+ break;
+ case HX_IDX:
+ hc08_reg_h->aop = NULL;
+ hc08_reg_h->isFree = 0;
+ hc08_reg_x->aop = NULL;
+ hc08_reg_x->isFree = 0;
+ break;
+ case XA_IDX:
+ hc08_reg_x->aop = NULL;
+ hc08_reg_x->isFree = 0;
+ hc08_reg_a->aop = NULL;
+ hc08_reg_a->isFree = 0;
+ break;
+ default:
+ break;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* hc08_dirtyReg - marks a register as dirty */
+/*-----------------------------------------------------------------*/
+void
+hc08_dirtyReg (regs * reg, bool freereg)
+{
+ reg->aop = NULL;
+
+ switch (reg->rIdx)
+ {
+ case A_IDX:
+ hc08_reg_xa->aop = NULL;
+ break;
+ case X_IDX:
+ hc08_reg_xa->aop = NULL;
+ hc08_reg_hx->aop = NULL;
+ break;
+ case H_IDX:
+ hc08_reg_hx->aop = NULL;
+ break;
+ case HX_IDX:
+ hc08_reg_h->aop = NULL;
+ hc08_reg_x->aop = NULL;
+ break;
+ case XA_IDX:
+ hc08_reg_x->aop = NULL;
+ hc08_reg_a->aop = NULL;
+ break;
+ default:
+ break;
+ }
+ if (freereg)
+ hc08_freeReg(reg);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 splilocation 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
+ the 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))
+ {
+ *sloc = sym;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* spillLRWithPtrReg :- will spil those live ranges which use PTR */
+/*-----------------------------------------------------------------*/
+static void
+spillLRWithPtrReg (symbol * forSym)
+{
+ symbol *lrsym;
+ regs *hx;
+ int k;
+
+ if (!_G.regAssigned ||
+ bitVectIsZero (_G.regAssigned))
+ return;
+
+ hx = hc08_regWithIdx (HX_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 with this then
+ not 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 spil it */
+ for (j = 0; j < lrsym->nRegs; j++)
+ if (lrsym->regs[j] == hx)
+ {
+ spillThis (lrsym);
+ break;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* createStackSpil - create a location on the stack to spil */
+/*-----------------------------------------------------------------*/
+static symbol *
+createStackSpil (symbol * sym)
+{
+ symbol *sloc = NULL;
+ int useXstack, model;
+
+ char slocBuffer[30];
+
+ /* 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 */
+
+ if (sprintf (slocBuffer, "sloc%d", _G.slocNum++) >= sizeof (slocBuffer))
+ {
+ fprintf (stderr, "***Internal error: slocBuffer overflowed: %s:%d\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+
+ sloc = newiTemp (slocBuffer);
+
+ /* set the type to the spilling symbol */
+ sloc->type = copyLinkChain (sym->type);
+ sloc->etype = getSpec (sloc->type);
+ SPEC_SCLS (sloc->etype) = S_DATA;
+ 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 */
+/*-----------------------------------------------------------------*/
+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;
+
+ 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 has 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])
+ {
+ hc08_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 (!hc08_ptrRegReq && isSpiltOnStack (sym))
+// {
+// hc08_ptrRegReq++;
+// spillLRWithPtrReg (sym);
+// }
+
+ 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);
+
+ /* get all live ranges that are rematerizable */
+ 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);
+ strcpy (sym->rname, (sym->usl.spillLoc->rname[0] ?
+ sym->usl.spillLoc->rname :
+ sym->usl.spillLoc->name));
+ 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 not
+ used in the remainder of the block */
+ if (!_G.blockSpil && (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])
+ hc08_freeReg (ssym->regs[i]);
+
+ /* if spilt on stack then free up hx
+ if it could have been assigned to as gprs */
+ if (!hc08_ptrRegReq && isSpiltOnStack (ssym))
+ {
+ hc08_ptrRegReq++;
+ spillLRWithPtrReg (ssym);
+ }
+
+ /* 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 regs *
+getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ regs *reg;
+
+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;
+
+ /* this looks like an infinite loop but
+ in really selectSpil will abort */
+ goto tryAgain;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegGpr - will try for GPR if not spil */
+/*-----------------------------------------------------------------*/
+static regs *
+getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ regs *reg;
+
+tryAgain:
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ if (!hc08_ptrRegReq)
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ /* we have to spil */
+ if (!spilSomething (ic, ebp, sym))
+ return NULL;
+
+ /* this looks like an infinite loop but
+ in really selectSpil will abort */
+ goto tryAgain;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegPtrNoSpil - get it cannot split */
+/*-----------------------------------------------------------------*/
+static regs *getRegPtrNoSpil()
+{
+ regs *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 split */
+/*-----------------------------------------------------------------*/
+static regs *getRegGprNoSpil()
+{
+
+ regs *reg;
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ if (!hc08_ptrRegReq)
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ assert(0);
+
+ /* just to make the compiler happy */
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* symHasReg - symbol has a given register */
+/*-----------------------------------------------------------------*/
+static bool
+symHasReg (symbol * sym, regs * reg)
+{
+ int i;
+
+ for (i = 0; i < sym->nRegs; i++)
+ if (sym->regs[i] == reg)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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->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]))
+ hc08_freeReg (sym->regs[i]);
+ }
+ else
+ hc08_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 avlb registers
+ of te type required */
+ if (rt == REG_PTR)
+ {
+ /* special case for pointer type
+ if pointer type not avlb then
+ check for type gpr */
+ if (nFreeRegs (rt) >= nr)
+ return 0;
+ if (nFreeRegs (REG_GPR) >= nr)
+ return 0;
+ }
+ else
+ {
+ if (hc08_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 res- */
+/* ult 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 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;
+again:
+ 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)
+ {
+ regs *tmp = result->regs[i];
+ result->regs[i] = result->regs[j];
+ result->regs[j] = tmp;
+ change ++;
+ goto again;
+ }
+ return change;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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;
+
+ /* of all instructions do */
+ for (ic = ebbs[i]->sch; ic; ic = ic->next) {
+#if 1
+ int reg;
+
+ // update the registers in use at the start of this icode
+ for (reg=0; reg<hc08_nRegs; reg++) {
+ if (regshc08[reg].isFree) {
+ ic->riu &= ~(regshc08[reg].mask);
+ } else {
+ ic->riu |= (regshc08[reg].mask);
+ }
+ }
+#endif
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+ }
+ /* if trying to allocate this will cause
+ a spill and there is nothing to spill
+ or this one is rematerializable then
+ spill this one */
+ willCS = willCauseSpill (sym->nRegs, sym->regType);
+ spillable = computeSpillable (ic);
+ if (sym->remat || (willCS && bitVectIsZero (spillable))) {
+ 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) PTRSIZE) {
+ hc08_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++) {
+ if (sym->regType == REG_PTR)
+ sym->regs[j] = getRegPtr (ic, ebbs[i], sym);
+ else
+ sym->regs[j] = getRegGpr (ic, ebbs[i], sym);
+
+ /* if the allocation failed which means
+ this was spilt then break */
+ if (!sym->regs[j]) {
+ break;
+ }
+ }
+
+ /* 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 && ic->op != '=') {
+ positionRegs (OP_SYMBOL (IC_RESULT (ic)),
+ OP_SYMBOL (IC_LEFT (ic)));
+ }
+ /* 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)));
+ }
+
+ if (ptrRegSet) {
+ hc08_ptrRegReq--;
+ ptrRegSet = 0;
+ }
+
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* fillGaps - Try to fill in the Gaps left by Pass1 */
+/*-----------------------------------------------------------------*/
+static void fillGaps()
+{
+ symbol *sym =NULL;
+ int key =0;
+
+ if (getenv("DISABLE_FILL_GAPS")) return;
+
+ /* look for livernages that was 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 ;
+
+ /* 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++ )
+ hc08_useReg(clr->regs[k]);
+ }
+
+ if (willCauseSpill(sym->nRegs,sym->regType)) {
+ /* NOPE :( clear all registers & and continue */
+ freeAllRegs();
+ continue ;
+ }
+
+ /* THERE IS HOPE !!!! */
+ for (i=0; i < sym->nRegs ; i++ ) {
+ if (sym->regType == REG_PTR)
+ sym->regs[i] = getRegPtrNoSpil ();
+ else
+ sym->regs[i] = getRegGprNoSpil ();
+ }
+
+ /* 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 */
+ sym->isspilt = 0;
+ for (i = 0 ; i < sym->defs->size ; i++ ) {
+ if (bitVectBitValue(sym->defs,i)) {
+ iCode *ic;
+ if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+ 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)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_LEFT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_LEFT(ic)));
+ }
+ if (IS_SYMOP(IC_RIGHT(ic)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RIGHT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_RIGHT(ic)));
+ }
+ if (pdone > 1) break;
+ }
+ }
+ for (i = 0 ; i < sym->uses->size ; i++ ) {
+ if (bitVectBitValue(sym->uses,i)) {
+ iCode *ic;
+ if (!(ic = hTabItemWithKey(iCodehTab,i))) continue ;
+ if (SKIP_IC(ic)) continue;
+ if (!IS_ASSIGN_ICODE(ic)) continue ;
+
+ /* if result is assigned to registers */
+ if (IS_SYMOP(IC_RESULT(ic)) &&
+ bitVectBitValue(_G.totRegAssigned,OP_SYMBOL(IC_RESULT(ic))->key)) {
+ pdone += positionRegs(sym,OP_SYMBOL(IC_RESULT(ic)));
+ }
+ if (pdone > 1) break;
+ }
+ }
+ /* 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();
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* rUmaskForOp :- returns register mask for an operand */
+/*-----------------------------------------------------------------*/
+bitVect *
+hc08_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 (hc08_nRegs);
+
+ for (j = 0; j < sym->nRegs; j++)
+ {
+ 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 (hc08_nRegs);
+
+ /* do the special cases first */
+ if (ic->op == IFX)
+ {
+ rmask = bitVectUnion (rmask,
+ hc08_rUmaskForOp (IC_COND (ic)));
+ goto ret;
+ }
+
+ /* for the jumptable */
+ if (ic->op == JUMPTABLE)
+ {
+ rmask = bitVectUnion (rmask,
+ hc08_rUmaskForOp (IC_JTCOND (ic)));
+
+ goto ret;
+ }
+
+ /* of all other cases */
+ if (IC_LEFT (ic))
+ rmask = bitVectUnion (rmask,
+ hc08_rUmaskForOp (IC_LEFT (ic)));
+
+
+ if (IC_RIGHT (ic))
+ rmask = bitVectUnion (rmask,
+ hc08_rUmaskForOp (IC_RIGHT (ic)));
+
+ if (IC_RESULT (ic))
+ rmask = bitVectUnion (rmask,
+ hc08_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 (hc08_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)
+{
+ char *s = buffer;
+ iCode *ic = sym->rematiCode;
+// int offset = 0;
+
+ while (1)
+ {
+
+ /* if plus or minus print the right hand side */
+ if (ic->op == '+' || ic->op == '-')
+ {
+ sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
+ ic->op);
+ s += strlen (s);
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+/*
+ if (ic->op == '+')
+ {
+ offset += operandLitValue (IC_RIGHT (ic));
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ continue;
+ }
+ if (ic->op == '-')
+ {
+ offset -= 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 */
+ sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
+ break;
+ }
+
+ return buffer;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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);
+ 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) &&
+ !sym->noSpilLoc &&
+ !IS_BITVAR (sym->etype))
+ {
+
+
+ /* and that pointer is remat in data space */
+ if (IS_SYMOP (IC_LEFT (ic)) &&
+ OP_SYMBOL (IC_LEFT (ic))->remat &&
+ !IS_CAST_ICODE(OP_SYMBOL (IC_LEFT (ic))->rematiCode) &&
+ DCL_TYPE (aggrToPtr (operandType(IC_LEFT(ic)), FALSE)) == POINTER)
+ {
+ /* create a psuedo symbol & force a spil */
+ symbol *psym = newSymbol (rematStr (OP_SYMBOL (IC_LEFT (ic))), 1);
+ psym->type = sym->type;
+ psym->etype = sym->etype;
+ strcpy (psym->rname, psym->name);
+ sym->isspilt = 1;
+ sym->usl.spillLoc = psym;
+#if 0 // an alternative fix for bug #480076
+ /* now this is a useless assignment to itself */
+ remiCodeFromeBBlock (ebbs, ic);
+#else
+ /* now this really is an assignment to itself, make it so;
+ it will be optimized out later */
+ ic->op='=';
+ ReplaceOpWithCheaperOp(&IC_RIGHT(ic), IC_RESULT(ic));
+ IC_LEFT(ic)=NULL;
+#endif
+ 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 > 4)
+ {
+ fprintf (stderr, "allocated more than 4 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
+ 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 < hc08_nRegs; i++) {
+ regshc08[i].isFree = 1;
+ regshc08[i].aop = NULL;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 0
+ /* 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;
+#endif
+
+ /* if any three 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 0
+ if (isOperandInFarSpace(IC_RESULT(ic)) && !farSpacePackable(ic)) {
+ return 0;
+ }
+#endif
+
+ /* find the definition of iTempNN scanning backwards if we find a
+ a use of the true symbol in before we find the definition then
+ we cannot */
+ for (dic = ic->prev; dic; dic = dic->prev)
+ {
+
+#if 0 /* jwk: This collides with 1.43 but I really see no need for
+ this anymore. It fixes bug #716790 and substantially improves
+ redundant register usage around function calls.
+ */
+
+ /* if there is a function call then don't pack it */
+ if ((dic->op == CALL || dic->op == PCALL))
+ {
+ dic = NULL;
+ break;
+ }
+#endif
+
+ if (SKIP_IC2 (dic))
+ continue;
+
+ 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 (POINTER_SET (dic) &&
+ IC_RESULT (dic)->key == IC_RESULT (ic)->key)
+ {
+ dic = NULL;
+ break;
+ }
+ }
+
+ if (!dic)
+ return 0; /* did not find */
+
+ /* if assignment then check that right is not a bit */
+ if (ASSIGNMENT (dic) && !POINTER_SET (dic))
+ {
+ sym_link *etype = operandType (IC_RIGHT (dic));
+ if (IS_BITFIELD (etype))
+ {
+ /* if result is a bit too then it's ok */
+ etype = operandType (IC_RESULT (dic));
+ 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 */
+ /* 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?
+
+ /* 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);
+ }
+
+ 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);
+ 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 (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 0
+ 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;
+ }
+#endif
+
+ /* 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;
+
+ /* 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 0
+ 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;
+ }
+#endif
+ /* found it we need to remove it from the
+ block */
+ reassignAliasedSym (ebp, dic, ic, IC_RIGHT(ic));
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
+
+
+/*-----------------------------------------------------------------*/
+/* packRegsForOneuse : - will reduce some registers for single Use */
+/*-----------------------------------------------------------------*/
+static iCode *
+packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
+{
+ bitVect *uses;
+ iCode *dic, *sic;
+
+ /* if returning a literal then do nothing */
+ if (!IS_SYMOP (op))
+ return NULL;
+
+ /* only upto 2 bytes since we cannot predict
+ the usage of b, & acc */
+ if (getSize (operandType (op)) > (fReturnSizeHC08 - 2))
+ return NULL;
+
+ return NULL;
+
+ if (ic->op != SEND //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 a symbol as used in one
+ instruction use only && if the defintion is local
+ (ie. within the basic block) && has only one definition &&
+ that definiion is either a return value from a
+ function or does not contain any variables in
+ far space */
+ uses = bitVectCopy (OP_USES (op));
+ bitVectUnSetBit (uses, ic->key); /* take away this iCode */
+ if (!bitVectIsZero (uses)) /* has other uses */
+ return NULL;
+
+ /* if it has only one defintion */
+ 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)))) {
+ /* than 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;
+ }
+ dic = dic->next;
+ }
+
+
+ /* 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 0
+ if (POINTER_SET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+#endif
+
+ sic = dic;
+
+ /* also make sure the intervenening instructions
+ don't have any thing 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 0
+ if (POINTER_SET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
+ return NULL;
+
+ if (POINTER_GET (dic) &&
+ !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
+ return NULL;
+#endif
+ /* if address of & the result is remat the 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 0
+ if ((dic->op == '%' || dic->op == '/' || dic->op == '*') &&
+ getSize (operandType (op)) >= 3)
+ return NULL;
+#endif
+
+ /* 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;
+// }
+ }
+
+ 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 isCommutativeOp2(unsigned int op)
+{
+ if (op == '+' || op == '*' || op == EQ_OP ||
+ op == '^' || op == '|' || op == BITWISEAND)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandUsesAcc2 - determines whether the code generated for this */
+/* operand will have to use the accumulator */
+/*-----------------------------------------------------------------*/
+bool operandUsesAcc2(operand *op)
+{
+ 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 (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 0
+ 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;
+ #endif
+
+ /* 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 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 0
+ if (POINTER_SET (uic) &&
+ getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
+ return;
+#endif
+
+ /* if the usage is not is 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) &&
+ (uic->op != GETHBIT))
+ return;
+
+#if 0
+ /* if used in ^ operation then make sure right is not a
+ literal (WIML: Why is this?) */
+ if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic)))
+ 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;
+#endif
+
+ /* 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 0
+ /* if the other operand uses the accumulator then we cannot */
+ if ( (IC_LEFT(uic)->key == IC_RESULT(ic)->key &&
+ operandUsesAcc2(IC_RIGHT(uic))) ||
+ (IC_RIGHT(uic)->key == IC_RESULT(ic)->key &&
+ operandUsesAcc2(IC_LEFT(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 (!(isCommutativeOp2(ic->op) || ic->op == '-') &&
+ IC_LEFT (uic)->key != IC_RESULT (ic)->key)
+ return;
+#endif
+
+#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:
+
+ if ((POINTER_GET(uic))
+ || (ic->op == ADDRESS_OF && uic->op == '+' && IS_OP_LITERAL (IC_RIGHT (uic))))
+ {
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_HX;
+ return;
+ }
+
+ OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_XA;
+}
+
+/*-----------------------------------------------------------------*/
+/* packForPush - hueristics to reduce iCode for pushing */
+/*-----------------------------------------------------------------*/
+static void
+packForPush (iCode * ic, eBBlock ** ebpp, int blockno)
+{
+ iCode *dic, *lic;
+ bitVect *dbv;
+ struct eBBlock * ebp=ebpp[blockno];
+
+ 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;
+
+ /* 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))) {
+ /* 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 ;
+ }
+ /* 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);
+ }
+
+ /* we 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];
+
+ while (1)
+ {
+
+ 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);
+ }
+
+ if (!change)
+ break;
+ }
+
+ for (ic = ebp->sch; ic; ic = ic->next)
+ {
+ /* 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) &&
+ bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1)
+ {
+
+ 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) {
+ sym_link *to_type = operandType(IC_LEFT(ic));
+ sym_link *from_type = operandType(IC_RIGHT(ic));
+ if (IS_GENPTR(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 rematerizable
+ 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))
+ 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 0
+ /* if we are using a symbol on the stack
+ then we should say hc08_ptrRegReq */
+ if (ic->op == IFX && IS_SYMOP (IC_COND (ic)))
+ hc08_ptrRegReq += ((OP_SYMBOL (IC_COND (ic))->onStack ||
+ OP_SYMBOL (IC_COND (ic))->iaccess) ? 1 : 0);
+ else if (ic->op == JUMPTABLE && IS_SYMOP (IC_JTCOND (ic)))
+ hc08_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack ||
+ OP_SYMBOL (IC_JTCOND (ic))->iaccess) ? 1 : 0);
+ else
+ {
+ if (IS_SYMOP (IC_LEFT (ic)))
+ hc08_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack ||
+ OP_SYMBOL (IC_LEFT (ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP (IC_RIGHT (ic)))
+ hc08_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack ||
+ OP_SYMBOL (IC_RIGHT (ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP (IC_RESULT (ic)))
+ hc08_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack ||
+ OP_SYMBOL (IC_RESULT (ic))->iaccess) ? 1 : 0);
+ }
+#endif
+ }
+
+ /* 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;
+ }
+
+ /* reduce for support function calls */
+ if (ic->supportRtn || ic->op == '+' || ic->op == '-')
+ packRegsForSupport (ic, ebp);
+
+ #if 0
+ /* 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) {
+ 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) &&
+ /* !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 cast for intergral promotion then
+ check if 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 packit */
+ 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;
+ }
+ }
+ }
+ }
+ #endif
+
+ /* pack for PUSH
+ iTempNN := (some variable in farspace) V1
+ push iTempNN ;
+ -------------
+ push V1
+ */
+ if (ic->op == IPUSH)
+ {
+ packForPush (ic, ebpp, blockno);
+ }
+
+
+ #if 0
+ /* 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 defintion 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 == '='
+ || ic->op == GETHBIT
+ || ic->op == LEFT_OP || ic->op == RIGHT_OP || ic->op == CALL
+ || (ic->op == ADDRESS_OF && isOperandOnStack (IC_LEFT (ic)))
+ ) &&
+ IS_ITEMP (IC_RESULT (ic)) &&
+ getSize (operandType (IC_RESULT (ic))) <= 2)
+
+ packRegsForAccUse (ic);
+ #endif
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignRegisters - assigns registers to each live range as need */
+/*-----------------------------------------------------------------*/
+void
+hc08_assignRegisters (eBBlock ** ebbs, int count)
+{
+ iCode *ic;
+ int i;
+
+ setToNull ((void *) &_G.funcrUsed);
+ setToNull ((void *) &_G.regAssigned);
+ setToNull ((void *) &_G.totRegAssigned);
+ hc08_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
+ hc08_nRegs = 5;
+ hc08_reg_a = hc08_regWithIdx(A_IDX);
+ hc08_reg_x = hc08_regWithIdx(X_IDX);
+ hc08_reg_h = hc08_regWithIdx(H_IDX);
+ hc08_reg_hx = hc08_regWithIdx(HX_IDX);
+ hc08_reg_xa = hc08_regWithIdx(XA_IDX);
+
+ /* change assignments this will remove some
+ live ranges reducing some register pressure */
+ for (i = 0; i < count; i++)
+ packRegisters (ebbs, i);
+
+ if (options.dump_pack)
+ dumpEbbsToFileExt (DUMP_PACK, ebbs, count);
+
+ /* 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();
+
+ /* 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 ();
+ }
+
+ if (options.dump_rassgn)
+ {
+ dumpEbbsToFileExt (DUMP_RASSGN, ebbs, count);
+ dumpLiveRanges (DUMP_LRANGE, liveRanges);
+ }
+
+ /* do the overlaysegment stuff SDCCmem.c */
+ doOverlays (ebbs, count);
+
+ /* now get back the chain */
+ ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
+
+ genhc08Code (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;
+}