From 8cd2c0dc8d10158574c765544ae47f2a7ae2a53e Mon Sep 17 00:00:00 2001 From: epetrich Date: Wed, 15 Oct 2003 04:30:41 +0000 Subject: [PATCH] Initial import git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@2939 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- src/hc08/Makefile | 2 + src/hc08/Makefile.bcc | 23 + src/hc08/gen.c | 7644 +++++++++++++++++++++++++++++++++++++++++ src/hc08/gen.h | 96 + src/hc08/hc08.dsp | 120 + src/hc08/hc08a.dsp | 90 + src/hc08/main.c | 392 +++ src/hc08/main.h | 8 + src/hc08/peeph.def | 106 + src/hc08/ralloc.c | 3004 ++++++++++++++++ src/hc08/ralloc.h | 73 + 11 files changed, 11558 insertions(+) create mode 100644 src/hc08/Makefile create mode 100644 src/hc08/Makefile.bcc create mode 100644 src/hc08/gen.c create mode 100644 src/hc08/gen.h create mode 100644 src/hc08/hc08.dsp create mode 100644 src/hc08/hc08a.dsp create mode 100644 src/hc08/main.c create mode 100644 src/hc08/main.h create mode 100644 src/hc08/peeph.def create mode 100644 src/hc08/ralloc.c create mode 100644 src/hc08/ralloc.h diff --git a/src/hc08/Makefile b/src/hc08/Makefile new file mode 100644 index 00000000..3b856364 --- /dev/null +++ b/src/hc08/Makefile @@ -0,0 +1,2 @@ +# Make all in this directory +include ../port.mk diff --git a/src/hc08/Makefile.bcc b/src/hc08/Makefile.bcc new file mode 100644 index 00000000..8370b9f0 --- /dev/null +++ b/src/hc08/Makefile.bcc @@ -0,0 +1,23 @@ +# Makefile for Borlad C++ + +PRJDIR = ../.. + +OBJ = gen.obj ralloc.obj main.obj +LIB = port.lib + +!include $(PRJDIR)/Bcc.inc +CFLAGS = $(CFLAGS) -I.. -I$(PRJDIR) + +all: $(LIB) + +main.obj: main.c peeph.rul + +$(LIB): $(OBJ) + if exist $(LIB) del $(LIB) + tlib $@ @&&! ++$(**: = &^ ++) +! + +.def.rul: + gawk -f ../SDCCpeeph.awk $< > $@ diff --git a/src/hc08/gen.c b/src/hc08/gen.c new file mode 100644 index 00000000..29637fae --- /dev/null +++ b/src/hc08/gen.c @@ -0,0 +1,7644 @@ +/*------------------------------------------------------------------------- + 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 +#include +#include +#include +#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;otheridxaop + && 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 (loffsetrIdx; + 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; loffsetsize; 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; offsetisFree) + { + 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; offsetnext) + 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 (11) + 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 + */ + 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=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=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;ia: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= 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= 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<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; +} diff --git a/src/hc08/gen.h b/src/hc08/gen.h new file mode 100644 index 00000000..fd9ae77a --- /dev/null +++ b/src/hc08/gen.h @@ -0,0 +1,96 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGEN51_H +#define SDCCGEN51_H + +enum + { + AOP_LIT = 1, + AOP_REG, AOP_DIR, + AOP_STK, AOP_IMMD, AOP_STR, + AOP_CRY, + AOP_EXT, AOP_SOF, + }; + +enum + { + ACCUSE_XA = 1, + ACCUSE_HX + }; + +/* type asmop : a homogenised type for + all the different spaces an operand can be + in */ +typedef struct asmop + { + + short type; + /* can have values + AOP_LIT - operand is a literal value + AOP_REG - is in registers + AOP_DIR - operand using direct addressing mode + AOP_STK - should be pushed on stack this + can happen only for the result + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + AOP_STR - array of strings + AOP_SOF - operand at an offset on the stack + AOP_EXT - operand using extended addressing mode + */ + short coff; /* current offset */ + short size; /* total size */ + short psize; /* pointer size */ + operand *op; /* originating operand */ + unsigned code:1; /* is in Code space */ + unsigned paged:1; /* in paged memory */ + unsigned freed:1; /* already freed */ + unsigned isaddr:1; /* is an address to actual operand */ + unsigned stacked:1; /* partial results stored on stack */ + struct asmop *stk_aop[4]; /* asmops for the results on the stack */ + union + { + value *aop_lit; /* if literal */ + regs *aop_reg[4]; /* array of registers */ + char *aop_dir; /* if direct */ + regs *aop_ptr; /* either -> to r0 or r1 */ + struct { + int from_cast_remat; /* cast remat created this : immd2 field used for highest order*/ + char *aop_immd1; /* if immediate others are implied */ + char *aop_immd2; /* cast remat will generate this */ + } aop_immd; + int aop_stk; /* stack offset when AOP_STK */ + char *aop_str[4]; /* just a string array containing the location */ + } + aopu; + } +asmop; + +void genhc08Code (iCode *); + +//extern char *fReturn8051[]; +extern unsigned fReturnSizeHC08; +//extern char **fReturn; + +#endif diff --git a/src/hc08/hc08.dsp b/src/hc08/hc08.dsp new file mode 100644 index 00000000..11648f1a --- /dev/null +++ b/src/hc08/hc08.dsp @@ -0,0 +1,120 @@ +# Microsoft Developer Studio Project File - Name="hc08" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=hc08 - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "hc08.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "hc08.mak" CFG="hc08 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "hc08 - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "hc08 - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "hc08 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /Zm500 /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /Zm1000 /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Debug\port.lib" +# ADD LIB32 /nologo /out:"Debug\port.lib" + +!ELSEIF "$(CFG)" == "hc08 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /ML /W3 /GX /O2 /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /Zm500 /c +# ADD CPP /nologo /ML /W3 /GX /O2 /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /Zm1000 /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Release\port.lib" +# ADD LIB32 /nologo /out:"Release\port.lib" + +!ENDIF + +# Begin Target + +# Name "hc08 - Win32 Debug" +# Name "hc08 - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gen.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\ralloc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gen.h +# End Source File +# Begin Source File + +SOURCE=.\main.h +# End Source File +# Begin Source File + +SOURCE=.\ralloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\sdcc_vc.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/hc08/hc08a.dsp b/src/hc08/hc08a.dsp new file mode 100644 index 00000000..cf67ead9 --- /dev/null +++ b/src/hc08/hc08a.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="hc08a" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Generic Project" 0x010a + +CFG=hc08a - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "hc08a.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "hc08a.mak" CFG="hc08a - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "hc08a - Win32 Debug" (based on "Win32 (x86) Generic Project") +!MESSAGE "hc08a - Win32 Release" (based on "Win32 (x86) Generic Project") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +MTL=midl.exe + +!IF "$(CFG)" == "hc08a - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "hc08a - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "hc08a - Win32 Debug" +# Name "hc08a - Win32 Release" +# Begin Source File + +SOURCE=.\peeph.def + +!IF "$(CFG)" == "hc08a - Win32 Debug" + +# Begin Custom Build +InputPath=.\peeph.def + +"peeph.rul" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + gawk -f ../SDCCpeeph.awk $(InputPath) >peeph.rul + +# End Custom Build + +!ELSEIF "$(CFG)" == "hc08a - Win32 Release" + +# Begin Custom Build +InputPath=.\peeph.def + +"peeph.rul" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + gawk -f ../SDCCpeeph.awk $(InputPath) >peeph.rul + +# End Custom Build + +!ENDIF + +# End Source File +# End Target +# End Project diff --git a/src/hc08/main.c b/src/hc08/main.c new file mode 100644 index 00000000..600e768d --- /dev/null +++ b/src/hc08/main.c @@ -0,0 +1,392 @@ +/** @file main.c + hc08 specific general functions. + + Note that mlh prepended _hc08_ on the static functions. Makes + it easier to set a breakpoint using the debugger. +*/ +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "gen.h" +#include "../SDCCutil.h" + +void copyFile(FILE *dest, FILE *src); +extern char * iComments2; + +static char _defaultRules[] = +{ +#include "peeph.rul" +}; + +/* list of key words used by msc51 */ +static char *_hc08_keywords[] = +{ + "at", + //"bit", + "code", + "critical", + "data", + "far", + //"idata", + "interrupt", + "near", + //"pdata", + "reentrant", + //"sfr", + //"sbit", + //"using", + "xdata", + "_data", + "_code", + "_generic", + "_near", + "_xdata", + //"_pdata", + //"_idata", + "_naked", + "_overlay", + NULL +}; + + +void hc08_assignRegisters (eBBlock ** ebbs, int count); + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void +_hc08_init (void) +{ + asm_addTree (&asm_asxxxx_mapping); +} + +static void +_hc08_reset_regparm () +{ + regParmFlg = 0; +} + +static int +_hc08_regparm (sym_link * l) +{ + int size = getSize(l); + + /* If they fit completely, the first two bytes of parameters can go */ + /* into A and X, otherwise, they go on the stack. Examples: */ + /* foo(char p1) A <- p1 */ + /* foo(char p1, char p2) A <- p1, X <- p2 */ + /* foo(char p1, char p2, char p3) A <- p1, X <- p2, stack <- p3 */ + /* foo(int p1) XA <- p1 */ + /* foo(long p1) stack <- p1 */ + /* foo(char p1, int p2) A <- p1, stack <- p2 */ + /* foo(int p1, char p2) XA <- p1, stack <- p2 */ + + if (regParmFlg>=2) + return 0; + + if ((regParmFlg+size)>2) + { + regParmFlg = 2; + return 0; + } + + regParmFlg += size; + return 1+regParmFlg-size; +} + +static bool +_hc08_parseOptions (int *pargc, char **argv, int *i) +{ + return FALSE; +} + +static void +_hc08_finaliseOptions (void) +{ + if (options.noXinitOpt) { + port->genXINIT=0; + } + + if (options.model == MODEL_LARGE) { + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + } + else + { + port->mem.default_local_map = data; + port->mem.default_globl_map = data; + } + +} + +static void +_hc08_setDefaultOptions (void) +{ + options.code_loc = 0x8000; + options.data_loc = 0x80; + options.xdata_loc = 0x100; + options.stack_loc = 0x7fff; + options.out_fmt = 1; /* use motorola S19 output */ + + options.ommitFramePtr = 1; /* no frame pointer (we use SP */ + /* offsets instead) */ + +} + +static const char * +_hc08_getRegName (struct regs *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +static void +_hc08_genAssemblerPreamble (FILE * of) +{ + int i; + symbol *mainExists=newSymbol("main", 0); + mainExists->block=0; + + fprintf (of, "\t.area %s\n",port->mem.code_name); + fprintf (of, "\t.area %s\n",port->mem.static_name); + fprintf (of, "\t.area %s\n",port->mem.post_static_name); + fprintf (of, "\t.area %s\n",port->mem.xinit_name); + fprintf (of, "\t.area %s\n",port->mem.data_name); + fprintf (of, "\t.area %s\n",port->mem.overlay_name); + fprintf (of, "\t.area %s\n",port->mem.bit_name); + fprintf (of, "\t.area %s\n",port->mem.xdata_name); + fprintf (of, "\t.area %s\n",port->mem.xidata_name); + + if ((mainExists=findSymWithLevel(SymbolTab, mainExists))) + { + // generate interrupt vector table + fprintf (of, "\t.area\tCODEIVT (ABS)\n"); + fprintf (of, "\t.org\t0x%4x\n", (0xfffe - (maxInterrupts * 2))); + + for (i=maxInterrupts;i>0;i--) + { + if (interrupts[i]) + fprintf (of, "\t.dw\t%s\n", interrupts[i]->rname); + else + fprintf (of, "\t.dw\t0\n"); + } + fprintf (of, "\t.dw\t%s", "__sdcc_gs_init_startup\n\n"); + + fprintf (of, "\t.area GSINIT\n"); + fprintf (of, "__sdcc_gs_init_startup:\n"); + if (options.stack_loc) + { + fprintf (of, "\tldhx\t#0x%4x\n", options.stack_loc+1); + fprintf (of, "\ttxs\n"); + } + else + fprintf (of, "\trsp\n"); + fprintf (of, "\tjsr\t__sdcc_external_startup\n"); + fprintf (of, "\tbeq\t__sdcc_init_data\n"); + fprintf (of, "\tjmp\t__sdcc_program_startup\n"); + fprintf (of, "__sdcc_init_data:\n"); + + fprintf (of, "; _hc08_genXINIT() start\n"); + fprintf (of, " ldhx #0\n"); + fprintf (of, "00001$:\n"); + fprintf (of, " cphx #l_XINIT\n"); + fprintf (of, " beq 00002$\n"); + fprintf (of, " lda s_XINIT,x\n"); + fprintf (of, " sta s_XISEG,x\n"); + fprintf (of, " aix #1\n"); + fprintf (of, " bra 00001$\n"); + fprintf (of, "00002$:\n"); + fprintf (of, "; _hc08_genXINIT() end\n"); + + fprintf (of, "\t.area GSFINAL\n"); + fprintf (of, "\tjmp\t__sdcc_program_startup\n\n"); + + fprintf (of, "\t.area CSEG\n"); + fprintf (of, "__sdcc_program_startup:\n"); + fprintf (of, "\tjsr\t_main\n"); + fprintf (of, "\tbra\t.\n"); + + } +} + +static void +_hc08_genExtraAreas (FILE * asmFile, bool mainExists) +{ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, xdata->oFile); +} + + +/* Generate interrupt vector table. */ +static int +_hc08_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts) +{ + int i; + + fprintf (of, "\t.area\tCODEIVT (ABS)\n"); + fprintf (of, "\t.org\t0x%4x\n", + (0xfffe - (maxInterrupts * 2))); + + for (i=maxInterrupts;i>0;i--) + { + if (interrupts[i]) + fprintf (of, "\t.dw\t%s\n", interrupts[i]->rname); + else + fprintf (of, "\t.dw\t0\n"); + } + fprintf (of, "\t.dw\t%s", "__sdcc_gs_init_startup\n"); + + return TRUE; +} + +/* Generate code to copy XINIT to XISEG */ +static void _hc08_genXINIT (FILE * of) { + fprintf (of, "; _hc08_genXINIT() start\n"); + fprintf (of, "; _hc08_genXINIT() end\n"); +} + + +/* Do CSE estimation */ +static bool cseCostEstimation (iCode *ic, iCode *pdic) +{ + operand *result = IC_RESULT(ic); + sym_link *result_type = operandType(result); + + return 0; /* disable CSE */ + + /* if it is a pointer then return ok for now */ + if (IC_RESULT(ic) && IS_PTR(result_type)) return 1; + + if (ic->op == ADDRESS_OF) + return 0; + + /* if bitwise | add & subtract then no since hc08 is pretty good at it + so we will cse only if they are local (i.e. both ic & pdic belong to + the same basic block */ + if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') { + /* then if they are the same Basic block then ok */ + if (ic->eBBlockNum == pdic->eBBlockNum) return 1; + else return 0; + } + + /* for others it is cheaper to do the cse */ + return 1; +} + + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +static const char *_linkCmd[] = +{ + "link-hc08", "-nf", "\"$1\"", NULL +}; + +/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */ +static const char *_asmCmd[] = +{ + "as-hc08", "$l", "$3", "\"$1.asm\"", NULL +}; + +/* Globals */ +PORT hc08_port = +{ + TARGET_ID_HC08, + "hc08", + "HC08", /* Target name */ + NULL, /* Processor name */ + { + glue, + FALSE, /* Emit glue around main */ + MODEL_SMALL | MODEL_LARGE, + MODEL_LARGE + }, + { + _asmCmd, + NULL, + "-plosgffc", /* Options with debug */ + "-plosgff", /* Options without debug */ + 0, + ".asm", + NULL /* no do_assemble function */ + }, + { + _linkCmd, + NULL, + NULL, + ".rel" + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 2, 2, 2, 1, 4, 4 + }, + { + "XSEG", + "STACK", + "CSEG", + "DSEG", + NULL, /* "ISEG" */ + "XSEG", + "BSEG", + "RSEG", + "GSINIT", + "OSEG (OVR)", + "GSFINAL", + "HOME", + "XISEG", // initialized xdata + "XINIT", // a code copy of xiseg + NULL, + NULL, + 1 + }, + { _hc08_genExtraAreas, + NULL }, + { + -1, 0, 4, 2, 0, 0 + }, + /* hc08 has an 8 bit mul */ + { + 1, -1 + }, + "_", + _hc08_init, + _hc08_parseOptions, + NULL, + _hc08_finaliseOptions, + _hc08_setDefaultOptions, + hc08_assignRegisters, + _hc08_getRegName, + _hc08_keywords, + _hc08_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _hc08_genIVT, + _hc08_genXINIT, + _hc08_reset_regparm, + _hc08_regparm, + NULL, /* process_pragma */ + NULL, /* getMangledFunctionName */ + NULL, /* hasNativeMulFor */ + TRUE, /* use_dw_for_init */ + FALSE, /* little endian */ + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + cseCostEstimation, + NULL, /* no builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + PORT_MAGIC +}; diff --git a/src/hc08/main.h b/src/hc08/main.h new file mode 100644 index 00000000..65552254 --- /dev/null +++ b/src/hc08/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions (char **argv, int *pargc); +void x_setDefaultOptions (void); +void x_finaliseOptions (void); + +#endif diff --git a/src/hc08/peeph.def b/src/hc08/peeph.def new file mode 100644 index 00000000..6000aa6c --- /dev/null +++ b/src/hc08/peeph.def @@ -0,0 +1,106 @@ +replace { + pula + psha + lda %1 +} by { + ; Peephole 1a - removed redundant pula/psha + lda %1 +} + +replace { + pula + psha + lda %1,s +} by { + ; Peephole 1b - removed redundant pula/psha + lda %1,s +} + +replace { + pula + psha + clra +} by { + ; Peephole 1c - removed redundant pula/psha + clra +} + + +replace { + bcs %1 + jmp %5 +%1: +} by { + ; Peephole 2a - eliminated jmp + bcc %5 +%1: +} if labelInRange + +replace { + bcc %1 + jmp %5 +%1: +} by { + ; Peephole 2b - eliminated jmp + bcs %5 +%1: +} if labelInRange + +replace { + beq %1 + jmp %5 +%1: +} by { + ; Peephole 2c - eliminated jmp + bne %5 +%1: +} if labelInRange + +replace { + bne %1 + jmp %5 +%1: +} by { + ; Peephole 2d - eliminated jmp + beq %5 +%1: +} if labelInRange + +replace { + jmp %5 +} by { + ; Peephole 3 - shortened jmp to bra + bra %5 +} if labelInRange + +replace { + lda %1 + tsta +} by { + ; Peephole 4a - eliminated redundant tsta + lda %1 +} + +replace { + lda %1,s + tsta +} by { + ; Peephole 4b - eliminated redundant tsta + lda %1,s +} + +replace { + ldx %1 + tstx +} by { + ; Peephole 4c - eliminated redundant tstx + ldx %1 +} + +replace { + ldx %1,s + tstx +} by { + ; Peephole 4d - eliminated redundant tstx + ldx %1,s +} diff --git a/src/hc08/ralloc.c b/src/hc08/ralloc.c new file mode 100644 index 00000000..cbd8b828 --- /dev/null +++ b/src/hc08/ralloc.c @@ -0,0 +1,3004 @@ +/*------------------------------------------------------------------------ + + 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; regriu &= ~(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; iseq >= 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; +} diff --git a/src/hc08/ralloc.h b/src/hc08/ralloc.h new file mode 100644 index 00000000..878c9aac --- /dev/null +++ b/src/hc08/ralloc.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +enum + { + A_IDX, + H_IDX, + X_IDX, + HX_IDX, + XA_IDX, + CND_IDX + }; + + +#define REG_PTR 0x01 +#define REG_GPR 0x02 +#define REG_CND 0x04 +/* definition for the registers */ +typedef struct regs + { + short type; /* can have value + REG_GPR, REG_PTR or REG_CND */ + short rIdx; /* index into register table */ + short otype; + char *name; /* name */ + char *dname; /* name when direct access needed */ + char *base; /* base address */ + short mask; /* bitmask for pair allocation */ + struct asmop *aop; /* last operand */ + int aopofs; /* last operand offset */ + unsigned isFree:1; /* is currently unassigned */ + } +regs; +extern regs regshc08[]; +extern regs *hc08_reg_a; +extern regs *hc08_reg_x; +extern regs *hc08_reg_h; +extern regs *hc08_reg_hx; +extern regs *hc08_reg_xa; + +regs *hc08_regWithIdx (int); +void hc08_useReg (regs * reg); +void hc08_freeReg (regs * reg); +void hc08_dirtyReg (regs * reg, bool freereg); +bitVect *hc08_rUmaskForOp (operand * op); + +#endif -- 2.30.2