--- /dev/null
+/*-------------------------------------------------------------------------
+ gen.c - source file for code generation for 8051
+
+ 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!
+
+ Notes:
+ 000123 mlh Moved aopLiteral to SDCCglue.c to help the split
+ Made everything static
+-------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "SDCCglobl.h"
+
+#ifdef HAVE_SYS_ISA_DEFS_H
+#include <sys/isa_defs.h>
+#else
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else
+#ifndef __BORLANDC__
+#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN"
+#warning "If you running sdcc on an INTEL 80x86 Platform you are okay"
+#endif
+#endif
+#endif
+
+#include "common.h"
+#include "SDCCpeeph.h"
+#include "ralloc.h"
+#include "gen.h"
+
+char *aopLiteral (value *val, int offset);
+extern int allocInfo;
+
+/* this is the down and dirty file with all kinds of
+ kludgy & hacky stuff. This is what it is all about
+ CODE GENERATION for a specific MCU . some of the
+ routines may be reusable, will have to see */
+
+static char *zero = "#0x00";
+static char *one = "#0x01";
+static char *spname ;
+
+#define D(x) x
+
+unsigned fReturnSize_390 = 5; /* shared with ralloc.c */
+static char *fReturn[] = {"dpl","dph","dpx", "b","a" };
+static char *accUse[] = {"a","b"};
+
+static short rbank = -1;
+
+static struct {
+ short r0Pushed;
+ short r1Pushed;
+ short accInUse;
+ short inLine;
+ short debugLine;
+ short nRegsSaved;
+ set *sendSet;
+} _G;
+
+extern int ds390_ptrRegReq ;
+extern int ds390_nRegs;
+extern FILE *codeOutFile;
+static void saverbank (int, iCode *,bool);
+#define RESULTONSTACK(x) \
+ (IC_RESULT(x) && IC_RESULT(x)->aop && \
+ IC_RESULT(x)->aop->type == AOP_STK )
+
+/* #define MOVA(x) if (strcmp(x,"a") && strcmp(x,"acc")) emitcode("mov","a,%s",x); */
+#define MOVA(x) { char *_mova_tmp = strdup(x); \
+ if (strcmp(_mova_tmp,"a") && strcmp(_mova_tmp,"acc")) \
+ { \
+ emitcode("mov","a,%s",_mova_tmp); \
+ } \
+ free(_mova_tmp); \
+ }
+#define CLRC emitcode("clr","c");
+
+static lineNode *lineHead = NULL;
+static lineNode *lineCurr = NULL;
+
+static unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
+0xE0, 0xC0, 0x80, 0x00};
+static unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
+0x07, 0x03, 0x01, 0x00};
+
+#define LSB 0
+#define MSB16 1
+#define MSB24 2
+#define MSB32 3
+
+/*-----------------------------------------------------------------*/
+/* emitcode - writes the code into a file : for now it is simple */
+/*-----------------------------------------------------------------*/
+static void emitcode (char *inst,char *fmt, ...)
+{
+ va_list ap;
+ char lb[MAX_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;
+ va_end(ap);
+}
+
+/*-----------------------------------------------------------------*/
+/* getFreePtr - returns r0 or r1 whichever is free or can be pushed*/
+/*-----------------------------------------------------------------*/
+static regs *getFreePtr (iCode *ic, asmop **aopp, bool result)
+{
+ bool r0iu = FALSE , r1iu = FALSE;
+ bool r0ou = FALSE , r1ou = FALSE;
+
+ /* the logic: if r0 & r1 used in the instruction
+ then we are in trouble otherwise */
+
+ /* first check if r0 & r1 are used by this
+ instruction, in which case we are in trouble */
+ if ((r0iu = bitVectBitValue(ic->rUsed,R0_IDX)) &&
+ (r1iu = bitVectBitValue(ic->rUsed,R1_IDX)))
+ {
+ goto endOfWorld;
+ }
+
+ r0ou = bitVectBitValue(ic->rMask,R0_IDX);
+ r1ou = bitVectBitValue(ic->rMask,R1_IDX);
+
+ /* if no usage of r0 then return it */
+ if (!r0iu && !r0ou) {
+ ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX);
+ (*aopp)->type = AOP_R0;
+
+ return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R0_IDX);
+ }
+
+ /* if no usage of r1 then return it */
+ if (!r1iu && !r1ou) {
+ ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX);
+ (*aopp)->type = AOP_R1;
+
+ return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R1_IDX);
+ }
+
+ /* now we know they both have usage */
+ /* if r0 not used in this instruction */
+ if (!r0iu) {
+ /* push it if not already pushed */
+ if (!_G.r0Pushed) {
+ emitcode ("push","%s",
+ ds390_regWithIdx(R0_IDX)->dname);
+ _G.r0Pushed++ ;
+ }
+
+ ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX);
+ (*aopp)->type = AOP_R0;
+
+ return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R0_IDX);
+ }
+
+ /* if r1 not used then */
+
+ if (!r1iu) {
+ /* push it if not already pushed */
+ if (!_G.r1Pushed) {
+ emitcode ("push","%s",
+ ds390_regWithIdx(R1_IDX)->dname);
+ _G.r1Pushed++ ;
+ }
+
+ ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX);
+ (*aopp)->type = AOP_R1;
+ return ds390_regWithIdx(R1_IDX);
+ }
+
+endOfWorld :
+ /* I said end of world but not quite end of world yet */
+ /* if this is a result then we can push it on the stack*/
+ if (result) {
+ (*aopp)->type = AOP_STK;
+ return NULL;
+ }
+
+ piCode(ic,stdout);
+ /* other wise this is true end of the world */
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "getFreePtr should never reach here");
+ exit(0);
+}
+
+/*-----------------------------------------------------------------*/
+/* newAsmop - creates a new asmOp */
+/*-----------------------------------------------------------------*/
+static asmop *newAsmop (short type)
+{
+ asmop *aop;
+
+ ALLOC(aop,sizeof(asmop));
+ aop->type = type;
+ return aop;
+}
+
+static void genSetDPTR(int n)
+{
+ if (!n)
+ {
+ emitcode(";", "Select standard DPTR");
+ emitcode("mov", "dps, #0x00");
+ }
+ else
+ {
+ emitcode(";", "Select alternate DPTR");
+ emitcode("mov", "dps, #0x01");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* pointerCode - returns the code for a pointer type */
+/*-----------------------------------------------------------------*/
+static int pointerCode (link *etype)
+{
+
+ return PTR_TYPE(SPEC_OCLS(etype));
+
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForSym - for a true symbol */
+/*-----------------------------------------------------------------*/
+static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool useDP2)
+{
+ asmop *aop;
+ memmap *space= SPEC_OCLS(sym->etype);
+
+ /* if already has one */
+ if (sym->aop)
+ return sym->aop;
+
+ /* assign depending on the storage class */
+ /* if it is on the stack or indirectly addressable */
+ /* space we need to assign either r0 or r1 to it */
+ if ((sym->onStack && !options.stack10bit) || sym->iaccess) {
+ sym->aop = aop = newAsmop(0);
+ aop->aopu.aop_ptr = getFreePtr(ic,&aop,result);
+ aop->size = getSize(sym->type);
+
+ /* now assign the address of the variable to
+ the pointer register */
+ if (aop->type != AOP_STK) {
+
+ if (sym->onStack) {
+ if ( _G.accInUse )
+ emitcode("push","acc");
+
+ emitcode("mov","a,_bp");
+ emitcode("add","a,#0x%02x",
+ ((sym->stack < 0) ?
+ ((char)(sym->stack - _G.nRegsSaved )) :
+ ((char)sym->stack)) & 0xff);
+ emitcode("mov","%s,a",
+ aop->aopu.aop_ptr->name);
+
+ if ( _G.accInUse )
+ emitcode("pop","acc");
+ } else
+ emitcode("mov","%s,#%s",
+ aop->aopu.aop_ptr->name,
+ sym->rname);
+ aop->paged = space->paged;
+ } else
+ aop->aopu.aop_stk = sym->stack;
+ return aop;
+ }
+
+ if (sym->onStack && options.stack10bit)
+ {
+ /* It's on the 10 bit stack, which is located in
+ * far data space.
+ */
+
+ if ( _G.accInUse )
+ emitcode("push","acc");
+
+ emitcode("mov","a,_bp");
+ emitcode("add","a,#0x%02x",
+ ((sym->stack < 0) ?
+ ((char)(sym->stack - _G.nRegsSaved )) :
+ ((char)sym->stack)) & 0xff);
+
+ if (useDP2)
+ {
+ genSetDPTR(1);
+ emitcode ("mov","dpx1,#0x40");
+ emitcode ("mov","dph1,#0x00");
+ emitcode ("mov","dpl1, a");
+ genSetDPTR(0);
+ }
+ else
+ {
+ emitcode ("mov","dpx,#0x40");
+ emitcode ("mov","dph,#0x00");
+ emitcode ("mov","dpl, a");
+ }
+
+ if ( _G.accInUse )
+ emitcode("pop","acc");
+
+ sym->aop = aop = newAsmop(useDP2 ? AOP_DPTR2 : AOP_DPTR);
+ aop->size = getSize(sym->type);
+ return aop;
+ }
+
+ /* if in bit space */
+ if (IN_BITSPACE(space)) {
+ sym->aop = aop = newAsmop (AOP_CRY);
+ aop->aopu.aop_dir = sym->rname ;
+ aop->size = getSize(sym->type);
+ return aop;
+ }
+ /* if it is in direct space */
+ if (IN_DIRSPACE(space)) {
+ sym->aop = aop = newAsmop (AOP_DIR);
+ aop->aopu.aop_dir = sym->rname ;
+ aop->size = getSize(sym->type);
+ return aop;
+ }
+
+ /* special case for a function */
+ if (IS_FUNC(sym->type)) {
+ sym->aop = aop = newAsmop(AOP_IMMD);
+ ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
+ strcpy(aop->aopu.aop_immd,sym->rname);
+ aop->size = FPTRSIZE;
+ return aop;
+ }
+
+ /* only remaining is far space */
+ /* in which case DPTR gets the address */
+ sym->aop = aop = newAsmop(useDP2 ? AOP_DPTR2 : AOP_DPTR);
+ if (useDP2)
+ {
+ genSetDPTR(1);
+ emitcode ("mov","dptr,#%s", sym->rname);
+ genSetDPTR(0);
+ }
+ else
+ {
+ emitcode ("mov","dptr,#%s", sym->rname);
+ }
+ aop->size = getSize(sym->type);
+
+ /* 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 val = 0;
+
+ for (;;) {
+ if (ic->op == '+')
+ val += operandLitValue(IC_RIGHT(ic));
+ else if (ic->op == '-')
+ val -= operandLitValue(IC_RIGHT(ic));
+ 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);
+
+ ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
+ strcpy(aop->aopu.aop_immd,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)
+ {
+ if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
+ {
+ return FALSE;
+ }
+ return TRUE ;
+ }
+
+ if (aop1->type != AOP_REG ||
+ aop2->type != AOP_REG )
+ return FALSE ;
+
+ if (aop1->size != aop2->size )
+ return FALSE ;
+
+ for (i = 0 ; i < aop1->size ; i++ )
+ if (aop1->aopu.aop_reg[i] !=
+ aop2->aopu.aop_reg[i] )
+ return FALSE ;
+
+ return TRUE ;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopOp - allocates an asmop for an operand : */
+/*-----------------------------------------------------------------*/
+static void aopOp (operand *op, iCode *ic, bool result, bool useDP2)
+{
+ asmop *aop;
+ symbol *sym;
+ int i;
+
+ if (!op)
+ return ;
+
+ /* if this a literal */
+ if (IS_OP_LITERAL(op)) {
+ op->aop = aop = newAsmop(AOP_LIT);
+ aop->aopu.aop_lit = op->operand.valOperand;
+ aop->size = getSize(operandType(op));
+ return;
+ }
+
+ /* if already has a asmop then continue */
+ if (op->aop)
+ return ;
+
+ /* if the underlying symbol has a aop */
+ if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
+ op->aop = OP_SYMBOL(op)->aop;
+ return;
+ }
+
+ /* if this is a true symbol */
+ if (IS_TRUE_SYMOP(op)) {
+ op->aop = aopForSym(ic,OP_SYMBOL(op),result, useDP2);
+ 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);
+
+
+ /* if the type is a conditional */
+ if (sym->regType == REG_CND) {
+ aop = op->aop = sym->aop = newAsmop(AOP_CRY);
+ aop->size = 0;
+ return;
+ }
+
+ /* if it is spilt then two situations
+ a) is rematerialize
+ b) has a spill location */
+ if (sym->isspilt || sym->nRegs == 0) {
+
+ /* rematerialize it NOW */
+ if (sym->remat) {
+ sym->aop = op->aop = aop =
+ aopForRemat (sym);
+ aop->size = getSize(sym->type);
+ return;
+ }
+
+ if (sym->accuse) {
+ int i;
+ aop = op->aop = sym->aop = newAsmop(AOP_ACC);
+ aop->size = getSize(sym->type);
+ for ( i = 0 ; i < 2 ; i++ )
+ aop->aopu.aop_str[i] = accUse[i];
+ return;
+ }
+
+ if (sym->ruonly ) {
+ int i;
+ aop = op->aop = sym->aop = newAsmop(AOP_STR);
+ aop->size = getSize(sym->type);
+ for ( i = 0 ; i < fReturnSize_390 ; i++ )
+ aop->aopu.aop_str[i] = fReturn[i];
+ return;
+ }
+
+ /* else spill location */
+ sym->aop = op->aop = aop =
+ aopForSym(ic,sym->usl.spillLoc,result, useDP2);
+ aop->size = getSize(sym->type);
+ return;
+ }
+
+ /* must be in a register */
+ sym->aop = op->aop = aop = newAsmop(AOP_REG);
+ aop->size = sym->nRegs;
+ for ( i = 0 ; i < sym->nRegs ;i++)
+ aop->aopu.aop_reg[i] = sym->regs[i];
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAsmop - free up the asmop given to an operand */
+/*----------------------------------------------------------------*/
+static void freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop)
+{
+ asmop *aop ;
+
+ if (!op)
+ aop = aaop;
+ else
+ aop = op->aop;
+
+ if (!aop)
+ return ;
+
+ if (aop->freed)
+ goto dealloc;
+
+ aop->freed = 1;
+
+ /* depending on the asmop type only three cases need work AOP_RO
+ , AOP_R1 && AOP_STK */
+ switch (aop->type) {
+ case AOP_R0 :
+ if (_G.r0Pushed ) {
+ if (pop) {
+ emitcode ("pop","ar0");
+ _G.r0Pushed--;
+ }
+ }
+ bitVectUnSetBit(ic->rUsed,R0_IDX);
+ break;
+
+ case AOP_R1 :
+ if (_G.r1Pushed ) {
+ if (pop) {
+ emitcode ("pop","ar1");
+ _G.r1Pushed--;
+ }
+ }
+ bitVectUnSetBit(ic->rUsed,R1_IDX);
+ break;
+
+ case AOP_STK :
+ {
+ int sz = aop->size;
+ int stk = aop->aopu.aop_stk + aop->size;
+ bitVectUnSetBit(ic->rUsed,R0_IDX);
+ bitVectUnSetBit(ic->rUsed,R1_IDX);
+
+ getFreePtr(ic,&aop,FALSE);
+
+ if (options.stack10bit)
+ {
+ /* I'm not sure what to do here yet... */
+ /* #STUB */
+ fprintf(stderr,
+ "*** Warning: probably generating bad code for "
+ "10 bit stack mode.\n");
+ }
+
+ if (stk) {
+ emitcode ("mov","a,_bp");
+ emitcode ("add","a,#0x%02x",((char)stk) & 0xff);
+ emitcode ("mov","%s,a",aop->aopu.aop_ptr->name);
+ } else {
+ emitcode ("mov","%s,_bp",aop->aopu.aop_ptr->name);
+ }
+
+ while (sz--) {
+ emitcode("pop","acc");
+ emitcode("mov","@%s,a",aop->aopu.aop_ptr->name);
+ if (!sz) break;
+ emitcode("dec","%s",aop->aopu.aop_ptr->name);
+ }
+ op->aop = aop;
+ freeAsmop(op,NULL,ic,TRUE);
+ if (_G.r0Pushed) {
+ emitcode("pop","ar0");
+ _G.r0Pushed--;
+ }
+
+ if (_G.r1Pushed) {
+ emitcode("pop","ar1");
+ _G.r1Pushed--;
+ }
+ }
+ }
+
+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;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* aopGet - for fetching value of the aop */
+/*-----------------------------------------------------------------*/
+static char *aopGet (asmop *aop, int offset, bool bit16, bool dname)
+{
+ char *s = buffer ;
+ char *rs;
+
+ /* offset is greater than
+ size then zero */
+ if (offset > (aop->size - 1) &&
+ aop->type != AOP_LIT)
+ return zero;
+
+ /* depending on type */
+ switch (aop->type) {
+
+ case AOP_R0:
+ case AOP_R1:
+ /* if we need to increment it */
+ while (offset > aop->coff) {
+ emitcode ("inc","%s",aop->aopu.aop_ptr->name);
+ aop->coff++;
+ }
+
+ while (offset < aop->coff) {
+ emitcode("dec","%s",aop->aopu.aop_ptr->name);
+ aop->coff--;
+ }
+
+ aop->coff = offset ;
+ if (aop->paged) {
+ emitcode("movx","a,@%s",aop->aopu.aop_ptr->name);
+ return (dname ? "acc" : "a");
+ }
+ sprintf(s,"@%s",aop->aopu.aop_ptr->name);
+ ALLOC_ATOMIC(rs,strlen(s)+1);
+ strcpy(rs,s);
+ return rs;
+
+ case AOP_DPTR:
+ case AOP_DPTR2:
+
+ if (aop->type == AOP_DPTR2)
+ {
+ genSetDPTR(1);
+ emitcode("xch", "a, ap");
+ }
+
+ while (offset > aop->coff) {
+ emitcode ("inc","dptr");
+ aop->coff++;
+ }
+
+ while (offset < aop->coff) {
+ emitcode("lcall","__decdptr");
+ aop->coff--;
+ }
+
+ aop->coff = offset;
+ if (aop->code) {
+ emitcode("clr","a");
+ emitcode("movc","a,@a+dptr");
+ }
+ else {
+ emitcode("movx","a,@dptr");
+ }
+
+ if (aop->type == AOP_DPTR2)
+ {
+ emitcode("xch", "a, ap");
+ genSetDPTR(0);
+ return "ap";
+ }
+
+ return (dname ? "acc" : "a");
+
+
+ case AOP_IMMD:
+ if (bit16)
+ sprintf (s,"#%s",aop->aopu.aop_immd);
+ else
+ if (offset)
+ sprintf(s,"#(%s >> %d)",
+ aop->aopu.aop_immd,
+ offset*8);
+ else
+ sprintf(s,"#%s",
+ aop->aopu.aop_immd);
+ ALLOC_ATOMIC(rs,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);
+ ALLOC_ATOMIC(rs,strlen(s)+1);
+ strcpy(rs,s);
+ return rs;
+
+ case AOP_REG:
+ if (dname)
+ return aop->aopu.aop_reg[offset]->dname;
+ else
+ return aop->aopu.aop_reg[offset]->name;
+
+ case AOP_CRY:
+ emitcode("clr","a");
+ emitcode("mov","c,%s",aop->aopu.aop_dir);
+ emitcode("rlc","a") ;
+ return (dname ? "acc" : "a");
+
+ case AOP_ACC:
+ if (!offset && dname)
+ return "acc";
+ return aop->aopu.aop_str[offset];
+
+ case AOP_LIT:
+ return aopLiteral (aop->aopu.aop_lit,offset);
+
+ case AOP_STR:
+ aop->coff = offset ;
+ if (strcmp(aop->aopu.aop_str[offset],"a") == 0 &&
+ dname)
+ return "acc";
+
+ return aop->aopu.aop_str[offset];
+
+ }
+
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "aopget got unsupported aop->type");
+ exit(0);
+}
+/*-----------------------------------------------------------------*/
+/* aopPut - puts a string for a aop */
+/*-----------------------------------------------------------------*/
+static void aopPut (asmop *aop, char *s, int offset)
+{
+ char *d = buffer ;
+ symbol *lbl ;
+
+ if (aop->size && offset > ( aop->size - 1)) {
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "aopPut got offset > aop->size");
+ exit(0);
+ }
+
+ /* will assign value to value */
+ /* depending on where it is ofcourse */
+ switch (aop->type) {
+ case AOP_DIR:
+ if (offset)
+ sprintf(d,"(%s + %d)",
+ aop->aopu.aop_dir,offset);
+ else
+ sprintf(d,"%s",aop->aopu.aop_dir);
+
+ if (strcmp(d,s))
+ emitcode("mov","%s,%s",d,s);
+
+ break;
+
+ case AOP_REG:
+ if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0 &&
+ strcmp(aop->aopu.aop_reg[offset]->dname,s)!= 0){
+ if (*s == '@' ||
+ strcmp(s,"r0") == 0 ||
+ strcmp(s,"r1") == 0 ||
+ strcmp(s,"r2") == 0 ||
+ strcmp(s,"r3") == 0 ||
+ strcmp(s,"r4") == 0 ||
+ strcmp(s,"r5") == 0 ||
+ strcmp(s,"r6") == 0 ||
+ strcmp(s,"r7") == 0 )
+ emitcode("mov","%s,%s",
+ aop->aopu.aop_reg[offset]->dname,s);
+ else
+ emitcode("mov","%s,%s",
+ aop->aopu.aop_reg[offset]->name,s);
+ }
+ break;
+
+ case AOP_DPTR:
+ case AOP_DPTR2:
+
+ if (aop->type == AOP_DPTR2)
+ {
+ genSetDPTR(1);
+ }
+
+ if (aop->code) {
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "aopPut writting to code space");
+ exit(0);
+ }
+
+ while (offset > aop->coff) {
+ aop->coff++;
+ emitcode ("inc","dptr");
+ }
+
+ while (offset < aop->coff) {
+ aop->coff-- ;
+ emitcode("lcall","__decdptr");
+ }
+
+ aop->coff = offset;
+
+ /* if not in accumulater */
+ MOVA(s);
+
+ emitcode ("movx","@dptr,a");
+
+ if (aop->type == AOP_DPTR2)
+ {
+ genSetDPTR(0);
+ }
+ break;
+
+ case AOP_R0:
+ case AOP_R1:
+ while (offset > aop->coff) {
+ aop->coff++;
+ emitcode("inc","%s",aop->aopu.aop_ptr->name);
+ }
+ while (offset < aop->coff) {
+ aop->coff-- ;
+ emitcode ("dec","%s",aop->aopu.aop_ptr->name);
+ }
+ aop->coff = offset;
+
+ if (aop->paged) {
+ MOVA(s);
+ emitcode("movx","@%s,a",aop->aopu.aop_ptr->name);
+
+ } else
+ if (*s == '@') {
+ MOVA(s);
+ emitcode("mov","@%s,a",aop->aopu.aop_ptr->name);
+ } else
+ if (strcmp(s,"r0") == 0 ||
+ strcmp(s,"r1") == 0 ||
+ strcmp(s,"r2") == 0 ||
+ strcmp(s,"r3") == 0 ||
+ strcmp(s,"r4") == 0 ||
+ strcmp(s,"r5") == 0 ||
+ strcmp(s,"r6") == 0 ||
+ strcmp(s,"r7") == 0 ) {
+ char buffer[10];
+ sprintf(buffer,"a%s",s);
+ emitcode("mov","@%s,%s",
+ aop->aopu.aop_ptr->name,buffer);
+ } else
+ emitcode("mov","@%s,%s",aop->aopu.aop_ptr->name,s);
+
+ break;
+
+ case AOP_STK:
+ if (strcmp(s,"a") == 0)
+ emitcode("push","acc");
+ else
+ emitcode("push","%s",s);
+
+ break;
+
+ case AOP_CRY:
+ /* if bit variable */
+ if (!aop->aopu.aop_dir) {
+ emitcode("clr","a");
+ emitcode("rlc","a");
+ } else {
+ if (s == zero)
+ emitcode("clr","%s",aop->aopu.aop_dir);
+ else
+ if (s == one)
+ emitcode("setb","%s",aop->aopu.aop_dir);
+ else
+ if (!strcmp(s,"c"))
+ emitcode("mov","%s,c",aop->aopu.aop_dir);
+ else {
+ lbl = newiTempLabel(NULL);
+
+ if (strcmp(s,"a")) {
+ MOVA(s);
+ }
+ emitcode("clr","c");
+ emitcode("jz","%05d$",lbl->key+100);
+ emitcode("cpl","c");
+ emitcode("","%05d$:",lbl->key+100);
+ emitcode("mov","%s,c",aop->aopu.aop_dir);
+ }
+ }
+ break;
+
+ case AOP_STR:
+ aop->coff = offset;
+ if (strcmp(aop->aopu.aop_str[offset],s))
+ emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s);
+ break;
+
+ case AOP_ACC:
+ aop->coff = offset;
+ if (!offset && (strcmp(s,"acc") == 0))
+ break;
+
+ if (strcmp(aop->aopu.aop_str[offset],s))
+ emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s);
+ break;
+
+ default :
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "aopPut got unsupported aop->type");
+ exit(0);
+ }
+
+}
+
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* pointToEnd :- points to the last byte of the operand */
+/*-----------------------------------------------------------------*/
+static void pointToEnd (asmop *aop)
+{
+ int count ;
+ if (!aop)
+ return ;
+
+ aop->coff = count = (aop->size - 1);
+ switch (aop->type) {
+ case AOP_R0 :
+ case AOP_R1 :
+ while (count--)
+ emitcode("inc","%s",aop->aopu.aop_ptr->name);
+ break;
+ case AOP_DPTR :
+ while (count--)
+ emitcode("inc","dptr");
+ break;
+ }
+
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* reAdjustPreg - points a register back to where it should */
+/*-----------------------------------------------------------------*/
+static void reAdjustPreg (asmop *aop)
+{
+ int size ;
+
+ aop->coff = 0;
+ if ((size = aop->size) <= 1)
+ return ;
+ size-- ;
+ switch (aop->type) {
+ case AOP_R0 :
+ case AOP_R1 :
+ while (size--)
+ emitcode("dec","%s",aop->aopu.aop_ptr->name);
+ break;
+ case AOP_DPTR :
+ case AOP_DPTR2:
+ if (aop->type == AOP_DPTR2)
+ {
+ genSetDPTR(1);
+ }
+ while (size--)
+ {
+ emitcode("lcall","__decdptr");
+ }
+
+ if (aop->type == AOP_DPTR2)
+ {
+ genSetDPTR(0);
+ }
+ break;
+
+ }
+
+}
+
+#define AOP(op) op->aop
+#define AOP_TYPE(op) AOP(op)->type
+#define AOP_SIZE(op) AOP(op)->size
+#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
+ AOP_TYPE(x) == AOP_R0))
+
+#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \
+ AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
+ AOP(x)->paged))
+
+#define AOP_INPREG(x) (x && (x->type == AOP_REG && \
+ (x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
+ x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
+
+/*-----------------------------------------------------------------*/
+/* genNotFloat - generates not for float operations */
+/*-----------------------------------------------------------------*/
+static void genNotFloat (operand *op, operand *res)
+{
+ int size, offset;
+ char *l;
+ symbol *tlbl ;
+
+ D(emitcode(";", "genNotFloat "););
+
+ /* we will put 127 in the first byte of
+ the result */
+ aopPut(AOP(res),"#127",0);
+ size = AOP_SIZE(op) - 1;
+ offset = 1;
+
+ l = aopGet(op->aop,offset++,FALSE,FALSE);
+ MOVA(l);
+
+ while(size--) {
+ emitcode("orl","a,%s",
+ aopGet(op->aop,
+ offset++,FALSE,FALSE));
+ }
+ tlbl = newiTempLabel(NULL);
+
+ tlbl = newiTempLabel(NULL);
+ aopPut(res->aop,one,1);
+ emitcode("jz","%05d$",(tlbl->key+100));
+ aopPut(res->aop,zero,1);
+ emitcode("","%05d$:",(tlbl->key+100));
+
+ size = res->aop->size - 2;
+ offset = 2;
+ /* put zeros in the rest */
+ while (size--)
+ aopPut(res->aop,zero,offset++);
+}
+
+/*-----------------------------------------------------------------*/
+/* opIsGptr: returns non-zero if the passed operand is */
+/* a generic pointer type. */
+/*-----------------------------------------------------------------*/
+static int opIsGptr(operand *op)
+{
+ link *type = operandType(op);
+
+ if ((AOP_SIZE(op) == GPTRSIZE) && IS_GENPTR(type))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* getDataSize - get the operand data size */
+/*-----------------------------------------------------------------*/
+static int getDataSize(operand *op)
+{
+ int size;
+ size = AOP_SIZE(op);
+ if (size == GPTRSIZE)
+ {
+ link *type = operandType(op);
+ if (IS_GENPTR(type))
+ {
+ /* generic pointer; arithmetic operations
+ * should ignore the high byte (pointer type).
+ */
+ size--;
+ }
+ }
+ return size;
+}
+
+/*-----------------------------------------------------------------*/
+/* outAcc - output Acc */
+/*-----------------------------------------------------------------*/
+static void outAcc(operand *result)
+{
+ int size, offset;
+ size = getDataSize(result);
+ if(size){
+ aopPut(AOP(result),"a",0);
+ size--;
+ offset = 1;
+ /* unsigned or positive */
+ while(size--){
+ aopPut(AOP(result),zero,offset++);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitC - output a bit C */
+/*-----------------------------------------------------------------*/
+static void outBitC(operand *result)
+{
+ /* if the result is bit */
+ if (AOP_TYPE(result) == AOP_CRY)
+ aopPut(AOP(result),"c",0);
+ else {
+ emitcode("clr","a");
+ emitcode("rlc","a");
+ outAcc(result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* toBoolean - emit code for orl a,operator(sizeop) */
+/*-----------------------------------------------------------------*/
+static void toBoolean(operand *oper)
+{
+ int size = AOP_SIZE(oper) - 1;
+ int offset = 1;
+
+ if (AOP_NEEDSACC(oper))
+ {
+ emitcode("push", "b");
+ emitcode("mov", "b, %s", aopGet(AOP(oper),0,FALSE,FALSE));
+ }
+ else
+ {
+ MOVA(aopGet(AOP(oper),0,FALSE,FALSE));
+ }
+ while (size--)
+ {
+ if (AOP_NEEDSACC(oper))
+ {
+ emitcode("orl","b,%s",aopGet(AOP(oper),offset++,FALSE,FALSE));
+ }
+ else
+ {
+ emitcode("orl","a,%s",aopGet(AOP(oper),offset++,FALSE,FALSE));
+}
+ }
+
+ if (AOP_NEEDSACC(oper))
+ {
+ emitcode("mov", "a,b");
+ emitcode("pop", "b");
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genNot - generate code for ! operation */
+/*-----------------------------------------------------------------*/
+static void genNot (iCode *ic)
+{
+ symbol *tlbl;
+ link *optype = operandType(IC_LEFT(ic));
+
+ D(emitcode(";", "genNot "););
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
+ aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
+
+ /* if in bit space then a special case */
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
+ emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir);
+ emitcode("cpl","c");
+ outBitC(IC_RESULT(ic));
+ goto release;
+ }
+
+ /* if type float then do float */
+ if (IS_FLOAT(optype)) {
+ genNotFloat(IC_LEFT(ic),IC_RESULT(ic));
+ goto release;
+ }
+
+ toBoolean(IC_LEFT(ic));
+
+ tlbl = newiTempLabel(NULL);
+ emitcode("cjne","a,#0x01,%05d$",tlbl->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitC(IC_RESULT(ic));
+
+release:
+ /* release the aops */
+ freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genCpl - generate code for complement */
+/*-----------------------------------------------------------------*/
+static void genCpl (iCode *ic)
+{
+ int offset = 0;
+ int size ;
+
+ D(emitcode(";", "genCpl "););
+
+
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
+ aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
+
+ /* if both are in bit space then
+ a special case */
+ if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
+ AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
+
+ emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir);
+ emitcode("cpl","c");
+ emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir);
+ goto release;
+ }
+
+ size = AOP_SIZE(IC_RESULT(ic));
+ while (size--) {
+ char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("cpl","a");
+ aopPut(AOP(IC_RESULT(ic)),"a",offset++);
+ }
+
+
+release:
+ /* release the aops */
+ freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void genUminusFloat(operand *op,operand *result)
+{
+ int size ,offset =0 ;
+ char *l;
+ /* for this we just need to flip the
+ first it then copy the rest in place */
+ size = AOP_SIZE(op) - 1;
+ l = aopGet(AOP(op),3,FALSE,FALSE);
+
+ D(emitcode(";", "genUminusFloat"););
+
+ MOVA(l);
+
+ emitcode("cpl","acc.7");
+ aopPut(AOP(result),"a",3);
+
+ while(size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(op),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminus - unary minus code generation */
+/*-----------------------------------------------------------------*/
+static void genUminus (iCode *ic)
+{
+ int offset ,size ;
+ link *optype, *rtype;
+
+ D(emitcode(";", "genUminus "););
+
+
+ /* assign asmops */
+ aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
+ aopOp(IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
+
+ /* if both in bit space then special
+ case */
+ if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
+ AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
+
+ emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir);
+ emitcode("cpl","c");
+ emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir);
+ goto release;
+ }
+
+ optype = operandType(IC_LEFT(ic));
+ rtype = operandType(IC_RESULT(ic));
+
+ /* if float then do float stuff */
+ if (IS_FLOAT(optype)) {
+ genUminusFloat(IC_LEFT(ic),IC_RESULT(ic));
+ goto release;
+ }
+
+ /* otherwise subtract from zero */
+ size = AOP_SIZE(IC_LEFT(ic));
+ offset = 0 ;
+ CLRC ;
+ while(size--) {
+ char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE);
+ if (!strcmp(l,"a")) {
+ emitcode("cpl","a");
+ emitcode("inc","a");
+ } else {
+ emitcode("clr","a");
+ emitcode("subb","a,%s",l);
+ }
+ aopPut(AOP(IC_RESULT(ic)),"a",offset++);
+ }
+
+ /* if any remaining bytes in the result */
+ /* we just need to propagate the sign */
+ if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
+ emitcode("rlc","a");
+ emitcode("subb","a,acc");
+ while (size--)
+ aopPut(AOP(IC_RESULT(ic)),"a",offset++);
+ }
+
+release:
+ /* release the aops */
+ freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* saveRegisters - will look for a call and save the registers */
+/*-----------------------------------------------------------------*/
+static void saveRegisters(iCode *lic)
+{
+ int i;
+ iCode *ic;
+ bitVect *rsave;
+ link *detype;
+
+ /* look for call */
+ for (ic = lic ; ic ; ic = ic->next)
+ if (ic->op == CALL || ic->op == PCALL)
+ break;
+
+ if (!ic) {
+ fprintf(stderr,"found parameter push with no function call\n");
+ return ;
+ }
+
+ /* if the registers have been saved already then
+ do nothing */
+ if (ic->regsSaved || (OP_SYMBOL(IC_LEFT(ic))->calleeSave))
+ return ;
+
+ /* find the registers in use at this time
+ and push them away to safety */
+ rsave = bitVectCplAnd(bitVectCopy(ic->rMask),
+ ic->rUsed);
+
+ ic->regsSaved = 1;
+ if (options.useXstack) {
+ if (bitVectBitValue(rsave,R0_IDX))
+ emitcode("mov","b,r0");
+ emitcode("mov","r0,%s",spname);
+ for (i = 0 ; i < ds390_nRegs ; i++) {
+ if (bitVectBitValue(rsave,i)) {
+ if (i == R0_IDX)
+ emitcode("mov","a,b");
+ else
+ emitcode("mov","a,%s",ds390_regWithIdx(i)->name);
+ emitcode("movx","@r0,a");
+ emitcode("inc","r0");
+ }
+ }
+ emitcode("mov","%s,r0",spname);
+ if (bitVectBitValue(rsave,R0_IDX))
+ emitcode("mov","r0,b");
+ } else
+ for (i = 0 ; i < ds390_nRegs ; i++) {
+ if (bitVectBitValue(rsave,i))
+ emitcode("push","%s",ds390_regWithIdx(i)->dname);
+ }
+
+ detype = getSpec(operandType(IC_LEFT(ic)));
+ if (detype &&
+ (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) &&
+ IS_ISR(currFunc->etype) &&
+ !ic->bankSaved)
+
+ saverbank(SPEC_BANK(detype),ic,TRUE);
+
+}
+/*-----------------------------------------------------------------*/
+/* unsaveRegisters - pop the pushed registers */
+/*-----------------------------------------------------------------*/
+static void unsaveRegisters (iCode *ic)
+{
+ int i;
+ bitVect *rsave;
+ /* find the registers in use at this time
+ and push them away to safety */
+ rsave = bitVectCplAnd(bitVectCopy(ic->rMask),
+ ic->rUsed);
+
+ if (options.useXstack) {
+ emitcode("mov","r0,%s",spname);
+ for (i = ds390_nRegs ; i >= 0 ; i--) {
+ if (bitVectBitValue(rsave,i)) {
+ emitcode("dec","r0");
+ emitcode("movx","a,@r0");
+ if (i == R0_IDX)
+ emitcode("mov","b,a");
+ else
+ emitcode("mov","%s,a",ds390_regWithIdx(i)->name);
+ }
+
+ }
+ emitcode("mov","%s,r0",spname);
+ if (bitVectBitValue(rsave,R0_IDX))
+ emitcode("mov","r0,b");
+ } else
+ for (i = ds390_nRegs ; i >= 0 ; i--) {
+ if (bitVectBitValue(rsave,i))
+ emitcode("pop","%s",ds390_regWithIdx(i)->dname);
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* pushSide - */
+/*-----------------------------------------------------------------*/
+static void pushSide(operand * oper, int size)
+{
+ int offset = 0;
+ while (size--) {
+ char *l = aopGet(AOP(oper),offset++,FALSE,TRUE);
+ if (AOP_TYPE(oper) != AOP_REG &&
+ AOP_TYPE(oper) != AOP_DIR &&
+ strcmp(l,"a") ) {
+ emitcode("mov","a,%s",l);
+ emitcode("push","acc");
+ } else
+ emitcode("push","%s",l);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignResultValue - */
+/*-----------------------------------------------------------------*/
+static void assignResultValue(operand * oper)
+{
+ int offset = 0;
+ int size = AOP_SIZE(oper);
+ while (size--) {
+ aopPut(AOP(oper),fReturn[offset],offset);
+ offset++;
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genXpush - pushes onto the external stack */
+/*-----------------------------------------------------------------*/
+static void genXpush (iCode *ic)
+{
+ asmop *aop = newAsmop(0);
+ regs *r ;
+ int size,offset = 0;
+
+ D(emitcode(";", "genXpush "););
+
+ aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
+ r = getFreePtr(ic,&aop,FALSE);
+
+
+ emitcode("mov","%s,_spx",r->name);
+
+ size = AOP_SIZE(IC_LEFT(ic));
+ while(size--) {
+
+ char *l = aopGet(AOP(IC_LEFT(ic)),
+ offset++,FALSE,FALSE);
+ MOVA(l);
+ emitcode("movx","@%s,a",r->name);
+ emitcode("inc","%s",r->name);
+
+ }
+
+
+ emitcode("mov","_spx,%s",r->name);
+
+ freeAsmop(NULL,aop,ic,TRUE);
+ freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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, FALSE);
+ size = AOP_SIZE(IC_LEFT(ic));
+ /* push it on the stack */
+ while(size--) {
+ l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE);
+ if (*l == '#') {
+ MOVA(l);
+ l = "acc";
+ }
+ emitcode("push","%s",l);
+ }
+ 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);
+
+ /* if use external stack then call the external
+ stack pushing routine */
+ if (options.useXstack) {
+ genXpush(ic);
+ return ;
+ }
+
+ /* then do the push */
+ aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
+
+
+ // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
+ size = AOP_SIZE(IC_LEFT(ic));
+
+ while (size--) {
+ l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE);
+ if (AOP_TYPE(IC_LEFT(ic)) != AOP_REG &&
+ AOP_TYPE(IC_LEFT(ic)) != AOP_DIR &&
+ strcmp(l,"a") ) {
+ emitcode("mov","a,%s",l);
+ emitcode("push","acc");
+ } else
+ emitcode("push","%s",l);
+ }
+
+ 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, FALSE);
+ size = AOP_SIZE(IC_LEFT(ic));
+ offset = (size-1);
+ while (size--)
+ emitcode("pop","%s",aopGet(AOP(IC_LEFT(ic)),offset--,
+ FALSE,TRUE));
+
+ freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaverbank - restores the resgister bank from stack */
+/*-----------------------------------------------------------------*/
+static void unsaverbank (int bank,iCode *ic,bool popPsw)
+{
+ int i;
+ asmop *aop ;
+ regs *r = NULL;
+
+ if (popPsw) {
+ if (options.useXstack) {
+ aop = newAsmop(0);
+ r = getFreePtr(ic,&aop,FALSE);
+
+
+ emitcode("mov","%s,_spx",r->name);
+ emitcode("movx","a,@%s",r->name);
+ emitcode("mov","psw,a");
+ emitcode("dec","%s",r->name);
+
+ }else
+ emitcode ("pop","psw");
+ }
+
+ for (i = (ds390_nRegs - 1) ; i >= 0 ;i--) {
+ if (options.useXstack) {
+ emitcode("movx","a,@%s",r->name);
+ emitcode("mov","(%s+%d),a",
+ regs390[i].base,8*bank+regs390[i].offset);
+ emitcode("dec","%s",r->name);
+
+ } else
+ emitcode("pop","(%s+%d)",
+ regs390[i].base,8*bank+regs390[i].offset);
+ }
+
+ if (options.useXstack) {
+
+ emitcode("mov","_spx,%s",r->name);
+ freeAsmop(NULL,aop,ic,TRUE);
+
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* saverbank - saves an entire register bank on the stack */
+/*-----------------------------------------------------------------*/
+static void saverbank (int bank, iCode *ic, bool pushPsw)
+{
+ int i;
+ asmop *aop ;
+ regs *r = NULL;
+
+ if (options.useXstack) {
+
+ aop = newAsmop(0);
+ r = getFreePtr(ic,&aop,FALSE);
+ emitcode("mov","%s,_spx",r->name);
+
+ }
+
+ for (i = 0 ; i < ds390_nRegs ;i++) {
+ if (options.useXstack) {
+ emitcode("inc","%s",r->name);
+ emitcode("mov","a,(%s+%d)",
+ regs390[i].base,8*bank+regs390[i].offset);
+ emitcode("movx","@%s,a",r->name);
+ } else
+ emitcode("push","(%s+%d)",
+ regs390[i].base,8*bank+regs390[i].offset);
+ }
+
+ if (pushPsw) {
+ if (options.useXstack) {
+ emitcode("mov","a,psw");
+ emitcode("movx","@%s,a",r->name);
+ emitcode("inc","%s",r->name);
+ emitcode("mov","_spx,%s",r->name);
+ freeAsmop (NULL,aop,ic,TRUE);
+
+ } else
+ emitcode("push","psw");
+
+ emitcode("mov","psw,#0x%02x",(bank << 3)&0x00ff);
+ }
+ ic->bankSaved = 1;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genCall - generates a call statement */
+/*-----------------------------------------------------------------*/
+static void genCall (iCode *ic)
+{
+ link *detype;
+
+ D(emitcode(";", "genCall "););
+
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters(ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ detype = getSpec(operandType(IC_LEFT(ic)));
+ if (detype &&
+ (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) &&
+ IS_ISR(currFunc->etype) &&
+ !ic->bankSaved)
+
+ saverbank(SPEC_BANK(detype),ic,TRUE);
+
+ /* if send set is not empty the assign */
+ if (_G.sendSet) {
+ iCode *sic ;
+
+ for (sic = setFirstItem(_G.sendSet) ; sic ;
+ sic = setNextItem(_G.sendSet)) {
+ int size, offset = 0;
+ aopOp(IC_LEFT(sic),sic,FALSE, TRUE);
+ size = AOP_SIZE(IC_LEFT(sic));
+ while (size--) {
+ char *l = aopGet(AOP(IC_LEFT(sic)),offset,
+ FALSE, FALSE);
+ if (strcmp(l,fReturn[offset]))
+ emitcode("mov","%s,%s",
+ fReturn[offset],
+ l);
+ offset++;
+ }
+ freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
+ }
+ _G.sendSet = NULL;
+ }
+ /* make the call */
+ emitcode("lcall","%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))->spildir )) ||
+ IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
+
+ if (!isOperandInFarSpace(IC_RESULT(ic)))
+ {
+ _G.accInUse++;
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
+ _G.accInUse--;
+
+ assignResultValue(IC_RESULT(ic));
+
+ freeAsmop(IC_RESULT(ic),NULL, ic,TRUE);
+ }
+ else
+ {
+ /* Result is in far space, and requires DPTR to access
+ * it. Push the result onto the stack and restore from
+ * there.
+ */
+ int size = getSize(operandType(IC_RESULT(ic)));
+ int offset = size - 1;
+ char *l;
+
+ emitcode(";", "Kevin function call abuse #1");
+
+ /* first push the right side on to the stack */
+ /* NB: this relies on the fact that "a" is the last
+ * register in fReturn. If it were not, the MOVA
+ * would potentially clobber a returned byte in A.
+ */
+ while (size--) {
+ l = fReturn[offset--];
+ MOVA(l);
+ emitcode ("push","acc");
+ }
+
+ /* now assign DPTR to result */
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
+ size = AOP_SIZE(IC_RESULT(ic));
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE); /* bug? */
+ while (size--) {
+ emitcode ("pop","acc");
+ aopPut(AOP(IC_RESULT(ic)),"a",++offset);
+ }
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+ }
+ }
+
+ /* adjust the stack for parameters if
+ required */
+ if (IC_LEFT(ic)->parmBytes) {
+ int i;
+ if (IC_LEFT(ic)->parmBytes > 3) {
+ emitcode("mov","a,%s",spname);
+ emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff);
+ emitcode("mov","%s,a",spname);
+ } else
+ for ( i = 0 ; i < IC_LEFT(ic)->parmBytes ;i++)
+ emitcode("dec","%s",spname);
+
+ }
+
+ /* if register bank was saved then pop them */
+ if (ic->bankSaved)
+ unsaverbank(SPEC_BANK(detype),ic,TRUE);
+
+ /* if we hade saved some registers then unsave them */
+ if (ic->regsSaved && !(OP_SYMBOL(IC_LEFT(ic))->calleeSave))
+ unsaveRegisters (ic);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPcall - generates a call by pointer statement */
+/*-----------------------------------------------------------------*/
+static void genPcall (iCode *ic)
+{
+ link *detype;
+ symbol *rlbl = newiTempLabel(NULL);
+
+ D(emitcode(";", "genPcall "););
+
+
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters(ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ detype = getSpec(operandType(IC_LEFT(ic)));
+ if (detype &&
+ IS_ISR(currFunc->etype) &&
+ (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)))
+ saverbank(SPEC_BANK(detype),ic,TRUE);
+
+
+ /* push the return address on to the stack */
+ emitcode("mov","a,#%05d$",(rlbl->key+100));
+ emitcode("push","acc");
+ emitcode("mov","a,#(%05d$ >> 8)",(rlbl->key+100));
+ emitcode("push","acc");
+
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov","a,#(%05d$ >> 16)",(rlbl->key+100));
+ emitcode("push","acc");
+ }
+
+ /* now push the calling address */
+ aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
+
+ pushSide(IC_LEFT(ic), FPTRSIZE);
+
+ freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
+
+ /* if send set is not empty the assign */
+ if (_G.sendSet) {
+ iCode *sic ;
+
+ for (sic = setFirstItem(_G.sendSet) ; sic ;
+ sic = setNextItem(_G.sendSet)) {
+ int size, offset = 0;
+ aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
+ size = AOP_SIZE(IC_LEFT(sic));
+ while (size--) {
+ char *l = aopGet(AOP(IC_LEFT(sic)),offset,
+ FALSE,FALSE);
+ if (strcmp(l,fReturn[offset]))
+ emitcode("mov","%s,%s",
+ fReturn[offset],
+ l);
+ offset++;
+ }
+ freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
+ }
+ _G.sendSet = NULL;
+ }
+
+ emitcode("ret","");
+ emitcode("","%05d$:",(rlbl->key+100));
+
+
+ /* 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, TRUE);
+ _G.accInUse--;
+
+ assignResultValue(IC_RESULT(ic));
+
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+ }
+
+ /* adjust the stack for parameters if
+ required */
+ if (IC_LEFT(ic)->parmBytes) {
+ int i;
+ if (IC_LEFT(ic)->parmBytes > 3) {
+ emitcode("mov","a,%s",spname);
+ emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff);
+ emitcode("mov","%s,a",spname);
+ } else
+ for ( i = 0 ; i < IC_LEFT(ic)->parmBytes ;i++)
+ emitcode("dec","%s",spname);
+
+ }
+
+ /* if register bank was saved then unsave them */
+ if (detype &&
+ (SPEC_BANK(currFunc->etype) !=
+ SPEC_BANK(detype)))
+ unsaverbank(SPEC_BANK(detype),ic,TRUE);
+
+ /* if we hade saved some registers then
+ unsave them */
+ if (ic->regsSaved)
+ 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;
+}
+
+#ifdef __BORLANDC__
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
+/*-----------------------------------------------------------------*/
+/* inExcludeList - return 1 if the string is in exclude Reg list */
+/*-----------------------------------------------------------------*/
+static bool inExcludeList(char *s)
+{
+ int i =0;
+
+ if (options.excludeRegs[i] &&
+ STRCASECMP(options.excludeRegs[i],"none") == 0)
+ return FALSE ;
+
+ for ( i = 0 ; options.excludeRegs[i]; i++) {
+ if (options.excludeRegs[i] &&
+ STRCASECMP(s,options.excludeRegs[i]) == 0)
+ return TRUE;
+ }
+ return FALSE ;
+}
+
+/*-----------------------------------------------------------------*/
+/* genFunction - generated code for function entry */
+/*-----------------------------------------------------------------*/
+static void genFunction (iCode *ic)
+{
+ symbol *sym;
+ link *fetype;
+
+ D(emitcode(";", "genFunction "););
+
+ _G.nRegsSaved = 0;
+ /* create the function header */
+ emitcode(";","-----------------------------------------");
+ emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
+ emitcode(";","-----------------------------------------");
+
+ emitcode("","%s:",sym->rname);
+ fetype = getSpec(operandType(IC_LEFT(ic)));
+
+ /* if critical function then turn interrupts off */
+ if (SPEC_CRTCL(fetype))
+ emitcode("clr","ea");
+
+ /* here we need to generate the equates for the
+ register bank if required */
+ if (SPEC_BANK(fetype) != rbank) {
+ int i ;
+
+ rbank = SPEC_BANK(fetype);
+ for ( i = 0 ; i < ds390_nRegs ; i++ ) {
+ if (strcmp(regs390[i].base,"0") == 0)
+ emitcode("","%s = 0x%02x",
+ regs390[i].dname,
+ 8*rbank+regs390[i].offset);
+ else
+ emitcode ("","%s = %s + 0x%02x",
+ regs390[i].dname,
+ regs390[i].base,
+ 8*rbank+regs390[i].offset);
+ }
+ }
+
+ /* if this is an interrupt service routine then
+ save acc, b, dpl, dph */
+ if (IS_ISR(sym->etype)) {
+
+ if (!inExcludeList("acc"))
+ emitcode ("push","acc");
+ if (!inExcludeList("b"))
+ emitcode ("push","b");
+ if (!inExcludeList("dpl"))
+ emitcode ("push","dpl");
+ if (!inExcludeList("dph"))
+ emitcode ("push","dph");
+ if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
+ {
+ emitcode ("push", "dpx");
+ /* Make sure we're using standard DPTR */
+ emitcode ("push", "dps");
+ emitcode ("mov", "dps, #0x00");
+ if (options.stack10bit)
+ {
+ /* This ISR could conceivably use DPTR2. Better save it. */
+ emitcode ("push", "dpl1");
+ emitcode ("push", "dph1");
+ emitcode ("push", "dpx1");
+ emitcode ("push", "ap");
+ }
+ }
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+ registers :-) */
+ if (!SPEC_BANK(sym->etype)) {
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (! sym->hasFcall) {
+ 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) ||
+ (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
+ emitcode("push","%s",ds390_regWithIdx(i)->dname);
+ }
+ }
+
+ } else {
+ /* this function has a function call cannot
+ determines register usage so we will have the
+ entire bank */
+ saverbank(0,ic,FALSE);
+ }
+ }
+ } else {
+ /* if callee-save to be used for this function
+ then save the registers being used in this function */
+ if (sym->calleeSave) {
+ 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) ||
+ (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) {
+ emitcode("push","%s",ds390_regWithIdx(i)->dname);
+ _G.nRegsSaved++;
+ }
+ }
+ }
+ }
+ }
+
+ /* set the register bank to the desired value */
+ if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype)) {
+ emitcode("push","psw");
+ emitcode("mov","psw,#0x%02x",(SPEC_BANK(sym->etype) << 3)&0x00ff);
+ }
+
+ if (IS_RENT(sym->etype) || options.stackAuto) {
+
+ if (options.useXstack) {
+ emitcode("mov","r0,%s",spname);
+ emitcode("mov","a,_bp");
+ emitcode("movx","@r0,a");
+ emitcode("inc","%s",spname);
+ }
+ else
+ {
+ /* set up the stack */
+ emitcode ("push","_bp"); /* save the callers stack */
+ }
+ emitcode ("mov","_bp,%s",spname);
+ }
+
+ /* adjust the stack for the function */
+ if (sym->stack) {
+
+ int i = sym->stack;
+ if (i > 256 )
+ werror(W_STACK_OVERFLOW,sym->name);
+
+ if (i > 3 && sym->recvSize < 4) {
+
+ emitcode ("mov","a,sp");
+ emitcode ("add","a,#0x%02x",((char)sym->stack & 0xff));
+ emitcode ("mov","sp,a");
+
+ }
+ else
+ while(i--)
+ emitcode("inc","sp");
+ }
+
+ if (sym->xstack) {
+
+ emitcode ("mov","a,_spx");
+ emitcode ("add","a,#0x%02x",((char)sym->xstack & 0xff));
+ emitcode ("mov","_spx,a");
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndFunction - generates epilogue for functions */
+/*-----------------------------------------------------------------*/
+static void genEndFunction (iCode *ic)
+{
+ symbol *sym = OP_SYMBOL(IC_LEFT(ic));
+
+ D(emitcode(";", "genEndFunction "););
+
+ if (IS_RENT(sym->etype) || options.stackAuto)
+ {
+ emitcode ("mov","%s,_bp",spname);
+ }
+
+ /* if use external stack but some variables were
+ added to the local stack then decrement the
+ local stack */
+ if (options.useXstack && sym->stack) {
+ emitcode("mov","a,sp");
+ emitcode("add","a,#0x%02x",((char)-sym->stack) & 0xff);
+ emitcode("mov","sp,a");
+ }
+
+
+ if ((IS_RENT(sym->etype) || options.stackAuto)) {
+ if (options.useXstack) {
+ emitcode("mov","r0,%s",spname);
+ emitcode("movx","a,@r0");
+ emitcode("mov","_bp,a");
+ emitcode("dec","%s",spname);
+ }
+ else
+ {
+ emitcode ("pop","_bp");
+ }
+ }
+
+ /* restore the register bank */
+ if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype))
+ emitcode ("pop","psw");
+
+ if (IS_ISR(sym->etype)) {
+
+ /* now we need to restore the registers */
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+ registers :-) */
+ if (!SPEC_BANK(sym->etype)) {
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (! sym->hasFcall) {
+ 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) ||
+ (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
+ emitcode("pop","%s",ds390_regWithIdx(i)->dname);
+ }
+ }
+
+ } else {
+ /* this function has a function call cannot
+ determines register usage so we will have the
+ entire bank */
+ unsaverbank(0,ic,FALSE);
+ }
+ }
+
+ if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
+ {
+ if (options.stack10bit)
+ {
+ emitcode ("pop", "ap");
+ emitcode ("pop", "dpx1");
+ emitcode ("pop", "dph1");
+ emitcode ("pop", "dpl1");
+ }
+ emitcode ("pop", "dps");
+ emitcode ("pop", "dpx");
+ }
+ if (!inExcludeList("dph"))
+ emitcode ("pop","dph");
+ if (!inExcludeList("dpl"))
+ emitcode ("pop","dpl");
+ if (!inExcludeList("b"))
+ emitcode ("pop","b");
+ if (!inExcludeList("acc"))
+ emitcode ("pop","acc");
+
+ if (SPEC_CRTCL(sym->etype))
+ emitcode("setb","ea");
+
+ /* if debug then send end of function */
+/* if (options.debug && currFunc) { */
+ if (currFunc) {
+ _G.debugLine = 1;
+ emitcode("","C$%s$%d$%d$%d ==.",
+ 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 ("reti","");
+ }
+ else {
+ if (SPEC_CRTCL(sym->etype))
+ emitcode("setb","ea");
+
+ if (sym->calleeSave) {
+ 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) ||
+ (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
+ emitcode("pop","%s",ds390_regWithIdx(i)->dname);
+ }
+ }
+
+ }
+
+ /* if debug then send end of function */
+ if (currFunc) {
+ _G.debugLine = 1;
+ emitcode("","C$%s$%d$%d$%d ==.",
+ 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 ("ret","");
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genRet - generate code for return statement */
+/*-----------------------------------------------------------------*/
+static void genRet (iCode *ic)
+{
+ int size,offset = 0 , 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, TRUE);
+ size = AOP_SIZE(IC_LEFT(ic));
+
+ while (size--) {
+ char *l ;
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) {
+ /* #NOCHANGE */
+ l = aopGet(AOP(IC_LEFT(ic)),offset++,
+ FALSE,TRUE);
+ emitcode("push","%s",l);
+ pushed++;
+ } else {
+ l = aopGet(AOP(IC_LEFT(ic)),offset,
+ FALSE,FALSE);
+ if (strcmp(fReturn[offset],l))
+ emitcode("mov","%s,%s",fReturn[offset++],l);
+ }
+ }
+
+ if (pushed) {
+ while(pushed) {
+ pushed--;
+ if (strcmp(fReturn[pushed],"a"))
+ emitcode("pop",fReturn[pushed]);
+ else
+ emitcode("pop","acc");
+ }
+ }
+ freeAsmop (IC_LEFT(ic),NULL,ic,TRUE);
+
+ jumpret:
+ /* generate a jump to the return label
+ if the next is not the return statement */
+ if (!(ic->next && ic->next->op == LABEL &&
+ IC_LABEL(ic->next) == returnLabel))
+
+ emitcode("ljmp","%05d$",(returnLabel->key+100));
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genLabel - generates a label */
+/*-----------------------------------------------------------------*/
+static void genLabel (iCode *ic)
+{
+ /* special case never generate */
+ if (IC_LABEL(ic) == entryLabel)
+ return ;
+
+ D(emitcode(";", "genLabel "););
+
+ emitcode("","%05d$:",(IC_LABEL(ic)->key+100));
+}
+
+/*-----------------------------------------------------------------*/
+/* genGoto - generates a ljmp */
+/*-----------------------------------------------------------------*/
+static void genGoto (iCode *ic)
+{
+ D(emitcode(";", "genGoto "););
+ emitcode ("ljmp","%05d$",(IC_LABEL(ic)->key+100));
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 (ic->op == LABEL && IC_LABEL(ic)->key == key)
+ {
+ /* printf("findLabelBackwards = %d\n", count); */
+ return count;
+ }
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlusIncr :- does addition with increment if possible */
+/*-----------------------------------------------------------------*/
+static bool genPlusIncr (iCode *ic)
+{
+ unsigned int icount ;
+ unsigned int size = getDataSize(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 ;
+
+ /* if the literal value of the right hand side
+ is greater than 4 then it is not worth it */
+ if ((icount = floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
+ return FALSE ;
+
+ /* if increment 16 bits in register */
+ if (
+ AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
+ AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
+ sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
+ (size > 1) &&
+ (icount == 1)) {
+ symbol *tlbl;
+ int emitTlbl;
+ int labelRange;
+
+ /* If the next instruction is a goto and the goto target
+ * is < 10 instructions previous to this, we can generate
+ * jumps straight to that target.
+ */
+ if (ic->next && ic->next->op == GOTO
+ && (labelRange = findLabelBackwards(ic, IC_LABEL(ic->next)->key)) != 0
+ && labelRange <= 10 )
+ {
+ emitcode(";", "tail increment optimized");
+ tlbl = IC_LABEL(ic->next);
+ emitTlbl = 0;
+ }
+ else
+ {
+ tlbl = newiTempLabel(NULL);
+ emitTlbl = 1;
+ }
+ emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0x00,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)
+ ,tlbl->key+100);
+ else {
+ emitcode("clr","a");
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)
+ ,tlbl->key+100);
+ }
+
+ emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE));
+ if (size > 2)
+ {
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0x00,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)
+ ,tlbl->key+100);
+ else
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)
+ ,tlbl->key+100);
+
+ emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE));
+ }
+ if (size > 3)
+ {
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0x00,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)
+ ,tlbl->key+100);
+ else{
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)
+ ,tlbl->key+100);
+ }
+ emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE));
+ }
+
+ if (emitTlbl)
+ {
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ return TRUE;
+ }
+
+ /* if the sizes are greater than 1 then we cannot */
+ if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
+ AOP_SIZE(IC_LEFT(ic)) > 1 )
+ return FALSE ;
+
+ /* we can if the aops of the left & result match or
+ if they are in registers and the registers are the
+ same */
+ if (
+ AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
+ AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
+ sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
+
+ if (icount > 3) {
+ MOVA(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
+ emitcode("add","a,#0x%02x",((char) icount) & 0xff);
+ aopPut(AOP(IC_RESULT(ic)),"a",0);
+ } else {
+
+ while (icount--)
+ emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
+ }
+
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+/*-----------------------------------------------------------------*/
+/* outBitAcc - output a bit in acc */
+/*-----------------------------------------------------------------*/
+static void outBitAcc(operand *result)
+{
+ symbol *tlbl = newiTempLabel(NULL);
+ /* if the result is a bit */
+ if (AOP_TYPE(result) == AOP_CRY){
+ aopPut(AOP(result),"a",0);
+ }
+ else {
+ emitcode("jz","%05d$",tlbl->key+100);
+ emitcode("mov","a,%s",one);
+ emitcode("","%05d$:",tlbl->key+100);
+ outAcc(result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlusBits - generates code for addition of two bits */
+/*-----------------------------------------------------------------*/
+static void genPlusBits (iCode *ic)
+{
+ D(emitcode(";", "genPlusBits "););
+ if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
+ symbol *lbl = newiTempLabel(NULL);
+ emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
+ emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100));
+ emitcode("cpl","c");
+ emitcode("","%05d$:",(lbl->key+100));
+ outBitC(IC_RESULT(ic));
+ }
+ else{
+ emitcode("clr","a");
+ emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
+ emitcode("rlc","a");
+ emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir);
+ emitcode("addc","a,#0x00");
+ outAcc(IC_RESULT(ic));
+ }
+}
+
+
+
+#if 0
+/* This is the original version of this code.
+ *
+ * This is being kept around for reference,
+ * because I am not entirely sure I got it right...
+ */
+static void adjustArithmeticResult(iCode *ic)
+{
+ if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
+ AOP_SIZE(IC_LEFT(ic)) == 3 &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
+ aopPut(AOP(IC_RESULT(ic)),
+ aopGet(AOP(IC_LEFT(ic)),2,FALSE,FALSE),
+ 2);
+
+ if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
+ AOP_SIZE(IC_RIGHT(ic)) == 3 &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
+ aopPut(AOP(IC_RESULT(ic)),
+ aopGet(AOP(IC_RIGHT(ic)),2,FALSE,FALSE),
+ 2);
+
+ if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
+ AOP_SIZE(IC_LEFT(ic)) < 3 &&
+ AOP_SIZE(IC_RIGHT(ic)) < 3 &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
+ char buffer[5];
+ sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
+ aopPut(AOP(IC_RESULT(ic)),buffer,2);
+ }
+}
+#else
+/* This is the pure and virtuous version of this code.
+ * I'm pretty certain it's right, but not enough to toss the old
+ * code just yet...
+ */
+static void adjustArithmeticResult(iCode *ic)
+{
+ if (opIsGptr(IC_RESULT(ic)) &&
+ opIsGptr(IC_LEFT(ic)) &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
+ {
+ aopPut(AOP(IC_RESULT(ic)),
+ aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE),
+ GPTRSIZE - 1);
+ }
+
+ if (opIsGptr(IC_RESULT(ic)) &&
+ opIsGptr(IC_RIGHT(ic)) &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
+ {
+ aopPut(AOP(IC_RESULT(ic)),
+ aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE),
+ GPTRSIZE - 1);
+ }
+
+ if (opIsGptr(IC_RESULT(ic)) &&
+ AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE &&
+ AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
+ !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
+ char buffer[5];
+ sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
+ aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
+ }
+}
+#endif
+
+#define AOP_OP_3(ic) \
+ aopOp (IC_LEFT(ic),ic,FALSE, FALSE); \
+ aopOp (IC_RIGHT(ic),ic,FALSE, TRUE); \
+ aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR); \
+ if (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR2 && \
+ AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR2) \
+ { \
+ /* werror(E_INTERNAL_ERROR,__FILE__,__LINE__, */ \
+ fprintf(stderr, \
+ "Ack: three operands in far space!\n"); \
+ }
+
+#define AOP_SET_LOCALS(ic) \
+ left = IC_LEFT(ic); \
+ right = IC_RIGHT(ic); \
+ result = IC_RESULT(ic);
+
+/*-----------------------------------------------------------------*/
+/* genPlus - generates code for addition */
+/*-----------------------------------------------------------------*/
+static void genPlus (iCode *ic)
+{
+ int size, offset = 0;
+ bool pushResult = FALSE;
+
+ D(emitcode(";", "genPlus "););
+
+ /* special cases :- */
+
+ aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
+ aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
+ if ((AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR2) &&
+ (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR))
+ {
+ pushResult = TRUE;
+ }
+ else
+ {
+ aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR);
+
+ /* if literal, literal on the right or
+ if left requires ACC or right is already
+ in ACC */
+ if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
+ (AOP_NEEDSACC(IC_LEFT(ic))) ||
+ AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
+ operand *t = IC_RIGHT(ic);
+ IC_RIGHT(ic) = IC_LEFT(ic);
+ IC_LEFT(ic) = t;
+ }
+
+ /* if both left & right are in bit
+ space */
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
+ AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
+ genPlusBits (ic);
+ goto release ;
+ }
+
+ /* if left in bit space & right literal */
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
+ AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
+ emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
+ /* if result in bit space */
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
+ if((unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L)
+ emitcode("cpl","c");
+ outBitC(IC_RESULT(ic));
+ } else {
+ size = getDataSize(IC_RESULT(ic));
+ while (size--) {
+ MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ emitcode("addc","a,#00");
+ aopPut(AOP(IC_RESULT(ic)),"a",offset++);
+ }
+ }
+ goto release ;
+ }
+
+ /* if I can do an increment instead
+ of add then GOOD for ME */
+ if (genPlusIncr (ic) == TRUE)
+ goto release;
+
+ }
+ size = getDataSize(pushResult ? IC_LEFT(ic) : IC_RESULT(ic));
+
+ while(size--){
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
+ MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE));
+ if(offset == 0)
+ emitcode("add","a,%s",
+ aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ else
+ emitcode("addc","a,%s",
+ aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ } else {
+ MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ if(offset == 0)
+ emitcode("add","a,%s",
+ aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE));
+ else
+ emitcode("addc","a,%s",
+ aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE));
+ }
+ if (!pushResult)
+ {
+ aopPut(AOP(IC_RESULT(ic)),"a",offset);
+ }
+ else
+ {
+ emitcode("push", "acc");
+ }
+ offset++;
+ }
+
+ if (pushResult)
+ {
+ aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
+
+ size = getDataSize(IC_LEFT(ic));
+
+ while(size--)
+ {
+ emitcode("pop", "acc");
+ aopPut(AOP(IC_RESULT(ic)), "a", --offset);
+ }
+ }
+
+ 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinusDec :- does subtraction with deccrement if possible */
+/*-----------------------------------------------------------------*/
+static bool genMinusDec (iCode *ic)
+{
+ unsigned int icount ;
+ unsigned int size = getDataSize(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 ;
+
+ /* if the literal value of the right hand side
+ is greater than 4 then it is not worth it */
+ if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
+ return FALSE ;
+
+ /* if decrement 16 bits in register */
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
+ AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
+ sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
+ (size > 1) &&
+ (icount == 1)) {
+ symbol *tlbl;
+ int emitTlbl;
+ int labelRange;
+
+ /* If the next instruction is a goto and the goto target
+ * is <= 10 instructions previous to this, we can generate
+ * jumps straight to that target.
+ */
+ if (ic->next && ic->next->op == GOTO
+ && (labelRange = findLabelBackwards(ic, IC_LABEL(ic->next)->key)) != 0
+ && labelRange <= 10 )
+ {
+ emitcode(";", "tail decrement optimized");
+ tlbl = IC_LABEL(ic->next);
+ emitTlbl = 0;
+ }
+ else
+ {
+ tlbl = newiTempLabel(NULL);
+ emitTlbl = 1;
+ }
+
+ emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0xff,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)
+ ,tlbl->key+100);
+ else{
+ emitcode("mov","a,#0xff");
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)
+ ,tlbl->key+100);
+ }
+ emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE));
+ if (size > 2)
+ {
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0xff,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)
+ ,tlbl->key+100);
+ else{
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)
+ ,tlbl->key+100);
+ }
+ emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE));
+ }
+ if (size > 3)
+ {
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
+ AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
+ IS_AOP_PREG(IC_RESULT(ic)))
+ emitcode("cjne","%s,#0xff,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)
+ ,tlbl->key+100);
+ else{
+ emitcode("cjne","a,%s,%05d$"
+ ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)
+ ,tlbl->key+100);
+ }
+ emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE));
+ }
+ if (emitTlbl)
+ {
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ return TRUE;
+ }
+
+ /* if the sizes are greater than 1 then we cannot */
+ if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
+ AOP_SIZE(IC_LEFT(ic)) > 1 )
+ return FALSE ;
+
+ /* we can if the aops of the left & result match or
+ if they are in registers and the registers are the
+ same */
+ if (
+ AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
+ AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
+ sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
+
+ while (icount--)
+ emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
+
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+/*-----------------------------------------------------------------*/
+/* addSign - complete with sign */
+/*-----------------------------------------------------------------*/
+static void addSign(operand *result, int offset, int sign)
+{
+ int size = (getDataSize(result) - offset);
+ if(size > 0){
+ if(sign){
+ emitcode("rlc","a");
+ emitcode("subb","a,acc");
+ while(size--)
+ aopPut(AOP(result),"a",offset++);
+ } else
+ while(size--)
+ aopPut(AOP(result),zero,offset++);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinusBits - generates code for subtraction of two bits */
+/*-----------------------------------------------------------------*/
+static void genMinusBits (iCode *ic)
+{
+ symbol *lbl = newiTempLabel(NULL);
+
+ D(emitcode(";", "genMinusBits "););
+
+ if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
+ emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
+ emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100));
+ emitcode("cpl","c");
+ emitcode("","%05d$:",(lbl->key+100));
+ outBitC(IC_RESULT(ic));
+ }
+ else{
+ emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir);
+ emitcode("subb","a,acc");
+ emitcode("jnb","%s,%05d$",AOP(IC_LEFT(ic))->aopu.aop_dir,(lbl->key+100));
+ emitcode("inc","a");
+ emitcode("","%05d$:",(lbl->key+100));
+ aopPut(AOP(IC_RESULT(ic)),"a",0);
+ addSign(IC_RESULT(ic), MSB16, SPEC_USIGN(getSpec(operandType(IC_RESULT(ic)))));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinus - generates code for subtraction */
+/*-----------------------------------------------------------------*/
+static void genMinus (iCode *ic)
+{
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ bool pushResult = FALSE;
+
+ D(emitcode(";", "genMinus "););
+
+ aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
+ aopOp (IC_RIGHT(ic),ic,FALSE, TRUE);
+ if ((AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) &&
+ (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR2))
+ {
+ pushResult = TRUE;
+ }
+ else
+ {
+ aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
+
+ /* special cases :- */
+ /* if both left & right are in bit space */
+ if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
+ AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
+ genMinusBits (ic);
+ goto release ;
+ }
+
+ /* if I can do an decrement instead
+ of subtract then GOOD for ME */
+ if (genMinusDec (ic) == TRUE)
+ goto release;
+
+ }
+
+ size = getDataSize(pushResult ? IC_LEFT(ic) : IC_RESULT(ic));
+
+ if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
+ CLRC;
+ }
+ else{
+ lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
+ lit = - (long)lit;
+ }
+
+
+ /* if literal, add a,#-lit, else normal subb */
+ while (size--) {
+ MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE));
+ if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
+ emitcode("subb","a,%s",
+ aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ else{
+ /* first add without previous c */
+ if(!offset)
+ emitcode("add","a,#0x%02x",
+ (unsigned int)(lit & 0x0FFL));
+ else
+ emitcode("addc","a,#0x%02x",
+ (unsigned int)((lit >> (offset*8)) & 0x0FFL));
+ }
+
+ if (pushResult)
+ {
+ emitcode("push", "acc");
+ }
+ else
+ {
+ aopPut(AOP(IC_RESULT(ic)),"a",offset);
+ }
+ offset++;
+ }
+
+ if (pushResult)
+ {
+ aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
+
+ size = getDataSize(IC_LEFT(ic));
+
+ while(size--)
+ {
+ emitcode("pop", "acc");
+ aopPut(AOP(IC_RESULT(ic)), "a", --offset);
+ }
+ }
+
+ 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);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMultbits :- multiplication of bits */
+/*-----------------------------------------------------------------*/
+static void genMultbits (operand *left,
+ operand *right,
+ operand *result)
+{
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("anl","c,%s",AOP(right)->aopu.aop_dir);
+ outBitC(result);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMultOneByte : 8 bit multiplication & division */
+/*-----------------------------------------------------------------*/
+static void genMultOneByte (operand *left,
+ operand *right,
+ operand *result)
+{
+ link *opetype = operandType(result);
+ char *l ;
+ symbol *lbl ;
+ int size,offset;
+
+ /* (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;
+ }
+
+ size = AOP_SIZE(result);
+ /* signed or unsigned */
+ emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE));
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("mul","ab");
+ /* if result size = 1, mul signed = mul unsigned */
+ aopPut(AOP(result),"a",0);
+ if (size > 1){
+ if (SPEC_USIGN(opetype)){
+ aopPut(AOP(result),"b",1);
+ if (size > 2)
+ /* for filling the MSBs */
+ emitcode("clr","a");
+ }
+ else{
+ emitcode("mov","a,b");
+
+ /* adjust the MSB if left or right neg */
+
+ /* if one literal */
+ if (AOP_TYPE(right) == AOP_LIT){
+ /* AND literal negative */
+ if((int) floatFromVal (AOP(right)->aopu.aop_lit) < 0){
+ /* adjust MSB (c==0 after mul) */
+ emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE));
+ }
+ }
+ else{
+ lbl = newiTempLabel(NULL);
+ emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("cjne","a,#0x80,%05d$", (lbl->key+100));
+ emitcode("","%05d$:",(lbl->key+100));
+ emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ lbl = newiTempLabel(NULL);
+ emitcode("jc","%05d$",(lbl->key+100));
+ emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE));
+ emitcode("","%05d$:",(lbl->key+100));
+ }
+
+ lbl = newiTempLabel(NULL);
+ emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE));
+ emitcode("cjne","a,#0x80,%05d$", (lbl->key+100));
+ emitcode("","%05d$:",(lbl->key+100));
+ emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE));
+ lbl = newiTempLabel(NULL);
+ emitcode("jc","%05d$",(lbl->key+100));
+ emitcode("subb","a,%s", aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("","%05d$:",(lbl->key+100));
+
+ aopPut(AOP(result),"a",1);
+ if(size > 2){
+ /* get the sign */
+ emitcode("rlc","a");
+ emitcode("subb","a,acc");
+ }
+ }
+ size -= 2;
+ offset = 2;
+ if (size > 0)
+ while (size--)
+ aopPut(AOP(result),"a",offset++);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 */
+ AOP_OP_3(ic);
+#if 0
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (right,ic,FALSE, TRUE);
+ aopOp (result,ic,TRUE, FALSE);
+#endif
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right)== AOP_CRY) {
+ genMultbits(left,right,result);
+ goto release ;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE(left) == 1 &&
+ AOP_SIZE(right) == 1 ) {
+ genMultOneByte(left,right,result);
+ goto release ;
+ }
+
+ /* should have been converted to function call */
+ assert(1) ;
+
+release :
+ freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivbits :- division of bits */
+/*-----------------------------------------------------------------*/
+static void genDivbits (operand *left,
+ operand *right,
+ operand *result)
+{
+
+ char *l;
+
+ /* the result must be bit */
+ emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+
+ MOVA(l);
+
+ emitcode("div","ab");
+ emitcode("rrc","a");
+ aopPut(AOP(result),"c",0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivOneByte : 8 bit division */
+/*-----------------------------------------------------------------*/
+static void genDivOneByte (operand *left,
+ operand *right,
+ operand *result)
+{
+ link *opetype = operandType(result);
+ char *l ;
+ symbol *lbl ;
+ int size,offset;
+
+ size = AOP_SIZE(result) - 1;
+ offset = 1;
+ /* signed or unsigned */
+ if (SPEC_USIGN(opetype)) {
+ /* unsigned is easy */
+ emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE));
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("div","ab");
+ aopPut(AOP(result),"a",0);
+ while (size--)
+ aopPut(AOP(result),zero,offset++);
+ return ;
+ }
+
+ /* signed is a little bit more difficult */
+
+ /* save the signs of the operands */
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,TRUE));
+ emitcode("push","acc"); /* save it on the stack */
+
+ /* now sign adjust for both left & right */
+ l = aopGet(AOP(right),0,FALSE,FALSE);
+ MOVA(l);
+ lbl = newiTempLabel(NULL);
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ emitcode("cpl","a");
+ emitcode("inc","a");
+ emitcode("","%05d$:",(lbl->key+100));
+ emitcode("mov","b,a");
+
+ /* sign adjust left side */
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+
+ lbl = newiTempLabel(NULL);
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ emitcode("cpl","a");
+ emitcode("inc","a");
+ emitcode("","%05d$:",(lbl->key+100));
+
+ /* now the division */
+ emitcode("div","ab");
+ /* we are interested in the lower order
+ only */
+ emitcode("mov","b,a");
+ lbl = newiTempLabel(NULL);
+ emitcode("pop","acc");
+ /* if there was an over flow we don't
+ adjust the sign of the result */
+ emitcode("jb","ov,%05d$",(lbl->key+100));
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ CLRC;
+ emitcode("clr","a");
+ emitcode("subb","a,b");
+ emitcode("mov","b,a");
+ emitcode("","%05d$:",(lbl->key+100));
+
+ /* now we are done */
+ aopPut(AOP(result),"b",0);
+ if(size > 0){
+ emitcode("mov","c,b.7");
+ emitcode("subb","a,acc");
+ }
+ while (size--)
+ aopPut(AOP(result),"a",offset++);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 */
+ AOP_OP_3(ic);
+#if 0
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (right,ic,FALSE, TRUE);
+ aopOp (result,ic,TRUE, FALSE);
+#endif
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right)== AOP_CRY) {
+ genDivbits(left,right,result);
+ goto release ;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE(left) == 1 &&
+ AOP_SIZE(right) == 1 ) {
+ genDivOneByte(left,right,result);
+ goto release ;
+ }
+
+ /* should have been converted to function call */
+ assert(1);
+release :
+ freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genModbits :- modulus of bits */
+/*-----------------------------------------------------------------*/
+static void genModbits (operand *left,
+ operand *right,
+ operand *result)
+{
+
+ char *l;
+
+ /* the result must be bit */
+ emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+
+ MOVA(l);
+
+ emitcode("div","ab");
+ emitcode("mov","a,b");
+ emitcode("rrc","a");
+ aopPut(AOP(result),"c",0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genModOneByte : 8 bit modulus */
+/*-----------------------------------------------------------------*/
+static void genModOneByte (operand *left,
+ operand *right,
+ operand *result)
+{
+ link *opetype = operandType(result);
+ char *l ;
+ symbol *lbl ;
+
+ /* signed or unsigned */
+ if (SPEC_USIGN(opetype)) {
+ /* unsigned is easy */
+ emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE));
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("div","ab");
+ aopPut(AOP(result),"b",0);
+ return ;
+ }
+
+ /* signed is a little bit more difficult */
+
+ /* save the signs of the operands */
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+
+ emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("push","acc"); /* save it on the stack */
+
+ /* now sign adjust for both left & right */
+ l = aopGet(AOP(right),0,FALSE,FALSE);
+ MOVA(l);
+
+ lbl = newiTempLabel(NULL);
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ emitcode("cpl","a");
+ emitcode("inc","a");
+ emitcode("","%05d$:",(lbl->key+100));
+ emitcode("mov","b,a");
+
+ /* sign adjust left side */
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+
+ lbl = newiTempLabel(NULL);
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ emitcode("cpl","a");
+ emitcode("inc","a");
+ emitcode("","%05d$:",(lbl->key+100));
+
+ /* now the multiplication */
+ emitcode("div","ab");
+ /* we are interested in the lower order
+ only */
+ lbl = newiTempLabel(NULL);
+ emitcode("pop","acc");
+ /* if there was an over flow we don't
+ adjust the sign of the result */
+ emitcode("jb","ov,%05d$",(lbl->key+100));
+ emitcode("jnb","acc.7,%05d$",(lbl->key+100));
+ CLRC ;
+ emitcode("clr","a");
+ emitcode("subb","a,b");
+ emitcode("mov","b,a");
+ emitcode("","%05d$:",(lbl->key+100));
+
+ /* now we are done */
+ aopPut(AOP(result),"b",0);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 */
+ AOP_OP_3(ic);
+#if 0
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (right,ic,FALSE, TRUE);
+ aopOp (result,ic,TRUE, FALSE);
+#endif
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right)== AOP_CRY) {
+ genModbits(left,right,result);
+ goto release ;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE(left) == 1 &&
+ AOP_SIZE(right) == 1 ) {
+ genModOneByte(left,right,result);
+ goto release ;
+ }
+
+ /* should have been converted to function call */
+ assert(1);
+
+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);
+ inst = ((strcmp(jval,"a") == 0 ? "jz" :
+ (strcmp(jval,"c") == 0 ? "jnc" : "jnb" )));
+ }
+ else {
+ /* false label is present */
+ jlbl = IC_FALSE(ic) ;
+ inst = ((strcmp(jval,"a") == 0 ? "jnz" :
+ (strcmp(jval,"c") == 0 ? "jc" : "jb" )));
+ }
+ if (strcmp(inst,"jb") == 0 || strcmp(inst,"jnb") == 0)
+ emitcode(inst,"%s,%05d$",jval,(tlbl->key+100));
+ else
+ emitcode(inst,"%05d$",tlbl->key+100);
+ emitcode("ljmp","%05d$",jlbl->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+
+ /* 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)
+{
+ int size, offset = 0 ;
+ unsigned long lit = 0L;
+ bool swappedOps = FALSE;
+
+ D(emitcode(";", "genCmp"););
+
+#if 0
+ /* If left if lit and right isn't, swap 'em. */
+ if (AOP_TYPE(left) == AOP_LIT &&
+ AOP_TYPE(right) != AOP_LIT)
+ {
+ operand *tmp = left;
+ left = right;
+ right = tmp;
+ D(emitcode(";", "kevin literal hack"););
+ swappedOps = !swappedOps;
+ }
+
+ if (AOP_NEEDSACC(right))
+ {
+ if (AOP_NEEDSACC(left))
+ {
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "both CMP operands need ACC!");
+ exit(-1);
+ }
+ else
+ {
+ operand *tmp = left;
+ left = right;
+ right = tmp;
+ D(emitcode(";", "kevin ACC hack"););
+ swappedOps = !swappedOps;
+ }
+ }
+#endif
+
+ /* if left & right are bit variables */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right) == AOP_CRY ) {
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ emitcode("anl","c,/%s",AOP(left)->aopu.aop_dir);
+ } else {
+ /* subtract right from left if at the
+ end the carry flag is set then we know that
+ left is greater than right */
+ size = max(AOP_SIZE(left),AOP_SIZE(right));
+
+ /* if unsigned char cmp with lit, do cjne left,#right,zz */
+ if((size == 1) && !sign &&
+ (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
+ symbol *lbl = newiTempLabel(NULL);
+ emitcode("cjne","%s,%s,%05d$",
+ aopGet(AOP(left),offset,FALSE,FALSE),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ lbl->key+100);
+ emitcode("","%05d$:",lbl->key+100);
+ } else {
+ 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{
+ MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE,FALSE));
+ if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx){
+ genIfxJump (ifx,"acc.7");
+ return;
+ }
+ else
+ emitcode("rlc","a");
+ }
+ goto release;
+ }
+ }
+ CLRC;
+ while (size--)
+ {
+ emitcode(";", "genCmp #1: %d/%d/%d", size, sign, offset);
+ MOVA(aopGet(AOP(left),offset,FALSE,FALSE));
+ emitcode(";", "genCmp #2");
+ if (sign && (size == 0))
+ {
+ emitcode(";", "genCmp #3");
+ emitcode("xrl","a,#0x80");
+ if (AOP_TYPE(right) == AOP_LIT)
+ {
+ unsigned long lit = (unsigned long)
+ floatFromVal(AOP(right)->aopu.aop_lit);
+ emitcode(";", "genCmp #3.1");
+ emitcode("subb","a,#0x%02x",
+ 0x80 ^ (unsigned int)((lit >> (offset*8)) & 0x0FFL));
+ }
+ else
+ {
+ emitcode(";", "genCmp #3.2");
+ if (AOP_NEEDSACC(right))
+ {
+ emitcode("push", "acc");
+ }
+ emitcode("mov","b,%s",aopGet(AOP(right),offset++,
+ FALSE,FALSE));
+ emitcode("xrl","b,#0x80");
+ if (AOP_NEEDSACC(right))
+ {
+ emitcode("pop", "acc");
+ }
+ emitcode("subb","a,b");
+ }
+ }
+ else
+ {
+ const char *s;
+
+ emitcode(";", "genCmp #4");
+ if (AOP_NEEDSACC(right))
+ {
+ /* Yuck!! */
+ emitcode(";", "genCmp #4.1");
+ emitcode("xch", "a, b");
+ MOVA(aopGet(AOP(right),offset++,FALSE,FALSE));
+ emitcode("xch", "a, b");
+ s = "b";
+ }
+ else
+ {
+ emitcode(";", "genCmp #4.2");
+ s = aopGet(AOP(right),offset++,FALSE,FALSE);
+ }
+
+ emitcode("subb","a,%s",s);
+ }
+ }
+ }
+ }
+
+release:
+ if (swappedOps)
+ {
+ D(emitcode(";","kevHack: flip carry."););
+ emitcode("cpl", "c");
+ }
+
+ if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
+ outBitC(result);
+ } else {
+ /* if the result is used in the next
+ ifx conditional branch then generate
+ code a little differently */
+ if (ifx )
+ genIfxJump (ifx,"c");
+ else
+ outBitC(result);
+ /* leave the result in acc */
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpGt :- greater than comparison */
+/*-----------------------------------------------------------------*/
+static void genCmpGt (iCode *ic, iCode *ifx)
+{
+ operand *left, *right, *result;
+ link *letype , *retype;
+ int sign ;
+
+ D(emitcode(";", "genCmpGt "););
+
+ left = IC_LEFT(ic);
+ right= IC_RIGHT(ic);
+ result = IC_RESULT(ic);
+
+ letype = getSpec(operandType(left));
+ retype =getSpec(operandType(right));
+ sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
+ /* assign the amsops */
+ AOP_OP_3(ic);
+#if 0
+ aopOp (left,ic,FALSE, TRUE);
+ aopOp (right,ic,FALSE, FALSE);
+ aopOp (result,ic,TRUE, FALSE);
+#endif
+
+ genCmp(right, left, result, ifx, sign);
+
+ freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpLt - less than comparisons */
+/*-----------------------------------------------------------------*/
+static void genCmpLt (iCode *ic, iCode *ifx)
+{
+ operand *left, *right, *result;
+ link *letype , *retype;
+ int sign ;
+
+ D(emitcode(";", "genCmpLt "););
+
+ left = IC_LEFT(ic);
+ right= IC_RIGHT(ic);
+ result = IC_RESULT(ic);
+
+ letype = getSpec(operandType(left));
+ retype =getSpec(operandType(right));
+ sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
+
+ /* assign the amsops */
+ AOP_OP_3(ic);
+#if 0
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (right,ic,FALSE, TRUE);
+ aopOp (result,ic,TRUE, FALSE);
+#endif
+
+ genCmp(left, right, result, ifx, sign);
+
+ freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjneshort - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void gencjneshort(operand *left, operand *right, symbol *lbl)
+{
+ int size = max(AOP_SIZE(left),AOP_SIZE(right));
+ int offset = 0;
+ unsigned long lit = 0L;
+
+ D(emitcode(";", "gencjneshort"););
+
+ /* 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) ||
+ (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+ if(AOP_TYPE(right) == AOP_LIT)
+ lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
+
+ /* if the right side is a literal then anything goes */
+ if (AOP_TYPE(right) == AOP_LIT &&
+ AOP_TYPE(left) != AOP_DIR ) {
+ while (size--) {
+ char *l = aopGet(AOP(left), offset, FALSE, FALSE);
+ MOVA(l);
+ emitcode("cjne","a,%s,%05d$",
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ lbl->key+100);
+ offset++;
+ }
+ }
+
+ /* if the right side is in a register or in direct space or
+ if the left is a pointer register & right is not */
+ else if (AOP_TYPE(right) == AOP_REG ||
+ AOP_TYPE(right) == AOP_DIR ||
+ (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) ||
+ (IS_AOP_PREG(left) && !IS_AOP_PREG(right))) {
+ while (size--) {
+ MOVA(aopGet(AOP(left),offset,FALSE,FALSE));
+ if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
+ ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
+ emitcode("jnz","%05d$",lbl->key+100);
+ else
+ emitcode("cjne","a,%s,%05d$",
+ aopGet(AOP(right),offset,FALSE,TRUE),
+ lbl->key+100);
+ offset++;
+ }
+ } else {
+ /* right is a pointer reg need both a & b */
+ while(size--) {
+ char *l = aopGet(AOP(left),offset,FALSE,FALSE);
+ if(strcmp(l,"b"))
+ emitcode("mov","b,%s",l);
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("cjne","a,b,%05d$",lbl->key+100);
+ offset++;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* gencjne - compare and jump if not equal */
+/*-----------------------------------------------------------------*/
+static void gencjne(operand *left, operand *right, symbol *lbl)
+{
+ symbol *tlbl = newiTempLabel(NULL);
+
+ D(emitcode(";", "gencjne"););
+
+ gencjneshort(left, right, lbl);
+
+ emitcode("mov","a,%s",one);
+ emitcode("sjmp","%05d$",tlbl->key+100);
+ emitcode("","%05d$:",lbl->key+100);
+ emitcode("clr","a");
+ emitcode("","%05d$:",tlbl->key+100);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpEq - generates code for equal to */
+/*-----------------------------------------------------------------*/
+static void genCmpEq (iCode *ic, iCode *ifx)
+{
+ operand *left, *right, *result;
+
+ D(emitcode(";", "genCmpEq "););
+
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+#if 0
+ aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
+#endif
+
+ /* 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) ||
+ (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) {
+ operand *t = IC_RIGHT(ic);
+ IC_RIGHT(ic) = IC_LEFT(ic);
+ IC_LEFT(ic) = t;
+ }
+
+ if(ifx && !AOP_SIZE(result)){
+ symbol *tlbl;
+ /* if they are both bit variables */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
+ if(AOP_TYPE(right) == AOP_LIT){
+ unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
+ if(lit == 0L){
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("cpl","c");
+ } else if(lit == 1L) {
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ } else {
+ emitcode("clr","c");
+ }
+ /* AOP_TYPE(right) == AOP_CRY */
+ } else {
+ symbol *lbl = newiTempLabel(NULL);
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100));
+ emitcode("cpl","c");
+ emitcode("","%05d$:",(lbl->key+100));
+ }
+ /* if true label then we jump if condition
+ supplied is true */
+ tlbl = newiTempLabel(NULL);
+ if ( IC_TRUE(ifx) ) {
+ emitcode("jnc","%05d$",tlbl->key+100);
+ emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100);
+ } else {
+ emitcode("jc","%05d$",tlbl->key+100);
+ emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100);
+ }
+ emitcode("","%05d$:",tlbl->key+100);
+ } else {
+ tlbl = newiTempLabel(NULL);
+ gencjneshort(left, right, tlbl);
+ if ( IC_TRUE(ifx) ) {
+ emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ } else {
+ symbol *lbl = newiTempLabel(NULL);
+ emitcode("sjmp","%05d$",lbl->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100);
+ emitcode("","%05d$:",lbl->key+100);
+ }
+ }
+ /* mark the icode as generated */
+ ifx->generated = 1;
+ goto release ;
+ }
+
+ /* if they are both bit variables */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
+ if(AOP_TYPE(right) == AOP_LIT){
+ unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
+ if(lit == 0L){
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("cpl","c");
+ } else if(lit == 1L) {
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ } else {
+ emitcode("clr","c");
+ }
+ /* AOP_TYPE(right) == AOP_CRY */
+ } else {
+ symbol *lbl = newiTempLabel(NULL);
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100));
+ emitcode("cpl","c");
+ emitcode("","%05d$:",(lbl->key+100));
+ }
+ /* c = 1 if egal */
+ if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)){
+ outBitC(result);
+ goto release ;
+ }
+ if (ifx) {
+ genIfxJump (ifx,"c");
+ goto release ;
+ }
+ /* if the result is used in an arithmetic operation
+ then put the result in place */
+ outBitC(result);
+ } else {
+ gencjne(left,right,newiTempLabel(NULL));
+ if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
+ aopPut(AOP(result),"a",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);
+ /* leave the result in acc */
+ }
+
+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;
+}
+/*-----------------------------------------------------------------*/
+/* genAndOp - for && operation */
+/*-----------------------------------------------------------------*/
+static void genAndOp (iCode *ic)
+{
+ operand *left,*right, *result;
+ symbol *tlbl;
+
+ D(emitcode(";", "genAndOp "););
+
+ /* note here that && operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+#if 0
+ aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
+#endif
+
+ /* if both are bit variables */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right) == AOP_CRY ) {
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("anl","c,%s",AOP(right)->aopu.aop_dir);
+ outBitC(result);
+ } else {
+ tlbl = newiTempLabel(NULL);
+ toBoolean(left);
+ emitcode("jz","%05d$",tlbl->key+100);
+ toBoolean(right);
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitAcc(result);
+ }
+
+ 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;
+
+ 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 */
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+#if 0
+ aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
+#endif
+
+ /* if both are bit variables */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right) == AOP_CRY ) {
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("orl","c,%s",AOP(right)->aopu.aop_dir);
+ outBitC(result);
+ } else {
+ tlbl = newiTempLabel(NULL);
+ toBoolean(left);
+ emitcode("jnz","%05d$",tlbl->key+100);
+ toBoolean(right);
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitAcc(result);
+ }
+
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* continueIfTrue - */
+/*-----------------------------------------------------------------*/
+static void continueIfTrue (iCode *ic)
+{
+ if(IC_TRUE(ic))
+ emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100);
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpIfTrue - */
+/*-----------------------------------------------------------------*/
+static void jumpIfTrue (iCode *ic)
+{
+ if(!IC_TRUE(ic))
+ emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100);
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse - */
+/*-----------------------------------------------------------------*/
+static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
+{
+ // ugly but optimized by peephole
+ if(IC_TRUE(ic)){
+ symbol *nlbl = newiTempLabel(NULL);
+ emitcode("sjmp","%05d$",nlbl->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100);
+ emitcode("","%05d$:",nlbl->key+100);
+ }
+ else{
+ emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAnd - code for and */
+/*-----------------------------------------------------------------*/
+static void genAnd (iCode *ic, iCode *ifx)
+{
+ operand *left, *right, *result;
+ int size, offset=0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+ char buffer[10];
+
+ D(emitcode(";", "genAnd "););
+
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+#if 0
+ aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
+#endif
+
+#ifdef DEBUG_TYPE
+ emitcode("","; Type res[%d] = l[%d]&r[%d]",
+ AOP_TYPE(result),
+ AOP_TYPE(left), AOP_TYPE(right));
+ emitcode("","; Size res[%d] = l[%d]&r[%d]",
+ AOP_SIZE(result),
+ AOP_SIZE(left), AOP_SIZE(right));
+#endif
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
+ AOP_NEEDSACC(left)) {
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if(sameRegs(AOP(result),AOP(right))){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE(right) == AOP_CRY &&
+ AOP_TYPE(left) != AOP_CRY){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+ if(AOP_TYPE(right) == AOP_LIT)
+ lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
+
+ size = AOP_SIZE(result);
+
+ // if(bit & yy)
+ // result = bit & yy;
+ if (AOP_TYPE(left) == AOP_CRY){
+ // c = bit & literal;
+ if(AOP_TYPE(right) == AOP_LIT){
+ if(lit & 1) {
+ if(size && sameRegs(AOP(result),AOP(left)))
+ // no change
+ goto release;
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ } else {
+ // bit(result) = 0;
+ if(size && (AOP_TYPE(result) == AOP_CRY)){
+ emitcode("clr","%s",AOP(result)->aopu.aop_dir);
+ goto release;
+ }
+ if((AOP_TYPE(result) == AOP_CRY) && ifx){
+ jumpIfTrue(ifx);
+ goto release;
+ }
+ emitcode("clr","c");
+ }
+ } else {
+ if (AOP_TYPE(right) == AOP_CRY){
+ // c = bit & bit;
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ emitcode("anl","c,%s",AOP(left)->aopu.aop_dir);
+ } else {
+ // c = bit & val;
+ MOVA(aopGet(AOP(right),0,FALSE,FALSE));
+ // c = lsb
+ emitcode("rrc","a");
+ emitcode("anl","c,%s",AOP(left)->aopu.aop_dir);
+ }
+ }
+ // bit = c
+ // val = c
+ if(size)
+ outBitC(result);
+ // if(bit & ...)
+ else if((AOP_TYPE(result) == AOP_CRY) && ifx)
+ genIfxJump(ifx, "c");
+ goto release ;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if((AOP_TYPE(right) == AOP_LIT) &&
+ (AOP_TYPE(result) == AOP_CRY) &&
+ (AOP_TYPE(left) != AOP_CRY)){
+ int posbit = isLiteralBit(lit);
+ /* left & 2^n */
+ if(posbit){
+ posbit--;
+ MOVA(aopGet(AOP(left),posbit>>3,FALSE,FALSE));
+ // bit = left & 2^n
+ if(size)
+ emitcode("mov","c,acc.%d",posbit&0x07);
+ // if(left & 2^n)
+ else{
+ if(ifx){
+ sprintf(buffer,"acc.%d",posbit&0x07);
+ genIfxJump(ifx, buffer);
+ }
+ goto release;
+ }
+ } else {
+ symbol *tlbl = newiTempLabel(NULL);
+ int sizel = AOP_SIZE(left);
+ if(size)
+ emitcode("setb","c");
+ while(sizel--){
+ if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
+ MOVA( aopGet(AOP(left),offset,FALSE,FALSE));
+ // byte == 2^n ?
+ if((posbit = isLiteralBit(bytelit)) != 0)
+ emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
+ else{
+ if(bytelit != 0x0FFL)
+ emitcode("anl","a,%s",
+ aopGet(AOP(right),offset,FALSE,TRUE));
+ emitcode("jnz","%05d$",tlbl->key+100);
+ }
+ }
+ offset++;
+ }
+ // bit = left & literal
+ if(size){
+ emitcode("clr","c");
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ // if(left & literal)
+ else{
+ if(ifx)
+ jmpTrueOrFalse(ifx, tlbl);
+ goto release ;
+ }
+ }
+ outBitC(result);
+ goto release ;
+ }
+
+ /* if left is same as result */
+ if(sameRegs(AOP(result),AOP(left))){
+ for(;size--; offset++) {
+ if(AOP_TYPE(right) == AOP_LIT){
+ if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
+ continue;
+ else
+ if (bytelit == 0)
+ aopPut(AOP(result),zero,offset);
+ else
+ if (IS_AOP_PREG(result)) {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+ } else
+ emitcode("anl","%s,%s",
+ aopGet(AOP(left),offset,FALSE,TRUE),
+ aopGet(AOP(right),offset,FALSE,FALSE));
+ } else {
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ if (IS_AOP_PREG(result)) {
+ emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+
+ } else
+ emitcode("anl","%s,a",
+ aopGet(AOP(left),offset,FALSE,TRUE));
+ }
+ }
+ }
+ } else {
+ // left & result in different registers
+ if(AOP_TYPE(result) == AOP_CRY){
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left & right)
+ symbol *tlbl = newiTempLabel(NULL);
+ int sizer = min(AOP_SIZE(left),AOP_SIZE(right));
+ if(size)
+ emitcode("setb","c");
+ while(sizer--){
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("anl","a,%s",
+ aopGet(AOP(left),offset,FALSE,FALSE));
+ emitcode("jnz","%05d$",tlbl->key+100);
+ offset++;
+ }
+ if(size){
+ CLRC;
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitC(result);
+ } else if(ifx)
+ jmpTrueOrFalse(ifx, tlbl);
+ } else {
+ for(;(size--);offset++) {
+ // normal case
+ // result = left & right
+ if(AOP_TYPE(right) == AOP_LIT){
+ if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
+ aopPut(AOP(result),
+ aopGet(AOP(left),offset,FALSE,FALSE),
+ offset);
+ continue;
+ } else if(bytelit == 0){
+ aopPut(AOP(result),zero,offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("anl","a,%s",
+ aopGet(AOP(left),offset,FALSE,FALSE));
+ }
+ aopPut(AOP(result),"a",offset);
+ }
+ }
+ }
+
+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 "););
+
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+ #if 0
+ aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
+ #endif
+
+#ifdef DEBUG_TYPE
+ emitcode("","; Type res[%d] = l[%d]&r[%d]",
+ AOP_TYPE(result),
+ AOP_TYPE(left), AOP_TYPE(right));
+ emitcode("","; Size res[%d] = l[%d]&r[%d]",
+ AOP_SIZE(result),
+ AOP_SIZE(left), AOP_SIZE(right));
+#endif
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
+ AOP_NEEDSACC(left)) {
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if(sameRegs(AOP(result),AOP(right))){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE(right) == AOP_CRY &&
+ AOP_TYPE(left) != AOP_CRY){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+ if(AOP_TYPE(right) == AOP_LIT)
+ lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
+
+ size = AOP_SIZE(result);
+
+ // if(bit | yy)
+ // xx = bit | yy;
+ if (AOP_TYPE(left) == AOP_CRY){
+ if(AOP_TYPE(right) == AOP_LIT){
+ // c = bit & literal;
+ if(lit){
+ // lit != 0 => result = 1
+ if(AOP_TYPE(result) == AOP_CRY){
+ if(size)
+ emitcode("setb","%s",AOP(result)->aopu.aop_dir);
+ else if(ifx)
+ continueIfTrue(ifx);
+ goto release;
+ }
+ emitcode("setb","c");
+ } else {
+ // lit == 0 => result = left
+ if(size && sameRegs(AOP(result),AOP(left)))
+ goto release;
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ }
+ } else {
+ if (AOP_TYPE(right) == AOP_CRY){
+ // c = bit | bit;
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ emitcode("orl","c,%s",AOP(left)->aopu.aop_dir);
+ }
+ else{
+ // c = bit | val;
+ symbol *tlbl = newiTempLabel(NULL);
+ if(!((AOP_TYPE(result) == AOP_CRY) && ifx))
+ emitcode("setb","c");
+ emitcode("jb","%s,%05d$",
+ AOP(left)->aopu.aop_dir,tlbl->key+100);
+ toBoolean(right);
+ emitcode("jnz","%05d$",tlbl->key+100);
+ if((AOP_TYPE(result) == AOP_CRY) && ifx){
+ jmpTrueOrFalse(ifx, tlbl);
+ goto release;
+ } else {
+ CLRC;
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ }
+ }
+ // bit = c
+ // val = c
+ if(size)
+ outBitC(result);
+ // if(bit | ...)
+ else if((AOP_TYPE(result) == AOP_CRY) && ifx)
+ genIfxJump(ifx, "c");
+ goto release ;
+ }
+
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
+ if((AOP_TYPE(right) == AOP_LIT) &&
+ (AOP_TYPE(result) == AOP_CRY) &&
+ (AOP_TYPE(left) != AOP_CRY)){
+ if(lit){
+ // result = 1
+ if(size)
+ emitcode("setb","%s",AOP(result)->aopu.aop_dir);
+ else
+ continueIfTrue(ifx);
+ goto release;
+ } else {
+ // lit = 0, result = boolean(left)
+ if(size)
+ emitcode("setb","c");
+ toBoolean(right);
+ if(size){
+ symbol *tlbl = newiTempLabel(NULL);
+ emitcode("jnz","%05d$",tlbl->key+100);
+ CLRC;
+ emitcode("","%05d$:",tlbl->key+100);
+ } else {
+ genIfxJump (ifx,"a");
+ goto release;
+ }
+ }
+ outBitC(result);
+ goto release ;
+ }
+
+ /* if left is same as result */
+ if(sameRegs(AOP(result),AOP(left))){
+ for(;size--; offset++) {
+ if(AOP_TYPE(right) == AOP_LIT){
+ if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ if (IS_AOP_PREG(left)) {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+ } else
+ emitcode("orl","%s,%s",
+ aopGet(AOP(left),offset,FALSE,TRUE),
+ aopGet(AOP(right),offset,FALSE,FALSE));
+ } else {
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ if (IS_AOP_PREG(left)) {
+ emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+ } else
+ emitcode("orl","%s,a",
+ aopGet(AOP(left),offset,FALSE,TRUE));
+ }
+ }
+ }
+ } else {
+ // left & result in different registers
+ if(AOP_TYPE(result) == AOP_CRY){
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left | right)
+ symbol *tlbl = newiTempLabel(NULL);
+ int sizer = max(AOP_SIZE(left),AOP_SIZE(right));
+ if(size)
+ emitcode("setb","c");
+ while(sizer--){
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("orl","a,%s",
+ aopGet(AOP(left),offset,FALSE,FALSE));
+ emitcode("jnz","%05d$",tlbl->key+100);
+ offset++;
+ }
+ if(size){
+ CLRC;
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitC(result);
+ } else if(ifx)
+ jmpTrueOrFalse(ifx, tlbl);
+ } else for(;(size--);offset++){
+ // normal case
+ // result = left & right
+ if(AOP_TYPE(right) == AOP_LIT){
+ if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
+ aopPut(AOP(result),
+ aopGet(AOP(left),offset,FALSE,FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("orl","a,%s",
+ aopGet(AOP(left),offset,FALSE,FALSE));
+ }
+ aopPut(AOP(result),"a",offset);
+ }
+ }
+
+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 "););
+
+ AOP_OP_3(ic);
+ AOP_SET_LOCALS(ic);
+#if 0
+ aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
+ aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
+ aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
+#endif
+
+#ifdef DEBUG_TYPE
+ emitcode("","; Type res[%d] = l[%d]&r[%d]",
+ AOP_TYPE(result),
+ AOP_TYPE(left), AOP_TYPE(right));
+ emitcode("","; Size res[%d] = l[%d]&r[%d]",
+ AOP_SIZE(result),
+ AOP_SIZE(left), AOP_SIZE(right));
+#endif
+
+ /* if left is a literal & right is not ||
+ if left needs acc & right does not */
+ if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
+ (AOP_NEEDSACC(left) && !AOP_NEEDSACC(right))) {
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if(sameRegs(AOP(result),AOP(right))){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE(right) == AOP_CRY &&
+ AOP_TYPE(left) != AOP_CRY){
+ operand *tmp = right ;
+ right = left;
+ left = tmp;
+ }
+ if(AOP_TYPE(right) == AOP_LIT)
+ lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
+
+ size = AOP_SIZE(result);
+
+ // if(bit ^ yy)
+ // xx = bit ^ yy;
+ if (AOP_TYPE(left) == AOP_CRY){
+ if(AOP_TYPE(right) == AOP_LIT){
+ // c = bit & literal;
+ if(lit>>1){
+ // lit>>1 != 0 => result = 1
+ if(AOP_TYPE(result) == AOP_CRY){
+ if(size)
+ emitcode("setb","%s",AOP(result)->aopu.aop_dir);
+ else if(ifx)
+ continueIfTrue(ifx);
+ goto release;
+ }
+ emitcode("setb","c");
+ } else{
+ // lit == (0 or 1)
+ if(lit == 0){
+ // lit == 0, result = left
+ if(size && sameRegs(AOP(result),AOP(left)))
+ goto release;
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ } else{
+ // lit == 1, result = not(left)
+ if(size && sameRegs(AOP(result),AOP(left))){
+ emitcode("cpl","%s",AOP(result)->aopu.aop_dir);
+ goto release;
+ } else {
+ emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
+ emitcode("cpl","c");
+ }
+ }
+ }
+
+ } else {
+ // right != literal
+ symbol *tlbl = newiTempLabel(NULL);
+ if (AOP_TYPE(right) == AOP_CRY){
+ // c = bit ^ bit;
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ }
+ else{
+ int sizer = AOP_SIZE(right);
+ // c = bit ^ val
+ // if val>>1 != 0, result = 1
+ emitcode("setb","c");
+ while(sizer){
+ MOVA(aopGet(AOP(right),sizer-1,FALSE,FALSE));
+ if(sizer == 1)
+ // test the msb of the lsb
+ emitcode("anl","a,#0xfe");
+ emitcode("jnz","%05d$",tlbl->key+100);
+ sizer--;
+ }
+ // val = (0,1)
+ emitcode("rrc","a");
+ }
+ emitcode("jnb","%s,%05d$",AOP(left)->aopu.aop_dir,(tlbl->key+100));
+ emitcode("cpl","c");
+ emitcode("","%05d$:",(tlbl->key+100));
+ }
+ // bit = c
+ // val = c
+ if(size)
+ outBitC(result);
+ // if(bit | ...)
+ else if((AOP_TYPE(result) == AOP_CRY) && ifx)
+ genIfxJump(ifx, "c");
+ goto release ;
+ }
+
+ if(sameRegs(AOP(result),AOP(left))){
+ /* if left is same as result */
+ for(;size--; offset++) {
+ if(AOP_TYPE(right) == AOP_LIT){
+ if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ if (IS_AOP_PREG(left)) {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+ } else
+ emitcode("xrl","%s,%s",
+ aopGet(AOP(left),offset,FALSE,TRUE),
+ aopGet(AOP(right),offset,FALSE,FALSE));
+ } else {
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ if (IS_AOP_PREG(left)) {
+ emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE));
+ aopPut(AOP(result),"a",offset);
+ } else
+ emitcode("xrl","%s,a",
+ aopGet(AOP(left),offset,FALSE,TRUE));
+ }
+ }
+ }
+ } else {
+ // left & result in different registers
+ if(AOP_TYPE(result) == AOP_CRY){
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left ^ right)
+ symbol *tlbl = newiTempLabel(NULL);
+ int sizer = max(AOP_SIZE(left),AOP_SIZE(right));
+ if(size)
+ emitcode("setb","c");
+ while(sizer--){
+ if((AOP_TYPE(right) == AOP_LIT) &&
+ (((lit >> (offset*8)) & 0x0FFL) == 0x00L)){
+ MOVA(aopGet(AOP(left),offset,FALSE,FALSE));
+ } else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("xrl","a,%s",
+ aopGet(AOP(left),offset,FALSE,FALSE));
+ }
+ emitcode("jnz","%05d$",tlbl->key+100);
+ offset++;
+ }
+ if(size){
+ CLRC;
+ emitcode("","%05d$:",tlbl->key+100);
+ outBitC(result);
+ } else if(ifx)
+ jmpTrueOrFalse(ifx, tlbl);
+ } else for(;(size--);offset++){
+ // normal case
+ // result = left & right
+ if(AOP_TYPE(right) == AOP_LIT){
+ if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
+ aopPut(AOP(result),
+ aopGet(AOP(left),offset,FALSE,FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE(left) == AOP_ACC)
+ emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE));
+ else {
+ MOVA(aopGet(AOP(right),offset,FALSE,FALSE));
+ emitcode("xrl","a,%s",
+ aopGet(AOP(left),offset,FALSE,TRUE));
+ }
+ aopPut(AOP(result),"a",offset);
+ }
+ }
+
+release :
+ freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+static void genInline (iCode *ic)
+{
+ char buffer[MAX_INLINEASM];
+ char *bp = buffer;
+ char *bp1= buffer;
+
+ D(emitcode(";", "genInline "););
+
+ _G.inLine += (!options.asmpeep);
+ strcpy(buffer,IC_INLINE(ic));
+
+ /* emit each line as a code */
+ while (*bp) {
+ if (*bp == '\n') {
+ *bp++ = '\0';
+ emitcode(bp1,"");
+ bp1 = bp;
+ } else {
+ if (*bp == ':') {
+ bp++;
+ *bp = '\0';
+ bp++;
+ emitcode(bp1,"");
+ bp1 = bp;
+ } else
+ bp++;
+ }
+ }
+ if (bp1 != bp)
+ emitcode(bp1,"");
+ /* emitcode("",buffer); */
+ _G.inLine -= (!options.asmpeep);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void genRRC (iCode *ic)
+{
+ operand *left , *result ;
+ int size, offset = 0;
+ char *l;
+
+ D(emitcode(";", "genRRC "););
+
+ /* rotate right with carry */
+ left = IC_LEFT(ic);
+ result=IC_RESULT(ic);
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ /* move it to the result */
+ size = AOP_SIZE(result);
+ offset = size - 1 ;
+ CLRC;
+ while (size--) {
+ l = aopGet(AOP(left),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("rrc","a");
+ if (AOP_SIZE(result) > 1)
+ aopPut(AOP(result),"a",offset--);
+ }
+ /* now we need to put the carry into the
+ highest order byte of the result */
+ if (AOP_SIZE(result) > 1) {
+ l = aopGet(AOP(result),AOP_SIZE(result)-1,FALSE,FALSE);
+ MOVA(l);
+ }
+ emitcode("mov","acc.7,c");
+ aopPut(AOP(result),"a",AOP_SIZE(result)-1);
+ 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 *l;
+
+ D(emitcode(";", "genRLC "););
+
+ /* rotate right with carry */
+ left = IC_LEFT(ic);
+ result=IC_RESULT(ic);
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ /* move it to the result */
+ size = AOP_SIZE(result);
+ offset = 0 ;
+ if (size--) {
+ l = aopGet(AOP(left),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("add","a,acc");
+ if (AOP_SIZE(result) > 1)
+ aopPut(AOP(result),"a",offset++);
+ while (size--) {
+ l = aopGet(AOP(left),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("rlc","a");
+ if (AOP_SIZE(result) > 1)
+ aopPut(AOP(result),"a",offset++);
+ }
+ }
+ /* now we need to put the carry into the
+ highest order byte of the result */
+ if (AOP_SIZE(result) > 1) {
+ l = aopGet(AOP(result),0,FALSE,FALSE);
+ MOVA(l);
+ }
+ emitcode("mov","acc.0,c");
+ aopPut(AOP(result),"a",0);
+ 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;
+ left = IC_LEFT(ic);
+ result=IC_RESULT(ic);
+ aopOp (left,ic,FALSE, FALSE);
+ aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ D(emitcode(";", "genGetHbit "););
+
+ /* get the highest order byte into a */
+ MOVA(aopGet(AOP(left),AOP_SIZE(left) - 1,FALSE,FALSE));
+ if(AOP_TYPE(result) == AOP_CRY){
+ emitcode("rlc","a");
+ outBitC(result);
+ }
+ else{
+ emitcode("rl","a");
+ emitcode("anl","a,#0x01");
+ outAcc(result);
+ }
+
+
+ freeAsmop(left,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRol - rotate left accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void AccRol (int shCount)
+{
+ shCount &= 0x0007; // shCount : 0..7
+ switch(shCount){
+ case 0 :
+ break;
+ case 1 :
+ emitcode("rl","a");
+ break;
+ case 2 :
+ emitcode("rl","a");
+ emitcode("rl","a");
+ break;
+ case 3 :
+ emitcode("swap","a");
+ emitcode("rr","a");
+ break;
+ case 4 :
+ emitcode("swap","a");
+ break;
+ case 5 :
+ emitcode("swap","a");
+ emitcode("rl","a");
+ break;
+ case 6 :
+ emitcode("rr","a");
+ emitcode("rr","a");
+ break;
+ case 7 :
+ emitcode("rr","a");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccLsh - left shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void AccLsh (int shCount)
+{
+ if(shCount != 0){
+ if(shCount == 1)
+ emitcode("add","a,acc");
+ else
+ if(shCount == 2) {
+ emitcode("add","a,acc");
+ emitcode("add","a,acc");
+ } else {
+ /* rotate left accumulator */
+ AccRol(shCount);
+ /* and kill the lower order bits */
+ emitcode("anl","a,#0x%02x", SLMask[shCount]);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void AccRsh (int shCount)
+{
+ if(shCount != 0){
+ if(shCount == 1){
+ CLRC;
+ emitcode("rrc","a");
+ } else {
+ /* rotate right accumulator */
+ AccRol(8 - shCount);
+ /* and kill the higher order bits */
+ emitcode("anl","a,#0x%02x", SRMask[shCount]);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccSRsh - signed right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void AccSRsh (int shCount)
+{
+ symbol *tlbl ;
+ if(shCount != 0){
+ if(shCount == 1){
+ emitcode("mov","c,acc.7");
+ emitcode("rrc","a");
+ } else if(shCount == 2){
+ emitcode("mov","c,acc.7");
+ emitcode("rrc","a");
+ emitcode("mov","c,acc.7");
+ emitcode("rrc","a");
+ } else {
+ tlbl = newiTempLabel(NULL);
+ /* rotate right accumulator */
+ AccRol(8 - shCount);
+ /* and kill the higher order bits */
+ emitcode("anl","a,#0x%02x", SRMask[shCount]);
+ emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100);
+ emitcode("orl","a,#0x%02x",
+ (unsigned char)~SRMask[shCount]);
+ emitcode("","%05d$:",tlbl->key+100);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR1Left2Result - shift right one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void shiftR1Left2Result (operand *left, int offl,
+ operand *result, int offr,
+ int shCount, int sign)
+{
+ MOVA(aopGet(AOP(left),offl,FALSE,FALSE));
+ /* shift right accumulator */
+ if(sign)
+ AccSRsh(shCount);
+ else
+ AccRsh(shCount);
+ aopPut(AOP(result),"a",offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL1Left2Result - shift left one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void shiftL1Left2Result (operand *left, int offl,
+ operand *result, int offr, int shCount)
+{
+ char *l;
+ l = aopGet(AOP(left),offl,FALSE,FALSE);
+ MOVA(l);
+ /* shift left accumulator */
+ AccLsh(shCount);
+ aopPut(AOP(result),"a",offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* movLeft2Result - move byte from left to result */
+/*-----------------------------------------------------------------*/
+static void movLeft2Result (operand *left, int offl,
+ operand *result, int offr, int sign)
+{
+ char *l;
+ if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
+ l = aopGet(AOP(left),offl,FALSE,FALSE);
+
+ if (*l == '@' && (IS_AOP_PREG(result))) {
+ emitcode("mov","a,%s",l);
+ aopPut(AOP(result),"a",offr);
+ } else {
+ if(!sign)
+ aopPut(AOP(result),l,offr);
+ else{
+ /* MSB sign in acc.7 ! */
+ if(getDataSize(left) == offl+1){
+ emitcode("mov","a,%s",l);
+ aopPut(AOP(result),"a",offr);
+ }
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRrl1 - right rotate c->a:x->c by 1 */
+/*-----------------------------------------------------------------*/
+static void AccAXRrl1 (char *x)
+{
+ emitcode("rrc","a");
+ emitcode("xch","a,%s", x);
+ emitcode("rrc","a");
+ emitcode("xch","a,%s", x);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */
+/*-----------------------------------------------------------------*/
+static void AccAXLrl1 (char *x)
+{
+ emitcode("xch","a,%s",x);
+ emitcode("rlc","a");
+ emitcode("xch","a,%s",x);
+ emitcode("rlc","a");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh1 - left shift a:x<-0 by 1 */
+/*-----------------------------------------------------------------*/
+static void AccAXLsh1 (char *x)
+{
+ emitcode("xch","a,%s",x);
+ emitcode("add","a,acc");
+ emitcode("xch","a,%s",x);
+ emitcode("rlc","a");
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXLsh - left shift a:x by known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void AccAXLsh (char *x, int shCount)
+{
+ switch(shCount){
+ case 0 :
+ break;
+ case 1 :
+ AccAXLsh1(x);
+ break;
+ case 2 :
+ AccAXLsh1(x);
+ AccAXLsh1(x);
+ break;
+ case 3 :
+ case 4 :
+ case 5 : // AAAAABBB:CCCCCDDD
+ AccRol(shCount); // BBBAAAAA:CCCCCDDD
+ emitcode("anl","a,#0x%02x",
+ SLMask[shCount]); // BBB00000:CCCCCDDD
+ emitcode("xch","a,%s",x); // CCCCCDDD:BBB00000
+ AccRol(shCount); // DDDCCCCC:BBB00000
+ emitcode("xch","a,%s",x); // BBB00000:DDDCCCCC
+ emitcode("xrl","a,%s",x); // (BBB^DDD)CCCCC:DDDCCCCC
+ emitcode("xch","a,%s",x); // DDDCCCCC:(BBB^DDD)CCCCC
+ emitcode("anl","a,#0x%02x",
+ SLMask[shCount]); // DDD00000:(BBB^DDD)CCCCC
+ emitcode("xch","a,%s",x); // (BBB^DDD)CCCCC:DDD00000
+ emitcode("xrl","a,%s",x); // BBBCCCCC:DDD00000
+ break;
+ case 6 : // AAAAAABB:CCCCCCDD
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000000BB:CCCCCCDD
+ emitcode("mov","c,acc.0"); // c = B
+ emitcode("xch","a,%s",x); // CCCCCCDD:000000BB
+ AccAXRrl1(x); // BCCCCCCD:D000000B
+ AccAXRrl1(x); // BBCCCCCC:DD000000
+ break;
+ case 7 : // a:x <<= 7
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 0000000B:CCCCCCCD
+ emitcode("mov","c,acc.0"); // c = B
+ emitcode("xch","a,%s",x); // CCCCCCCD:0000000B
+ AccAXRrl1(x); // BCCCCCCC:D0000000
+ break;
+ default :
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRsh - right shift a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void AccAXRsh (char *x, int shCount)
+{
+ switch(shCount){
+ case 0 :
+ break;
+ case 1 :
+ CLRC;
+ AccAXRrl1(x); // 0->a:x
+ break;
+ case 2 :
+ CLRC;
+ AccAXRrl1(x); // 0->a:x
+ CLRC;
+ AccAXRrl1(x); // 0->a:x
+ break;
+ case 3 :
+ case 4 :
+ case 5 : // AAAAABBB:CCCCCDDD = a:x
+ AccRol(8 - shCount); // BBBAAAAA:DDDCCCCC
+ emitcode("xch","a,%s",x); // CCCCCDDD:BBBAAAAA
+ AccRol(8 - shCount); // DDDCCCCC:BBBAAAAA
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000CCCCC:BBBAAAAA
+ emitcode("xrl","a,%s",x); // BBB(CCCCC^AAAAA):BBBAAAAA
+ emitcode("xch","a,%s",x); // BBBAAAAA:BBB(CCCCC^AAAAA)
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA)
+ emitcode("xch","a,%s",x); // BBB(CCCCC^AAAAA):000AAAAA
+ emitcode("xrl","a,%s",x); // BBBCCCCC:000AAAAA
+ emitcode("xch","a,%s",x); // 000AAAAA:BBBCCCCC
+ break;
+ case 6 : // AABBBBBB:CCDDDDDD
+ emitcode("mov","c,acc.7");
+ AccAXLrl1(x); // ABBBBBBC:CDDDDDDA
+ AccAXLrl1(x); // BBBBBBCC:DDDDDDAA
+ emitcode("xch","a,%s",x); // DDDDDDAA:BBBBBBCC
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000000AA:BBBBBBCC
+ break;
+ case 7 : // ABBBBBBB:CDDDDDDD
+ emitcode("mov","c,acc.7"); // c = A
+ AccAXLrl1(x); // BBBBBBBC:DDDDDDDA
+ emitcode("xch","a,%s",x); // DDDDDDDA:BBBBBBCC
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 0000000A:BBBBBBBC
+ break;
+ default :
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccAXRshS - right shift signed a:x known count (0..7) */
+/*-----------------------------------------------------------------*/
+static void AccAXRshS (char *x, int shCount)
+{
+ symbol *tlbl ;
+ switch(shCount){
+ case 0 :
+ break;
+ case 1 :
+ emitcode("mov","c,acc.7");
+ AccAXRrl1(x); // s->a:x
+ break;
+ case 2 :
+ emitcode("mov","c,acc.7");
+ AccAXRrl1(x); // s->a:x
+ emitcode("mov","c,acc.7");
+ AccAXRrl1(x); // s->a:x
+ break;
+ case 3 :
+ case 4 :
+ case 5 : // AAAAABBB:CCCCCDDD = a:x
+ tlbl = newiTempLabel(NULL);
+ AccRol(8 - shCount); // BBBAAAAA:CCCCCDDD
+ emitcode("xch","a,%s",x); // CCCCCDDD:BBBAAAAA
+ AccRol(8 - shCount); // DDDCCCCC:BBBAAAAA
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000CCCCC:BBBAAAAA
+ emitcode("xrl","a,%s",x); // BBB(CCCCC^AAAAA):BBBAAAAA
+ emitcode("xch","a,%s",x); // BBBAAAAA:BBB(CCCCC^AAAAA)
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA)
+ emitcode("xch","a,%s",x); // BBB(CCCCC^AAAAA):000AAAAA
+ emitcode("xrl","a,%s",x); // BBBCCCCC:000AAAAA
+ emitcode("xch","a,%s",x); // 000SAAAA:BBBCCCCC
+ emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100);
+ emitcode("orl","a,#0x%02x",
+ (unsigned char)~SRMask[shCount]); // 111AAAAA:BBBCCCCC
+ emitcode("","%05d$:",tlbl->key+100);
+ break; // SSSSAAAA:BBBCCCCC
+ case 6 : // AABBBBBB:CCDDDDDD
+ tlbl = newiTempLabel(NULL);
+ emitcode("mov","c,acc.7");
+ AccAXLrl1(x); // ABBBBBBC:CDDDDDDA
+ AccAXLrl1(x); // BBBBBBCC:DDDDDDAA
+ emitcode("xch","a,%s",x); // DDDDDDAA:BBBBBBCC
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 000000AA:BBBBBBCC
+ emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100);
+ emitcode("orl","a,#0x%02x",
+ (unsigned char)~SRMask[shCount]); // 111111AA:BBBBBBCC
+ emitcode("","%05d$:",tlbl->key+100);
+ break;
+ case 7 : // ABBBBBBB:CDDDDDDD
+ tlbl = newiTempLabel(NULL);
+ emitcode("mov","c,acc.7"); // c = A
+ AccAXLrl1(x); // BBBBBBBC:DDDDDDDA
+ emitcode("xch","a,%s",x); // DDDDDDDA:BBBBBBCC
+ emitcode("anl","a,#0x%02x",
+ SRMask[shCount]); // 0000000A:BBBBBBBC
+ emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100);
+ emitcode("orl","a,#0x%02x",
+ (unsigned char)~SRMask[shCount]); // 1111111A:BBBBBBBC
+ emitcode("","%05d$:",tlbl->key+100);
+ break;
+ default :
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL2Left2Result - shift left two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void shiftL2Left2Result (operand *left, int offl,
+ operand *result, int offr, int shCount)
+{
+ if(sameRegs(AOP(result), AOP(left)) &&
+ ((offl + MSB16) == offr)){
+ /* don't crash result[offr] */
+ MOVA(aopGet(AOP(left),offl,FALSE,FALSE));
+ emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE));
+ } else {
+ movLeft2Result(left,offl, result, offr, 0);
+ MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE));
+ }
+ /* ax << shCount (x = lsb(result))*/
+ AccAXLsh( aopGet(AOP(result),offr,FALSE,FALSE) , shCount);
+ aopPut(AOP(result),"a",offr+MSB16);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* shiftR2Left2Result - shift right two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void shiftR2Left2Result (operand *left, int offl,
+ operand *result, int offr,
+ int shCount, int sign)
+{
+ if(sameRegs(AOP(result), AOP(left)) &&
+ ((offl + MSB16) == offr)){
+ /* don't crash result[offr] */
+ MOVA(aopGet(AOP(left),offl,FALSE,FALSE));
+ emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE));
+ } else {
+ movLeft2Result(left,offl, result, offr, 0);
+ MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE));
+ }
+ /* a:x >> shCount (x = lsb(result))*/
+ if(sign)
+ AccAXRshS( aopGet(AOP(result),offr,FALSE,FALSE) , shCount);
+ else
+ AccAXRsh( aopGet(AOP(result),offr,FALSE,FALSE) , shCount);
+ if(getDataSize(result) > 1)
+ aopPut(AOP(result),"a",offr+MSB16);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftLLeftOrResult - shift left one byte from left, or to result*/
+/*-----------------------------------------------------------------*/
+static void shiftLLeftOrResult (operand *left, int offl,
+ operand *result, int offr, int shCount)
+{
+ MOVA(aopGet(AOP(left),offl,FALSE,FALSE));
+ /* shift left accumulator */
+ AccLsh(shCount);
+ /* or with result */
+ emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE));
+ /* back to result */
+ aopPut(AOP(result),"a",offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRLeftOrResult - shift right one byte from left,or to result*/
+/*-----------------------------------------------------------------*/
+static void shiftRLeftOrResult (operand *left, int offl,
+ operand *result, int offr, int shCount)
+{
+ MOVA(aopGet(AOP(left),offl,FALSE,FALSE));
+ /* shift right accumulator */
+ AccRsh(shCount);
+ /* or with result */
+ emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE));
+ /* back to result */
+ aopPut(AOP(result),"a",offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshOne - left shift a one byte quantity by known count */
+/*-----------------------------------------------------------------*/
+static void genlshOne (operand *result, operand *left, int shCount)
+{
+ D(emitcode(";", "genlshOne "););
+ shiftL1Left2Result(left, LSB, result, LSB, shCount);
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshTwo - left shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void genlshTwo (operand *result,operand *left, int shCount)
+{
+ int size;
+
+ D(emitcode(";", "genlshTwo "););
+
+ size = getDataSize(result);
+
+ /* if shCount >= 8 */
+ if (shCount >= 8) {
+ shCount -= 8 ;
+
+ if (size > 1){
+ if (shCount)
+ shiftL1Left2Result(left, LSB, result, MSB16, shCount);
+ else
+ movLeft2Result(left, LSB, result, MSB16, 0);
+ }
+ aopPut(AOP(result),zero,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);
+
+ if(size >= LSB+offr){
+ l = aopGet(AOP(left),LSB,FALSE,FALSE);
+ MOVA(l);
+ emitcode("add","a,acc");
+ if (sameRegs(AOP(left),AOP(result)) &&
+ size >= MSB16+offr && offr != LSB )
+ emitcode("xch","a,%s",
+ aopGet(AOP(left),LSB+offr,FALSE,FALSE));
+ else
+ aopPut(AOP(result),"a",LSB+offr);
+ }
+
+ if(size >= MSB16+offr){
+ if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB16+offr && offr != LSB) ) {
+ l = aopGet(AOP(left),MSB16,FALSE,FALSE);
+ MOVA(l);
+ }
+ emitcode("rlc","a");
+ if (sameRegs(AOP(left),AOP(result)) &&
+ size >= MSB24+offr && offr != LSB)
+ emitcode("xch","a,%s",
+ aopGet(AOP(left),MSB16+offr,FALSE,FALSE));
+ else
+ aopPut(AOP(result),"a",MSB16+offr);
+ }
+
+ if(size >= MSB24+offr){
+ if (!(sameRegs(AOP(left),AOP(left)) && size >= MSB24+offr && offr != LSB)) {
+ l = aopGet(AOP(left),MSB24,FALSE,FALSE);
+ MOVA(l);
+ }
+ emitcode("rlc","a");
+ if (sameRegs(AOP(left),AOP(result)) &&
+ size >= MSB32+offr && offr != LSB )
+ emitcode("xch","a,%s",
+ aopGet(AOP(left),MSB24+offr,FALSE,FALSE));
+ else
+ aopPut(AOP(result),"a",MSB24+offr);
+ }
+
+ if(size > MSB32+offr){
+ if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB32+offr && offr != LSB)) {
+ l = aopGet(AOP(left),MSB32,FALSE,FALSE);
+ MOVA(l);
+ }
+ emitcode("rlc","a");
+ aopPut(AOP(result),"a",MSB32+offr);
+ }
+ if(offr != LSB)
+ aopPut(AOP(result),zero,LSB);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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);
+
+ /* 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);
+ aopPut(AOP(result),zero,LSB);
+ aopPut(AOP(result),zero,MSB16);
+ aopPut(AOP(result),zero,MSB32);
+ 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);
+ }
+ aopPut(AOP(result),zero,MSB16);
+ aopPut(AOP(result),zero,LSB);
+ 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);
+ aopPut(AOP(result),zero,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);
+ aopPut(AOP(result),zero,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 (%d)", shCount););
+
+ freeAsmop(right,NULL,ic,TRUE);
+
+ aopOp(left,ic,FALSE, FALSE);
+ aopOp(result,ic,FALSE, TRUE);
+
+ size = getSize(operandType(result));
+
+#if VIEW_SIZE
+ emitcode("; shift left ","result %d, left %d",size,
+ AOP_SIZE(left));
+#endif
+
+ /* I suppose that the left size >= result size */
+ if(shCount == 0){
+ while(size--){
+ movLeft2Result(left, size, result, size, 0);
+ }
+ }
+
+ else if(shCount >= (size * 8))
+ while(size--)
+ aopPut(AOP(result),zero,size);
+ else{
+ switch (size) {
+ case 1:
+ genlshOne (result,left,shCount);
+ break;
+
+ case 2:
+ case 3: /* bug: this is for generic pointers, I bet. */
+ genlshTwo (result,left,shCount);
+ break;
+
+ case 4:
+ genlshFour (result,left,shCount);
+ 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;
+ char *l;
+ symbol *tlbl , *tlbl1;
+
+ D(emitcode(";", "genLeftShift "););
+
+ right = IC_RIGHT(ic);
+ left = IC_LEFT(ic);
+ result = IC_RESULT(ic);
+
+ aopOp(right,ic,FALSE, FALSE);
+
+ #if 0
+ /* 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 ;
+ }
+ #endif
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("inc","b");
+ freeAsmop (right,NULL,ic,TRUE);
+ aopOp(left,ic,FALSE, FALSE);
+ aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs(AOP(left),AOP(result)) &&
+ AOP_SIZE(result) > 1) {
+
+ size = AOP_SIZE(result);
+ offset=0;
+ while (size--) {
+ l = aopGet(AOP(left),offset,FALSE,TRUE);
+ if (*l == '@' && (IS_AOP_PREG(result))) {
+
+ emitcode("mov","a,%s",l);
+ aopPut(AOP(result),"a",offset);
+ } else
+ aopPut(AOP(result),l,offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel(NULL);
+ size = AOP_SIZE(result);
+ offset = 0 ;
+ tlbl1 = newiTempLabel(NULL);
+
+ /* if it is only one byte then */
+ if (size == 1) {
+ symbol *tlbl1 = newiTempLabel(NULL);
+
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ emitcode("add","a,acc");
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+ aopPut(AOP(result),"a",0);
+ goto release ;
+ }
+
+ reAdjustPreg(AOP(result));
+
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ l = aopGet(AOP(result),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("add","a,acc");
+ aopPut(AOP(result),"a",offset++);
+ while (--size) {
+ l = aopGet(AOP(result),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("rlc","a");
+ aopPut(AOP(result),"a",offset++);
+ }
+ reAdjustPreg(AOP(result));
+
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+release:
+ freeAsmop(left,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshOne - right shift a one byte quantity by known count */
+/*-----------------------------------------------------------------*/
+static void genrshOne (operand *result, operand *left,
+ int shCount, int sign)
+{
+ D(emitcode(";", "genrshOne"););
+ shiftR1Left2Result(left, LSB, result, LSB, shCount, sign);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshTwo - right shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void genrshTwo (operand *result,operand *left,
+ int shCount, int sign)
+{
+ D(emitcode(";", "genrshTwo"););
+
+ /* if shCount >= 8 */
+ if (shCount >= 8) {
+ shCount -= 8 ;
+ if (shCount)
+ shiftR1Left2Result(left, MSB16, result, LSB,
+ shCount, sign);
+ else
+ movLeft2Result(left, MSB16, result, LSB, sign);
+ addSign(result, MSB16, sign);
+ }
+
+ /* 1 <= shCount <= 7 */
+ else
+ shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRLong - shift right one long from left to result */
+/* offl = LSB or MSB16 */
+/*-----------------------------------------------------------------*/
+static void shiftRLong (operand *left, int offl,
+ operand *result, int sign)
+{
+ if(!sign)
+ emitcode("clr","c");
+ MOVA(aopGet(AOP(left),MSB32,FALSE,FALSE));
+ if(sign)
+ emitcode("mov","c,acc.7");
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",MSB32-offl);
+ if(offl == MSB16)
+ /* add sign of "a" */
+ addSign(result, MSB32, sign);
+
+ MOVA(aopGet(AOP(left),MSB24,FALSE,FALSE));
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",MSB24-offl);
+
+ MOVA(aopGet(AOP(left),MSB16,FALSE,FALSE));
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",MSB16-offl);
+
+ if(offl == LSB){
+ MOVA(aopGet(AOP(left),LSB,FALSE,FALSE));
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",LSB);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshFour - shift four byte by a known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void genrshFour (operand *result, operand *left,
+ int shCount, int sign)
+{
+ D(emitcode(";", "genrshFour"););
+
+ /* if shifting more that 3 bytes */
+ if(shCount >= 24 ) {
+ shCount -= 24;
+ if(shCount)
+ shiftR1Left2Result(left, MSB32, result, LSB, shCount, sign);
+ else
+ movLeft2Result(left, MSB32, result, LSB, sign);
+ addSign(result, MSB16, sign);
+ }
+ else if(shCount >= 16){
+ shCount -= 16;
+ if(shCount)
+ shiftR2Left2Result(left, MSB24, result, LSB, shCount, sign);
+ else{
+ movLeft2Result(left, MSB24, result, LSB, 0);
+ movLeft2Result(left, MSB32, result, MSB16, sign);
+ }
+ addSign(result, MSB24, sign);
+ }
+ else if(shCount >= 8){
+ shCount -= 8;
+ if(shCount == 1)
+ shiftRLong(left, MSB16, result, sign);
+ else if(shCount == 0){
+ movLeft2Result(left, MSB16, result, LSB, 0);
+ movLeft2Result(left, MSB24, result, MSB16, 0);
+ movLeft2Result(left, MSB32, result, MSB24, sign);
+ addSign(result, MSB32, sign);
+ }
+ else{
+ shiftR2Left2Result(left, MSB16, result, LSB, shCount, 0);
+ shiftLLeftOrResult(left, MSB32, result, MSB16, 8 - shCount);
+ /* the last shift is signed */
+ shiftR1Left2Result(left, MSB32, result, MSB24, shCount, sign);
+ addSign(result, MSB32, sign);
+ }
+ }
+ else{ /* 1 <= shCount <= 7 */
+ if(shCount <= 2){
+ shiftRLong(left, LSB, result, sign);
+ if(shCount == 2)
+ shiftRLong(result, LSB, result, sign);
+ }
+ else{
+ shiftR2Left2Result(left, LSB, result, LSB, shCount, 0);
+ shiftLLeftOrResult(left, MSB24, result, MSB16, 8 - shCount);
+ shiftR2Left2Result(left, MSB24, result, MSB24, shCount, sign);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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, FALSE);
+ aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+#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--)
+ movLeft2Result(left, size, result, size, 0);
+ }
+
+ else if(shCount >= (size * 8)){
+ if(sign)
+ /* get sign in acc.7 */
+ MOVA(aopGet(AOP(left),size-1,FALSE,FALSE));
+ addSign(result, LSB, sign);
+ } else{
+ switch (size) {
+ case 1:
+ genrshOne (result,left,shCount,sign);
+ break;
+
+ case 2:
+ genrshTwo (result,left,shCount,sign);
+ break;
+
+ case 4:
+ genrshFour (result,left,shCount,sign);
+ break;
+ default :
+ break;
+ }
+
+ freeAsmop(left,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genSignedRightShift - right shift of signed number */
+/*-----------------------------------------------------------------*/
+static void genSignedRightShift (iCode *ic)
+{
+ operand *right, *left, *result;
+ int size, offset;
+ char *l;
+ symbol *tlbl, *tlbl1 ;
+
+ D(emitcode(";", "genSignedRightShift "););
+
+ /* we do it the hard way put the shift count in b
+ and loop thru preserving the sign */
+
+ right = IC_RIGHT(ic);
+ left = IC_LEFT(ic);
+ result = IC_RESULT(ic);
+
+ aopOp(right,ic,FALSE, FALSE);
+
+ #if 0
+ if ( AOP_TYPE(right) == AOP_LIT) {
+ genRightShiftLiteral (left,right,result,ic,1);
+ return ;
+ }
+ #endif
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("inc","b");
+ freeAsmop (right,NULL,ic,TRUE);
+ aopOp(left,ic,FALSE, FALSE);
+ aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs(AOP(left),AOP(result)) &&
+ AOP_SIZE(result) > 1) {
+
+ size = AOP_SIZE(result);
+ offset=0;
+ while (size--) {
+ l = aopGet(AOP(left),offset,FALSE,TRUE);
+ if (*l == '@' && IS_AOP_PREG(result)) {
+
+ emitcode("mov","a,%s",l);
+ aopPut(AOP(result),"a",offset);
+ } else
+ aopPut(AOP(result),l,offset);
+ offset++;
+ }
+ }
+
+ /* mov the highest order bit to OVR */
+ tlbl = newiTempLabel(NULL);
+ tlbl1= newiTempLabel(NULL);
+
+ size = AOP_SIZE(result);
+ offset = size - 1;
+ emitcode("mov","a,%s",aopGet(AOP(left),offset,FALSE,FALSE));
+ emitcode("rlc","a");
+ emitcode("mov","ov,c");
+ /* if it is only one byte then */
+ if (size == 1) {
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ emitcode("mov","c,ov");
+ emitcode("rrc","a");
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+ aopPut(AOP(result),"a",0);
+ goto release ;
+ }
+
+ reAdjustPreg(AOP(result));
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ emitcode("mov","c,ov");
+ while (size--) {
+ l = aopGet(AOP(result),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",offset--);
+ }
+ reAdjustPreg(AOP(result));
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+
+release:
+ 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;
+ link *retype ;
+ int size, offset;
+ char *l;
+ symbol *tlbl, *tlbl1 ;
+
+ 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)));
+
+ if (!SPEC_USIGN(retype)) {
+ genSignedRightShift (ic);
+ return ;
+ }
+
+ /* signed & unsigned types are treated the same : i.e. the
+ signed is NOT propagated inwards : quoting from the
+ ANSI - standard : "for E1 >> E2, is equivalent to division
+ by 2**E2 if unsigned or if it has a non-negative value,
+ otherwise the result is implementation defined ", MY definition
+ is that the sign does not get propagated */
+
+ right = IC_RIGHT(ic);
+ left = IC_LEFT(ic);
+ result = IC_RESULT(ic);
+
+ aopOp(right,ic,FALSE, FALSE);
+
+ #if 0
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE(right) == AOP_LIT) {
+ genRightShiftLiteral (left,right,result,ic, 0);
+ return ;
+ }
+ #endif
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
+ emitcode("inc","b");
+ freeAsmop (right,NULL,ic,TRUE);
+ aopOp(left,ic,FALSE, FALSE);
+ aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs(AOP(left),AOP(result)) &&
+ AOP_SIZE(result) > 1) {
+
+ size = AOP_SIZE(result);
+ offset=0;
+ while (size--) {
+ l = aopGet(AOP(left),offset,FALSE,TRUE);
+ if (*l == '@' && IS_AOP_PREG(result)) {
+
+ emitcode("mov","a,%s",l);
+ aopPut(AOP(result),"a",offset);
+ } else
+ aopPut(AOP(result),l,offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel(NULL);
+ tlbl1= newiTempLabel(NULL);
+ size = AOP_SIZE(result);
+ offset = size - 1;
+
+ /* if it is only one byte then */
+ if (size == 1) {
+ l = aopGet(AOP(left),0,FALSE,FALSE);
+ MOVA(l);
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ CLRC;
+ emitcode("rrc","a");
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+ aopPut(AOP(result),"a",0);
+ goto release ;
+ }
+
+ reAdjustPreg(AOP(result));
+ emitcode("sjmp","%05d$",tlbl1->key+100);
+ emitcode("","%05d$:",tlbl->key+100);
+ CLRC;
+ while (size--) {
+ l = aopGet(AOP(result),offset,FALSE,FALSE);
+ MOVA(l);
+ emitcode("rrc","a");
+ aopPut(AOP(result),"a",offset--);
+ }
+ reAdjustPreg(AOP(result));
+
+ emitcode("","%05d$:",tlbl1->key+100);
+ emitcode("djnz","b,%05d$",tlbl->key+100);
+
+release:
+ freeAsmop(left,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits */
+/*-----------------------------------------------------------------*/
+static void genUnpackBits (operand *result, char *rname, int ptype)
+{
+ int shCnt ;
+ int rlen = 0 ;
+ link *etype;
+ int offset = 0 ;
+
+ D(emitcode(";", "genUnpackBits "););
+
+ etype = getSpec(operandType(result));
+
+ /* read the first byte */
+ switch (ptype) {
+
+ case POINTER:
+ case IPOINTER:
+ emitcode("mov","a,@%s",rname);
+ break;
+
+ case PPOINTER:
+ emitcode("movx","a,@%s",rname);
+ break;
+
+ case FPOINTER:
+ emitcode("movx","a,@dptr");
+ break;
+
+ case CPOINTER:
+ emitcode("clr","a");
+ emitcode("movc","a","@a+dptr");
+ break;
+
+ case GPOINTER:
+ emitcode("lcall","__gptrget");
+ break;
+ }
+
+ /* if we have bitdisplacement then it fits */
+ /* into this byte completely or if length is */
+ /* less than a byte */
+ if ((shCnt = SPEC_BSTR(etype)) ||
+ (SPEC_BLEN(etype) <= 8)) {
+
+ /* shift right acc */
+ AccRsh(shCnt);
+
+ emitcode("anl","a,#0x%02x",
+ ((unsigned char) -1)>>(8 - SPEC_BLEN(etype)));
+ aopPut(AOP(result),"a",offset);
+ return ;
+ }
+
+ /* bit field did not fit in a byte */
+ rlen = SPEC_BLEN(etype) - 8;
+ aopPut(AOP(result),"a",offset++);
+
+ while (1) {
+
+ switch (ptype) {
+ case POINTER:
+ case IPOINTER:
+ emitcode("inc","%s",rname);
+ emitcode("mov","a,@%s",rname);
+ break;
+
+ case PPOINTER:
+ emitcode("inc","%s",rname);
+ emitcode("movx","a,@%s",rname);
+ break;
+
+ case FPOINTER:
+ emitcode("inc","dptr");
+ emitcode("movx","a,@dptr");
+ break;
+
+ case CPOINTER:
+ emitcode("clr","a");
+ emitcode("inc","dptr");
+ emitcode("movc","a","@a+dptr");
+ break;
+
+ case GPOINTER:
+ emitcode("inc","dptr");
+ emitcode("lcall","__gptrget");
+ break;
+ }
+
+ rlen -= 8;
+ /* if we are done */
+ if ( rlen <= 0 )
+ break ;
+
+ aopPut(AOP(result),"a",offset++);
+
+ }
+
+ if (rlen) {
+ emitcode("anl","a,#0x%02x",((unsigned char)-1)>>(-rlen));
+ aopPut(AOP(result),"a",offset);
+ }
+
+ return ;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerGet - generates code when ptr offset is known */
+/*-----------------------------------------------------------------*/
+static void genDataPointerGet (operand *left,
+ operand *result,
+ iCode *ic)
+{
+ char *l;
+ char buffer[256];
+ int size , offset = 0;
+ aopOp(result,ic,TRUE, FALSE);
+
+ /* get the string representation of the name */
+ l = aopGet(AOP(left),0,FALSE,TRUE);
+ size = AOP_SIZE(result);
+ while (size--) {
+ if (offset)
+ sprintf(buffer,"(%s + %d)",l+1,offset);
+ else
+ sprintf(buffer,"%s",l+1);
+ aopPut(AOP(result),buffer,offset++);
+ }
+
+ freeAsmop(left,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerGet - emitcode for near pointer fetch */
+/*-----------------------------------------------------------------*/
+static void genNearPointerGet (operand *left,
+ operand *result,
+ iCode *ic)
+{
+ asmop *aop = NULL;
+ regs *preg = NULL ;
+ char *rname ;
+ link *rtype, *retype;
+ link *ltype = operandType(left);
+ char buffer[80];
+
+ rtype = operandType(result);
+ retype= getSpec(rtype);
+
+ aopOp(left,ic,FALSE, 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 value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG(AOP(left))) {
+ /* otherwise get a free pointer register */
+ aop = newAsmop(0);
+ preg = getFreePtr(ic,&aop,FALSE);
+ emitcode("mov","%s,%s",
+ preg->name,
+ aopGet(AOP(left),0,FALSE,TRUE));
+ rname = preg->name ;
+ } else
+ rname = aopGet(AOP(left),0,FALSE,FALSE);
+
+ freeAsmop(left,NULL,ic,TRUE);
+ aopOp (result,ic,FALSE, FALSE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITVAR(retype))
+ genUnpackBits (result,rname,POINTER);
+ else {
+ /* we have can just get the values */
+ int size = AOP_SIZE(result);
+ int offset = 0 ;
+
+ while (size--) {
+ if (IS_AOP_PREG(result) || AOP_TYPE(result) == AOP_STK ) {
+
+ emitcode("mov","a,@%s",rname);
+ aopPut(AOP(result),"a",offset);
+ } else {
+ sprintf(buffer,"@%s",rname);
+ aopPut(AOP(result),buffer,offset);
+ }
+ offset++ ;
+ if (size)
+ emitcode("inc","%s",rname);
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) {
+ /* we had to allocate for this iCode */
+ freeAsmop(NULL,aop,ic,TRUE);
+ } else {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if (AOP_SIZE(result) > 1 &&
+ !OP_SYMBOL(left)->remat &&
+ ( OP_SYMBOL(left)->liveTo > ic->seq ||
+ ic->depth )) {
+ int size = AOP_SIZE(result) - 1;
+ while (size--)
+ emitcode("dec","%s",rname);
+ }
+ }
+
+ /* done */
+ freeAsmop(result,NULL,ic,TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPagedPointerGet - emitcode for paged pointer fetch */
+/*-----------------------------------------------------------------*/
+static void genPagedPointerGet (operand *left,
+ operand *result,
+ iCode *ic)
+{
+ asmop *aop = NULL;
+ regs *preg = NULL ;
+ char *rname ;
+ link *rtype, *retype;
+
+ rtype = operandType(result);
+ retype= getSpec(rtype);
+
+ aopOp(left,ic,FALSE, FALSE);
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG(AOP(left))) {
+ /* otherwise get a free pointer register */
+ aop = newAsmop(0);
+ preg = getFreePtr(ic,&aop,FALSE);
+ emitcode("mov","%s,%s",
+ preg->name,
+ aopGet(AOP(left),0,FALSE,TRUE));
+ rname = preg->name ;
+ } else
+ rname = aopGet(AOP(left),0,FALSE,FALSE);
+
+ freeAsmop(left,NULL,ic,TRUE);
+ aopOp (result,ic,FALSE, FALSE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITVAR(retype))
+ genUnpackBits (result,rname,PPOINTER);
+ else {
+ /* we have can just get the values */
+ int size = AOP_SIZE(result);
+ int offset = 0 ;
+
+ while (size--) {
+
+ emitcode("movx","a,@%s",rname);
+ aopPut(AOP(result),"a",offset);
+
+ offset++ ;
+
+ if (size)
+ emitcode("inc","%s",rname);
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) {
+ /* we had to allocate for this iCode */
+ freeAsmop(NULL,aop,ic,TRUE);
+ } else {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if (AOP_SIZE(result) > 1 &&
+ !OP_SYMBOL(left)->remat &&
+ ( OP_SYMBOL(left)->liveTo > ic->seq ||
+ ic->depth )) {
+ int size = AOP_SIZE(result) - 1;
+ while (size--)
+ emitcode("dec","%s",rname);
+ }
+ }
+
+ /* done */
+ freeAsmop(result,NULL,ic,TRUE);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerGet - gget value from far space */
+/*-----------------------------------------------------------------*/
+static void genFarPointerGet (operand *left,
+ operand *result, iCode *ic)
+{
+ int size, offset ;
+ link *retype = getSpec(operandType(result));
+
+ D(emitcode(";", "genFarPointerGet"););
+
+ aopOp(left,ic,FALSE, FALSE);
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE(left) != AOP_STR) {
+ /* if this is remateriazable */
+ if (AOP_TYPE(left) == AOP_IMMD)
+ emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE));
+ else { /* we need to get it byte by byte */
+ emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE));
+ emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE));
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE));
+ }
+ }
+ }
+ /* so dptr know contains the address */
+ freeAsmop(left,NULL,ic,TRUE);
+ aopOp(result,ic,FALSE, TRUE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR(retype))
+ genUnpackBits(result,"dptr",FPOINTER);
+ else {
+ size = AOP_SIZE(result);
+ offset = 0 ;
+
+ while (size--) {
+ emitcode("movx","a,@dptr");
+ aopPut(AOP(result),"a",offset++);
+ if (size)
+ emitcode("inc","dptr");
+ }
+ }
+
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* emitcodePointerGet - gget value from code space */
+/*-----------------------------------------------------------------*/
+static void emitcodePointerGet (operand *left,
+ operand *result, iCode *ic)
+{
+ int size, offset ;
+ link *retype = getSpec(operandType(result));
+
+ aopOp(left,ic,FALSE, FALSE);
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE(left) != AOP_STR) {
+ /* if this is remateriazable */
+ if (AOP_TYPE(left) == AOP_IMMD)
+ emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE));
+ else { /* we need to get it byte by byte */
+ emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE));
+ emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE));
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE));
+ }
+ }
+ }
+ /* so dptr know contains the address */
+ freeAsmop(left,NULL,ic,TRUE);
+ aopOp(result,ic,FALSE, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR(retype))
+ genUnpackBits(result,"dptr",CPOINTER);
+ else {
+ size = AOP_SIZE(result);
+ offset = 0 ;
+
+ while (size--) {
+ emitcode("clr","a");
+ emitcode("movc","a,@a+dptr");
+ aopPut(AOP(result),"a",offset++);
+ if (size)
+ emitcode("inc","dptr");
+ }
+ }
+
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerGet - gget value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void genGenPointerGet (operand *left,
+ operand *result, iCode *ic)
+{
+ int size, offset ;
+ link *retype = getSpec(operandType(result));
+
+ aopOp(left,ic,FALSE, TRUE);
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE(left) != AOP_STR) {
+ /* if this is remateriazable */
+ if (AOP_TYPE(left) == AOP_IMMD) {
+ emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE));
+ emitcode("mov","b,#%d",pointerCode(retype));
+ }
+ else { /* we need to get it byte by byte */
+ emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE));
+ emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE));
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE));
+ emitcode("mov","b,%s",aopGet(AOP(left),3,FALSE,FALSE));
+ }
+ else
+ {
+ emitcode("mov","b,%s",aopGet(AOP(left),2,FALSE,FALSE));
+ }
+ }
+ }
+ /* so dptr know contains the address */
+ freeAsmop(left,NULL,ic,TRUE);
+ aopOp(result,ic,FALSE, TRUE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR(retype))
+ genUnpackBits(result,"dptr",GPOINTER);
+ else {
+ size = AOP_SIZE(result);
+ offset = 0 ;
+
+ while (size--) {
+ emitcode("lcall","__gptrget");
+ aopPut(AOP(result),"a",offset++);
+ if (size)
+ emitcode("inc","dptr");
+ }
+ }
+
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void genPointerGet (iCode *ic)
+{
+ operand *left, *result ;
+ 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));
+
+/* if (SPEC_OCLS(etype)->codesp ) { */
+/* p_type = CPOINTER ; */
+/* } */
+/* else */
+/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
+/* p_type = FPOINTER ; */
+/* else */
+/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
+/* p_type = PPOINTER; */
+/* else */
+/* if (SPEC_OCLS(etype) == idata ) */
+/* p_type = IPOINTER; */
+/* else */
+/* p_type = POINTER ; */
+ }
+
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type) {
+
+ case POINTER:
+ case IPOINTER:
+ genNearPointerGet (left,result,ic);
+ break;
+
+ case PPOINTER:
+ genPagedPointerGet(left,result,ic);
+ break;
+
+ case FPOINTER:
+ genFarPointerGet (left,result,ic);
+ break;
+
+ case CPOINTER:
+ emitcodePointerGet (left,result,ic);
+ break;
+
+ case GPOINTER:
+ genGenPointerGet (left,result,ic);
+ break;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPackBits - generates code for packed bit storage */
+/*-----------------------------------------------------------------*/
+static void genPackBits (link *etype ,
+ operand *right ,
+ char *rname, int p_type)
+{
+ int shCount = 0 ;
+ int offset = 0 ;
+ int rLen = 0 ;
+ int blen, bstr ;
+ char *l ;
+
+ blen = SPEC_BLEN(etype);
+ bstr = SPEC_BSTR(etype);
+
+ l = aopGet(AOP(right),offset++,FALSE,FALSE);
+ MOVA(l);
+
+ /* if the bit lenth is less than or */
+ /* it exactly fits a byte then */
+ if (SPEC_BLEN(etype) <= 8 ) {
+ shCount = SPEC_BSTR(etype) ;
+
+ /* shift left acc */
+ AccLsh(shCount);
+
+ if (SPEC_BLEN(etype) < 8 ) { /* if smaller than a byte */
+
+
+ switch (p_type) {
+ case POINTER:
+ emitcode ("mov","b,a");
+ emitcode("mov","a,@%s",rname);
+ break;
+
+ case FPOINTER:
+ emitcode ("mov","b,a");
+ emitcode("movx","a,@dptr");
+ break;
+
+ case GPOINTER:
+ emitcode ("push","b");
+ emitcode ("push","acc");
+ emitcode ("lcall","__gptrget");
+ emitcode ("pop","b");
+ break;
+ }
+
+ emitcode ("anl","a,#0x%02x",(unsigned char)
+ ((unsigned char)(0xFF << (blen+bstr)) |
+ (unsigned char)(0xFF >> (8-bstr)) ) );
+ emitcode ("orl","a,b");
+ if (p_type == GPOINTER)
+ emitcode("pop","b");
+ }
+ }
+
+ switch (p_type) {
+ case POINTER:
+ emitcode("mov","@%s,a",rname);
+ break;
+
+ case FPOINTER:
+ emitcode("movx","@dptr,a");
+ break;
+
+ case GPOINTER:
+ emitcode("lcall","__gptrput");
+ break;
+ }
+
+ /* if we r done */
+ if ( SPEC_BLEN(etype) <= 8 )
+ return ;
+
+ emitcode("inc","%s",rname);
+ rLen = SPEC_BLEN(etype) ;
+
+ /* now generate for lengths greater than one byte */
+ while (1) {
+
+ l = aopGet(AOP(right),offset++,FALSE,TRUE);
+
+ rLen -= 8 ;
+ if (rLen <= 0 )
+ break ;
+
+ switch (p_type) {
+ case POINTER:
+ if (*l == '@') {
+ MOVA(l);
+ emitcode("mov","@%s,a",rname);
+ } else
+ emitcode("mov","@%s,%s",rname,l);
+ break;
+
+ case FPOINTER:
+ MOVA(l);
+ emitcode("movx","@dptr,a");
+ break;
+
+ case GPOINTER:
+ MOVA(l);
+ emitcode("lcall","__gptrput");
+ break;
+ }
+ emitcode ("inc","%s",rname);
+ }
+
+ MOVA(l);
+
+ /* last last was not complete */
+ if (rLen) {
+ /* save the byte & read byte */
+ switch (p_type) {
+ case POINTER:
+ emitcode ("mov","b,a");
+ emitcode("mov","a,@%s",rname);
+ break;
+
+ case FPOINTER:
+ emitcode ("mov","b,a");
+ emitcode("movx","a,@dptr");
+ break;
+
+ case GPOINTER:
+ emitcode ("push","b");
+ emitcode ("push","acc");
+ emitcode ("lcall","__gptrget");
+ emitcode ("pop","b");
+ break;
+ }
+
+ emitcode ("anl","a,#0x%02x",((unsigned char)-1 << -rLen) );
+ emitcode ("orl","a,b");
+ }
+
+ if (p_type == GPOINTER)
+ emitcode("pop","b");
+
+ switch (p_type) {
+
+ case POINTER:
+ emitcode("mov","@%s,a",rname);
+ break;
+
+ case FPOINTER:
+ emitcode("movx","@dptr,a");
+ break;
+
+ case GPOINTER:
+ emitcode("lcall","__gptrput");
+ break;
+ }
+}
+/*-----------------------------------------------------------------*/
+/* genDataPointerSet - remat pointer to data space */
+/*-----------------------------------------------------------------*/
+static void genDataPointerSet(operand *right,
+ operand *result,
+ iCode *ic)
+{
+ int size, offset = 0 ;
+ char *l, buffer[256];
+
+ aopOp(right,ic,FALSE, FALSE);
+
+ l = aopGet(AOP(result),0,FALSE,TRUE);
+ size = AOP_SIZE(right);
+ while (size--) {
+ if (offset)
+ sprintf(buffer,"(%s + %d)",l+1,offset);
+ else
+ sprintf(buffer,"%s",l+1);
+ emitcode("mov","%s,%s",buffer,
+ aopGet(AOP(right),offset++,FALSE,FALSE));
+ }
+
+ freeAsmop(right,NULL,ic,TRUE);
+ freeAsmop(result,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerSet - emitcode for near pointer put */
+/*-----------------------------------------------------------------*/
+static void genNearPointerSet (operand *right,
+ operand *result,
+ iCode *ic)
+{
+ asmop *aop = NULL;
+ regs *preg = NULL ;
+ char *rname , *l;
+ link *retype;
+ link *ptype = operandType(result);
+
+ retype= getSpec(operandType(right));
+
+ aopOp(result,ic,FALSE, 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)) {
+ genDataPointerSet (right,result,ic);
+ return;
+ }
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG(AOP(result))) {
+ /* otherwise get a free pointer register */
+ aop = newAsmop(0);
+ preg = getFreePtr(ic,&aop,FALSE);
+ emitcode("mov","%s,%s",
+ preg->name,
+ aopGet(AOP(result),0,FALSE,TRUE));
+ rname = preg->name ;
+ } else
+ rname = aopGet(AOP(result),0,FALSE,FALSE);
+
+ freeAsmop(result,NULL,ic,TRUE);
+ aopOp (right,ic,FALSE, FALSE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITVAR(retype))
+ genPackBits (retype,right,rname,POINTER);
+ else {
+ /* we have can just get the values */
+ int size = AOP_SIZE(right);
+ int offset = 0 ;
+
+ while (size--) {
+ l = aopGet(AOP(right),offset,FALSE,TRUE);
+ if (*l == '@' ) {
+ MOVA(l);
+ emitcode("mov","@%s,a",rname);
+ } else
+ emitcode("mov","@%s,%s",rname,l);
+ if (size)
+ emitcode("inc","%s",rname);
+ offset++;
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) {
+ /* we had to allocate for this iCode */
+ freeAsmop(NULL,aop,ic,TRUE);
+ } else {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if (AOP_SIZE(right) > 1 &&
+ !OP_SYMBOL(result)->remat &&
+ ( OP_SYMBOL(result)->liveTo > ic->seq ||
+ ic->depth )) {
+ int size = AOP_SIZE(right) - 1;
+ while (size--)
+ emitcode("dec","%s",rname);
+ }
+ }
+
+ /* done */
+ freeAsmop(right,NULL,ic,TRUE);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPagedPointerSet - emitcode for Paged pointer put */
+/*-----------------------------------------------------------------*/
+static void genPagedPointerSet (operand *right,
+ operand *result,
+ iCode *ic)
+{
+ asmop *aop = NULL;
+ regs *preg = NULL ;
+ char *rname , *l;
+ link *retype;
+
+ retype= getSpec(operandType(right));
+
+ aopOp(result,ic,FALSE, FALSE);
+
+ /* if the value is already in a pointer register
+ then don't need anything more */
+ if (!AOP_INPREG(AOP(result))) {
+ /* otherwise get a free pointer register */
+ aop = newAsmop(0);
+ preg = getFreePtr(ic,&aop,FALSE);
+ emitcode("mov","%s,%s",
+ preg->name,
+ aopGet(AOP(result),0,FALSE,TRUE));
+ rname = preg->name ;
+ } else
+ rname = aopGet(AOP(result),0,FALSE,FALSE);
+
+ freeAsmop(result,NULL,ic,TRUE);
+ aopOp (right,ic,FALSE, FALSE);
+
+ /* if bitfield then unpack the bits */
+ if (IS_BITVAR(retype))
+ genPackBits (retype,right,rname,PPOINTER);
+ else {
+ /* we have can just get the values */
+ int size = AOP_SIZE(right);
+ int offset = 0 ;
+
+ while (size--) {
+ l = aopGet(AOP(right),offset,FALSE,TRUE);
+
+ MOVA(l);
+ emitcode("movx","@%s,a",rname);
+
+ if (size)
+ emitcode("inc","%s",rname);
+
+ offset++;
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop) {
+ /* we had to allocate for this iCode */
+ freeAsmop(NULL,aop,ic,TRUE);
+ } else {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ if (AOP_SIZE(right) > 1 &&
+ !OP_SYMBOL(result)->remat &&
+ ( OP_SYMBOL(result)->liveTo > ic->seq ||
+ ic->depth )) {
+ int size = AOP_SIZE(right) - 1;
+ while (size--)
+ emitcode("dec","%s",rname);
+ }
+ }
+
+ /* done */
+ freeAsmop(right,NULL,ic,TRUE);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarPointerSet - set value from far space */
+/*-----------------------------------------------------------------*/
+static void genFarPointerSet (operand *right,
+ operand *result, iCode *ic)
+{
+ int size, offset ;
+ link *retype = getSpec(operandType(right));
+
+ aopOp(result,ic,FALSE, FALSE);
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE(result) != AOP_STR) {
+ /* if this is remateriazable */
+ if (AOP_TYPE(result) == AOP_IMMD)
+ emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE));
+ else { /* we need to get it byte by byte */
+ emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE));
+ emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE));
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE));
+ }
+ }
+ }
+ /* so dptr know contains the address */
+ freeAsmop(result,NULL,ic,TRUE);
+ aopOp(right,ic,FALSE, FALSE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR(retype))
+ genPackBits(retype,right,"dptr",FPOINTER);
+ else {
+ size = AOP_SIZE(right);
+ offset = 0 ;
+
+ while (size--) {
+ char *l = aopGet(AOP(right),offset++,FALSE,FALSE);
+ MOVA(l);
+ emitcode("movx","@dptr,a");
+ if (size)
+ emitcode("inc","dptr");
+ }
+ }
+
+ freeAsmop(right,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerSet - set value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void genGenPointerSet (operand *right,
+ operand *result, iCode *ic)
+{
+ int size, offset ;
+ link *retype = getSpec(operandType(right));
+
+ aopOp(result,ic,FALSE, TRUE);
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE(result) != AOP_STR) {
+ /* if this is remateriazable */
+ if (AOP_TYPE(result) == AOP_IMMD) {
+ emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE));
+ emitcode("mov","b,%s + 1",aopGet(AOP(result),0,TRUE,FALSE));
+ }
+ else { /* we need to get it byte by byte */
+ emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE));
+ emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE));
+ if (options.model == MODEL_FLAT24)
+ {
+ emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE));
+ emitcode("mov","b,%s",aopGet(AOP(result),3,FALSE,FALSE));
+ }
+ else
+ {
+ emitcode("mov","b,%s",aopGet(AOP(result),2,FALSE,FALSE));
+ }
+ }
+ }
+ /* so dptr know contains the address */
+ freeAsmop(result,NULL,ic,TRUE);
+ aopOp(right,ic,FALSE, TRUE);
+
+ /* if bit then unpack */
+ if (IS_BITVAR(retype))
+ genPackBits(retype,right,"dptr",GPOINTER);
+ else {
+ size = AOP_SIZE(right);
+ offset = 0 ;
+
+ while (size--) {
+ char *l = aopGet(AOP(right),offset++,FALSE,FALSE);
+ MOVA(l);
+ emitcode("lcall","__gptrput");
+ if (size)
+ emitcode("inc","dptr");
+ }
+ }
+
+ freeAsmop(right,NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void genPointerSet (iCode *ic)
+{
+ operand *right, *result ;
+ 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));
+
+/* if (SPEC_OCLS(etype)->codesp ) { */
+/* p_type = CPOINTER ; */
+/* } */
+/* else */
+/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
+/* p_type = FPOINTER ; */
+/* else */
+/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
+/* p_type = PPOINTER ; */
+/* else */
+/* if (SPEC_OCLS(etype) == idata ) */
+/* p_type = IPOINTER ; */
+/* else */
+/* p_type = POINTER ; */
+ }
+
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type) {
+
+ case POINTER:
+ case IPOINTER:
+ genNearPointerSet (right,result,ic);
+ break;
+
+ case PPOINTER:
+ genPagedPointerSet (right,result,ic);
+ break;
+
+ case FPOINTER:
+ genFarPointerSet (right,result,ic);
+ break;
+
+ case GPOINTER:
+ genGenPointerSet (right,result,ic);
+ break;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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, FALSE);
+
+ /* get the value into acc */
+ if (AOP_TYPE(cond) != AOP_CRY)
+ toBoolean(cond);
+ 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, 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 */
+ if (sym->stack) {
+ emitcode("mov","a,_bp");
+ emitcode("add","a,#0x%02x",((char) sym->stack & 0xff));
+ aopPut(AOP(IC_RESULT(ic)),"a",0);
+ } else {
+ /* we can just move _bp */
+ aopPut(AOP(IC_RESULT(ic)),"_bp",0);
+ }
+ /* fill the result with zero */
+ size = AOP_SIZE(IC_RESULT(ic)) - 1;
+
+
+ if (options.stack10bit && size < (FPTRSIZE - 1))
+ {
+ fprintf(stderr,
+ "*** warning: pointer to stack var truncated.\n");
+ }
+
+ offset = 1;
+ while (size--)
+ {
+ /* Yuck! */
+ if (options.stack10bit && offset == 2)
+ {
+ aopPut(AOP(IC_RESULT(ic)),"#0x40", offset++);
+ }
+ else
+ {
+ aopPut(AOP(IC_RESULT(ic)),zero,offset++);
+ }
+ }
+
+ 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];
+ if (offset)
+ sprintf(s,"#(%s >> %d)",
+ sym->rname,
+ offset*8);
+ else
+ sprintf(s,"#%s",sym->rname);
+ aopPut(AOP(IC_RESULT(ic)),s,offset++);
+ }
+
+release:
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genFarFarAssign - assignment when both are in far space */
+/*-----------------------------------------------------------------*/
+static void genFarFarAssign (operand *result, operand *right, iCode *ic)
+{
+ int size = AOP_SIZE(right);
+ int offset = 0;
+ char *l ;
+ /* first push the right side on to the stack */
+ while (size--) {
+ l = aopGet(AOP(right),offset++,FALSE,FALSE);
+ MOVA(l);
+ emitcode ("push","acc");
+ }
+
+ D(emitcode(";", "genFarFarAssign "););
+
+ freeAsmop(right,NULL,ic,FALSE);
+ /* now assign DPTR to result */
+ aopOp(result,ic,FALSE, FALSE);
+ size = AOP_SIZE(result);
+ while (size--) {
+ emitcode ("pop","acc");
+ aopPut(AOP(result),"a",--offset);
+ }
+ freeAsmop(result,NULL,ic,FALSE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 (IC_RESULT(ic),IC_RIGHT(ic)))
+ return ;
+
+ aopOp(right,ic,FALSE, FALSE);
+
+ emitcode(";", "genAssign: resultIsFar = %s",
+ isOperandInFarSpace(result) ?
+ "TRUE" : "FALSE");
+
+ /* special case both in far space */
+ if ((AOP_TYPE(right) == AOP_DPTR ||
+ AOP_TYPE(right) == AOP_DPTR2) &&
+ /* IS_TRUE_SYMOP(result) && */
+ isOperandInFarSpace(result)) {
+
+ genFarFarAssign (result,right,ic);
+ return ;
+ }
+
+ aopOp(result,ic,TRUE, FALSE);
+
+ /* if they are the same registers */
+ if (sameRegs(AOP(right),AOP(result)))
+ goto release;
+
+ /* if the result is a bit */
+ if (AOP_TYPE(result) == AOP_CRY) {
+
+ /* if the right size is a literal then
+ we know what the value is */
+ if (AOP_TYPE(right) == AOP_LIT) {
+ if (((int) operandLitValue(right)))
+ aopPut(AOP(result),one,0);
+ else
+ aopPut(AOP(result),zero,0);
+ goto release;
+ }
+
+ /* the right is also a bit variable */
+ if (AOP_TYPE(right) == AOP_CRY) {
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ aopPut(AOP(result),"c",0);
+ goto release ;
+ }
+
+ /* we need to or */
+ toBoolean(right);
+ aopPut(AOP(result),"a",0);
+ goto release ;
+ }
+
+ /* bit variables done */
+ /* general case */
+ size = AOP_SIZE(result);
+ offset = 0 ;
+ if(AOP_TYPE(right) == AOP_LIT)
+ lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
+ if((size > 1) &&
+ (AOP_TYPE(result) != AOP_REG) &&
+ (AOP_TYPE(right) == AOP_LIT) &&
+ !IS_FLOAT(operandType(right)) &&
+ (lit < 256L)){
+ emitcode("clr","a");
+ while (size--) {
+ if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0)
+ aopPut(AOP(result),"a",size);
+ else
+ aopPut(AOP(result),
+ aopGet(AOP(right),size,FALSE,FALSE),
+ size);
+ }
+ } else {
+ while (size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+ }
+
+release:
+ freeAsmop (right,NULL,ic,FALSE);
+ 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, FALSE);
+ /* get the condition into accumulator */
+ l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE,FALSE);
+ MOVA(l);
+ /* multiply by three */
+ emitcode("add","a,acc");
+ emitcode("add","a,%s",aopGet(AOP(IC_JTCOND(ic)),0,FALSE,FALSE));
+ freeAsmop(IC_JTCOND(ic),NULL,ic,TRUE);
+
+ jtab = newiTempLabel(NULL);
+ emitcode("mov","dptr,#%05d$",jtab->key+100);
+ emitcode("jmp","@a+dptr");
+ emitcode("","%05d$:",jtab->key+100);
+ /* now generate the jump labels */
+ for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
+ jtab = setNextItem(IC_JTLABELS(ic)))
+ emitcode("ljmp","%05d$",jtab->key+100);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genCast - gen code for casting */
+/*-----------------------------------------------------------------*/
+static void genCast (iCode *ic)
+{
+ operand *result = IC_RESULT(ic);
+ link *ctype = operandType(IC_LEFT(ic));
+ 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, FALSE) ;
+ aopOp(result,ic,FALSE, AOP_TYPE(right) == AOP_DPTR);
+
+ /* if the result is a bit */
+ if (AOP_TYPE(result) == AOP_CRY) {
+ /* if the right size is a literal then
+ we know what the value is */
+ if (AOP_TYPE(right) == AOP_LIT) {
+ if (((int) operandLitValue(right)))
+ aopPut(AOP(result),one,0);
+ else
+ aopPut(AOP(result),zero,0);
+
+ goto release;
+ }
+
+ /* the right is also a bit variable */
+ if (AOP_TYPE(right) == AOP_CRY) {
+ emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
+ aopPut(AOP(result),"c",0);
+ goto release ;
+ }
+
+ /* we need to or */
+ toBoolean(right);
+ aopPut(AOP(result),"a",0);
+ goto release ;
+ }
+
+ /* if they are the same size : or less */
+ if (AOP_SIZE(result) <= AOP_SIZE(right)) {
+
+ /* if they are in the same place */
+ if (sameRegs(AOP(right),AOP(result)))
+ goto release;
+
+ /* if they in different places then copy */
+ size = AOP_SIZE(result);
+ offset = 0 ;
+ while (size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+ goto release;
+ }
+
+
+ /* if the result is of type pointer */
+ if (IS_PTR(ctype)) {
+
+ int p_type;
+ link *type = operandType(right);
+ link *etype = getSpec(type);
+
+ /* pointer to generic pointer */
+ if (IS_GENPTR(ctype)) {
+ char *l = zero;
+
+ if (IS_PTR(type))
+ p_type = DCL_TYPE(type);
+ else {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE(SPEC_OCLS(etype));
+ }
+
+ /* the first two bytes are known */
+ size = GPTRSIZE - 1;
+ offset = 0 ;
+ while (size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+ /* the last byte depending on type */
+ switch (p_type) {
+ case IPOINTER:
+ case POINTER:
+ l = zero;
+ break;
+ case FPOINTER:
+ l = one;
+ break;
+ case CPOINTER:
+ l = "#0x02";
+ break;
+ case PPOINTER:
+ l = "#0x03";
+ break;
+
+ default:
+ /* this should never happen */
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "got unknown pointer type");
+ exit(1);
+ }
+ aopPut(AOP(result),l, GPTRSIZE - 1);
+ goto release ;
+ }
+
+ /* just copy the pointers */
+ size = AOP_SIZE(result);
+ offset = 0 ;
+ while (size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+ goto release ;
+ }
+
+ /* so we now know that the size of destination is greater
+ than the size of the source */
+ /* we move to result for the size of source */
+ size = AOP_SIZE(right);
+ offset = 0 ;
+ while (size--) {
+ aopPut(AOP(result),
+ aopGet(AOP(right),offset,FALSE,FALSE),
+ offset);
+ offset++;
+ }
+
+ /* now depending on the sign of the source && destination */
+ size = AOP_SIZE(result) - AOP_SIZE(right);
+ /* if unsigned or not an integral type */
+ if (SPEC_USIGN(rtype) || !IS_SPEC(rtype)) {
+ while (size--)
+ aopPut(AOP(result),zero,offset++);
+ } else {
+ /* we need to extend the sign :{ */
+ char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
+ FALSE,FALSE);
+ MOVA(l);
+ emitcode("rlc","a");
+ emitcode("subb","a,acc");
+ while (size--)
+ aopPut(AOP(result),"a",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;
+
+ /* if the if condition has a false label
+ then we cannot save */
+ if (IC_FALSE(ifx))
+ return 0;
+
+ /* if the minus is not of the form
+ a = a - 1 */
+ if (!isOperandEqual(IC_RESULT(ic),IC_LEFT(ic)) ||
+ !IS_OP_LITERAL(IC_RIGHT(ic)))
+ return 0;
+
+ if (operandLitValue(IC_RIGHT(ic)) != 1)
+ return 0;
+
+ /* if the size of this greater than one then no
+ saving */
+ if (getSize(operandType(IC_RESULT(ic))) > 1)
+ return 0;
+
+ /* otherwise we can save BIG */
+ lbl = newiTempLabel(NULL);
+ lbl1= newiTempLabel(NULL);
+
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
+
+ if (IS_AOP_PREG(IC_RESULT(ic))) {
+ emitcode("dec","%s",
+ aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
+ emitcode("mov","a,%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
+ emitcode("jnz","%05d$",lbl->key+100);
+ } else {
+ emitcode ("djnz","%s,%05d$",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE),
+ lbl->key+100);
+ }
+ emitcode ("sjmp","%05d$",lbl1->key+100);
+ emitcode ("","%05d$:",lbl->key+100);
+ emitcode ("ljmp","%05d$",IC_TRUE(ifx)->key+100);
+ emitcode ("","%05d$:",lbl1->key+100);
+
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+ ifx->generated = 1;
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genReceive - generate code for a receive iCode */
+/*-----------------------------------------------------------------*/
+static void genReceive (iCode *ic)
+{
+
+ D(emitcode(";", "genReceive "););
+
+ if (isOperandInFarSpace(IC_RESULT(ic)) &&
+ ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
+ IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
+ int size = getSize(operandType(IC_RESULT(ic)));
+ int offset = fReturnSize_390 - size;
+ while (size--) {
+ emitcode ("push","%s", (strcmp(fReturn[fReturnSize_390 - offset - 1],"a") ?
+ fReturn[fReturnSize_390 - offset - 1] : "acc"));
+ offset++;
+ }
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
+ size = AOP_SIZE(IC_RESULT(ic));
+ offset = 0;
+ while (size--) {
+ emitcode ("pop","acc");
+ aopPut (AOP(IC_RESULT(ic)),"a",offset++);
+ }
+
+ } else {
+ _G.accInUse++;
+ aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
+ _G.accInUse--;
+ assignResultValue(IC_RESULT(ic));
+ }
+
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* gen390Code - generate code for 8051 based controllers */
+/*-----------------------------------------------------------------*/
+void gen390Code (iCode *lic)
+{
+ iCode *ic;
+ int cln = 0;
+
+ lineHead = lineCurr = NULL;
+
+ /* print the allocation information */
+ if (allocInfo)
+ printAllocInfo( currFunc, codeOutFile);
+ /* if debug information required */
+/* if (options.debug && currFunc) { */
+ if (currFunc) {
+ cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
+ _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";
+
+
+ for (ic = lic ; ic ; ic = ic->next ) {
+
+ if ( cln != ic->lineno ) {
+ if ( options.debug ) {
+ _G.debugLine = 1;
+ emitcode("","C$%s$%d$%d$%d ==.",
+ ic->filename,ic->lineno,
+ ic->level,ic->block);
+ _G.debugLine = 0;
+ }
+ emitcode(";","%s %d",ic->filename,ic->lineno);
+ cln = ic->lineno ;
+ }
+ /* if the result is marked as
+ spilt and rematerializable or code for
+ this has already been generated then
+ do nothing */
+ if (resultRemat(ic) || ic->generated )
+ continue ;
+
+ /* depending on the operation */
+ switch (ic->op) {
+ case '!' :
+ genNot(ic);
+ break;
+
+ case '~' :
+ genCpl(ic);
+ break;
+
+ case UNARYMINUS:
+ genUminus (ic);
+ break;
+
+ case IPUSH:
+ genIpush (ic);
+ break;
+
+ case IPOP:
+ /* 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 '+' :
+ 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);
+ break;
+
+ case '=' :
+ if (POINTER_SET(ic))
+ genPointerSet(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;
+ /* piCode(ic,stdout); */
+
+ }
+ }
+
+
+ /* now we are ready to call the
+ peep hole optimizer */
+ if (!options.nopeep)
+ peepHole (&lineHead);
+
+ /* now do the actual printing */
+ printLine (lineHead,codeOutFile);
+ return;
+}
--- /dev/null
+/*------------------------------------------------------------------------
+
+ SDCCralloc.c - source file for register allocation. (8051) specific
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "common.h"
+#include "ralloc.h"
+#include "gen.h"
+
+/*-----------------------------------------------------------------*/
+/* At this point we start getting processor specific although */
+/* some routines are non-processor specific & can be reused when */
+/* targetting other processors. The decision for this will have */
+/* to be made on a routine by routine basis */
+/* routines used to pack registers are most definitely not reusable*/
+/* since the pack the registers depending strictly on the MCU */
+/*-----------------------------------------------------------------*/
+
+extern void gen390Code(iCode *);
+
+/* Global data */
+static struct {
+ bitVect *spiltSet;
+ set *stackSpil;
+ bitVect *regAssigned;
+ short blockSpil;
+ int slocNum;
+ bitVect *funcrUsed; /* registers used in a function */
+ int stackExtend;
+ int dataExtend;
+} _G;
+
+/* Shared with gen.c */
+int ds390_ptrRegReq; /* one byte pointer register required */
+
+/* 8051 registers */
+regs regs390[] =
+{
+
+ { REG_GPR ,R2_IDX , REG_GPR , "r2", "ar2", "0", 2, 1 },
+ { REG_GPR ,R3_IDX , REG_GPR , "r3", "ar3", "0", 3, 1 },
+ { REG_GPR ,R4_IDX , REG_GPR , "r4", "ar4", "0", 4, 1 },
+ { REG_GPR ,R5_IDX , REG_GPR , "r5", "ar5", "0", 5, 1 },
+ { REG_GPR ,R6_IDX , REG_GPR , "r6", "ar6", "0", 6, 1 },
+ { REG_GPR ,R7_IDX , REG_GPR , "r7", "ar7", "0", 7, 1 },
+ { REG_PTR ,R0_IDX , REG_PTR , "r0" , "ar0", "0", 0, 1 },
+ { REG_PTR ,R1_IDX , REG_PTR , "r1" , "ar1", "0", 1, 1 },
+ { REG_GPR ,X8_IDX , REG_GPR , "x8", "x8" , "xreg", 0, 1 },
+ { REG_GPR ,X9_IDX , REG_GPR , "x9", "x9" , "xreg", 1, 1 },
+ { REG_GPR ,X10_IDX,REG_GPR , "x10", "x10", "xreg", 2, 1 },
+ { REG_GPR ,X11_IDX,REG_GPR , "x11", "x11", "xreg", 3, 1 },
+ { REG_GPR ,X12_IDX,REG_GPR , "x12", "x12", "xreg", 4, 1 },
+ { REG_CND ,CND_IDX,REG_CND , "C" , "C" , "xreg", 0, 1 },
+};
+int ds390_nRegs = 13;
+static void spillThis (symbol *);
+
+/*-----------------------------------------------------------------*/
+/* allocReg - allocates register of given type */
+/*-----------------------------------------------------------------*/
+static regs *allocReg (short type)
+{
+ int i;
+
+ for ( i = 0 ; i < ds390_nRegs ; i++ ) {
+
+ /* if type is given as 0 then any
+ free register will do */
+ if (!type &&
+ regs390[i].isFree ) {
+ regs390[i].isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed =
+ bitVectSetBit(currFunc->regsUsed,i);
+ return ®s390[i];
+ }
+ /* other wise look for specific type
+ of register */
+ if (regs390[i].isFree &&
+ regs390[i].type == type) {
+ regs390[i].isFree = 0;
+ if (currFunc)
+ currFunc->regsUsed =
+ bitVectSetBit(currFunc->regsUsed,i);
+ return ®s390[i];
+ }
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* ds390_regWithIdx - returns pointer to register wit index number */
+/*-----------------------------------------------------------------*/
+regs *ds390_regWithIdx (int idx)
+{
+ int i ;
+
+ for (i=0;i < ds390_nRegs;i++)
+ if (regs390[i].rIdx == idx)
+ return ®s390[i];
+
+ werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
+ "regWithIdx not found");
+ exit(1);
+}
+
+/*-----------------------------------------------------------------*/
+/* freeReg - frees a register */
+/*-----------------------------------------------------------------*/
+static void freeReg (regs *reg)
+{
+ reg->isFree = 1;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* nFreeRegs - returns number of free registers */
+/*-----------------------------------------------------------------*/
+static int nFreeRegs (int type)
+{
+ int i;
+ int nfr=0;
+
+ for (i = 0 ; i < ds390_nRegs; i++ )
+ if (regs390[i].isFree && regs390[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);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* allDefsOutOfRange - all definitions are out of a range */
+/*-----------------------------------------------------------------*/
+static bool allDefsOutOfRange (bitVect *defs,int fseq, int toseq)
+{
+ int i ;
+
+ if (!defs)
+ return TRUE ;
+
+ for ( i = 0 ;i < defs->size ; i++ ) {
+ iCode *ic;
+
+ if (bitVectBitValue(defs,i) &&
+ (ic = hTabItemWithKey(iCodehTab,i)) &&
+ ( ic->seq >= fseq && ic->seq <= toseq))
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* notUsedInBlock - not used in this block */
+/*-----------------------------------------------------------------*/
+static int notUsedInBlock (symbol *sym, eBBlock *ebp, iCode *ic)
+{
+ return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs) &&
+ allDefsOutOfRange (sym->defs,ebp->fSeq,ebp->lSeq));
+/* return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs)); */
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 (sym->liveTo > fsym->liveFrom )
+ 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 *r0,*r1;
+ int k;
+
+ if (!_G.regAssigned ||
+ bitVectIsZero(_G.regAssigned))
+ return;
+
+ r0 = ds390_regWithIdx(R0_IDX);
+ r1 = ds390_regWithIdx(R1_IDX);
+
+ /* for all live ranges */
+ for (lrsym = hTabFirstItem(liveRanges,&k) ; lrsym ;
+ lrsym = hTabNextItem(liveRanges,&k) ) {
+ int j;
+
+ /* if no registers assigned to it or
+ spilt */
+ /* if it does not overlap 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] == r0 ||
+ lrsym->regs[j] == r1 ) {
+ spillThis (lrsym);
+ break;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* createStackSpil - create a location on the stack to spil */
+/*-----------------------------------------------------------------*/
+static symbol *createStackSpil (symbol *sym)
+{
+ symbol *sloc= NULL;
+ int useXstack, model, noOverlay;
+
+ 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) = options.model ? S_XDATA : S_DATA;
+ SPEC_EXTR(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
+ and turn off overlaying
+ */
+
+ 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)
+{
+ 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 = 1;
+ _G.spiltSet = bitVectSetBit(_G.spiltSet,sym->key);
+
+ bitVectUnSetBit(_G.regAssigned,sym->key);
+
+ for (i = 0 ; i < sym->nRegs ; i++)
+
+ if (sym->regs[i]) {
+ freeReg(sym->regs[i]);
+ sym->regs[i] = NULL;
+ }
+
+ /* if spilt on stack then free up r0 & r1
+ if they could have been assigned to some
+ LIVE ranges */
+ if (!ds390_ptrRegReq && isSpiltOnStack(sym)) {
+ ds390_ptrRegReq++ ;
+ spillLRWithPtrReg(sym);
+ }
+
+ if (sym->usl.spillLoc && !sym->remat)
+ sym->usl.spillLoc->allocreq = 1;
+ 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 = 1;
+ 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->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 = 1;
+ return sym;
+ }
+
+ /* find live ranges with spillocation */
+ if ((selectS = liveRangesWith(lrcs,hasSpilLoc,ebp,ic))) {
+
+ sym = leastUsedLR(selectS);
+ sym->usl.spillLoc->allocreq = 1;
+ 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 = 1;
+ 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 = 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);
+
+ /* mark the registers as free */
+ for (i = 0 ; i < ssym->nRegs ;i++ )
+ if (ssym->regs[i])
+ freeReg(ssym->regs[i]);
+
+ /* if spilt on stack then free up r0 & r1
+ if they could have been assigned to as gprs */
+ if (!ds390_ptrRegReq && isSpiltOnStack(ssym) ) {
+ ds390_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 (!ds390_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 ;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 < max(sym->nRegs,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);
+
+ }
+
+ /* free the remaining */
+ for (; i < sym->nRegs ; i++) {
+ if (psym) {
+ if (!symHasReg(psym,sym->regs[i]))
+ freeReg(sym->regs[i]);
+ } else
+ freeReg(sym->regs[i]);
+ }
+ }
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* reassignLR - reassign this to registers */
+/*-----------------------------------------------------------------*/
+static void reassignLR (operand *op)
+{
+ symbol *sym = OP_SYMBOL(op);
+ int i;
+
+ /* not spilt any more */
+ sym->isspilt = sym->blockSpil = sym->remainSpil = 0;
+ bitVectUnSetBit(_G.spiltSet,sym->key);
+
+ _G.regAssigned = bitVectSetBit(_G.regAssigned,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 (ds390_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 void positionRegs (symbol *result, symbol *opsym, int lineno)
+{
+ int count = min(result->nRegs,opsym->nRegs);
+ int i , j = 0, shared = 0;
+
+ /* if the result has been spilt then cannot share */
+ if (opsym->isspilt)
+ return ;
+ 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;
+ goto again;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 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 = 1;
+
+ /* 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 && sym->usl.spillLoc ) {
+
+ symbol *leastUsed =
+ leastUsedLR(liveRangesWith (spillable ,
+ allLRs,
+ ebbs[i],
+ ic));
+ if (leastUsed &&
+ leastUsed->used > sym->used) {
+ spillThis (sym);
+ continue;
+ }
+ }
+
+ /* if we need ptr regs for the right side
+ then mark it */
+ if (POINTER_GET(ic) && getSize(OP_SYMBOL(IC_LEFT(ic))->type)
+ <= PTRSIZE)
+ {
+ ds390_ptrRegReq++;
+ ptrRegSet = 1;
+ }
+ /* else we assign registers to it */
+ _G.regAssigned = bitVectSetBit(_G.regAssigned,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 falied 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)),ic->lineno);
+ /* 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)),ic->lineno);
+
+ if (ptrRegSet) {
+ ds390_ptrRegReq--;
+ ptrRegSet = 0;
+ }
+
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* rUmaskForOp :- returns register mask for an operand */
+/*-----------------------------------------------------------------*/
+static bitVect *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(ds390_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(ds390_nRegs);
+
+ /* do the special cases first */
+ if (ic->op == IFX ) {
+ rmask = bitVectUnion(rmask,
+ rUmaskForOp(IC_COND(ic)));
+ goto ret;
+ }
+
+ /* for the jumptable */
+ if (ic->op == JUMPTABLE) {
+ rmask = bitVectUnion(rmask,
+ rUmaskForOp(IC_JTCOND(ic)));
+
+ goto ret;
+ }
+
+ /* of all other cases */
+ if (IC_LEFT(ic))
+ rmask = bitVectUnion(rmask,
+ rUmaskForOp(IC_LEFT(ic)));
+
+
+ if (IC_RIGHT(ic))
+ rmask = bitVectUnion(rmask,
+ rUmaskForOp(IC_RIGHT(ic)));
+
+ if (IC_RESULT(ic))
+ rmask = bitVectUnion(rmask,
+ 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(ds390_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");
+ 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;
+
+ 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 ;
+ }
+
+ /* 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 ()
+{
+ 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 and the
+ pointer we are getting is rematerializable and
+ in "data" space */
+
+ if (bitVectnBitsOn(sym->defs) == 1 &&
+ (ic = hTabItemWithKey(iCodehTab,
+ bitVectFirstBit(sym->defs))) &&
+ POINTER_GET(ic) &&
+ !IS_BITVAR(sym->etype)) {
+
+
+ /* if remat in data space */
+ if (OP_SYMBOL(IC_LEFT(ic))->remat &&
+ // sym->type &&
+ DCL_TYPE(aggrToPtr(sym->type,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;
+ 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< ds390_nRegs;i++ )
+ regs390[i].isFree = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* deallocStackSpil - this will set the stack pointer back */
+/*-----------------------------------------------------------------*/
+static DEFSETFUNC(deallocStackSpil)
+{
+ symbol *sym = item;
+
+ deallocLocal(sym);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* farSpacePackable - returns the packable icode for far variables */
+/*-----------------------------------------------------------------*/
+static iCode *farSpacePackable (iCode *ic)
+{
+ iCode *dic ;
+
+ /* go thru till we find a definition for the
+ symbol on the right */
+ for ( dic = ic->prev ; dic ; dic = dic->prev) {
+
+ /* if the definition is a call then no */
+ if ((dic->op == CALL || dic->op == PCALL) &&
+ IC_RESULT(dic)->key == IC_RIGHT(ic)->key) {
+ return NULL;
+ }
+
+ /* if shift by unknown amount then not */
+ if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) &&
+ IC_RESULT(dic)->key == IC_RIGHT(ic)->key)
+ return NULL;
+
+ /* if pointer get and size > 1 */
+ if (POINTER_GET(dic) &&
+ getSize(aggrToPtr(operandType(IC_LEFT(dic)),FALSE)) > 1)
+ return NULL ;
+
+ if (POINTER_SET(dic) &&
+ getSize(aggrToPtr(operandType(IC_RESULT(dic)),FALSE)) > 1)
+ return NULL ;
+
+ /* if 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 (isOperandInFarSpace(IC_RESULT(ic))) {
+ if ((dic = farSpacePackable(ic)))
+ goto pack;
+ else
+ return 0;
+
+ }
+ /* 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 there is a function call and this is
+ a parameter & not my parameter then don't pack it */
+ if ( (dic->op == CALL || dic->op == PCALL) &&
+ (OP_SYMBOL(IC_RESULT(ic))->_isparm &&
+ !OP_SYMBOL(IC_RESULT(ic))->ismyparm)) {
+ dic = NULL;
+ break;
+ }
+
+ 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 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 */
+ 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;
+ }
+ /* 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);
+ 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;
+
+ 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)) */
+ ) {
+
+ /* we are interested only if defined in far space */
+ /* or in stack space in case of + & - */
+
+ /* if assigned to a non-symbol then return
+ true */
+ if (!IS_SYMOP(IC_RIGHT(dic)))
+ break ;
+
+ /* if the symbol is in far space then
+ we should not */
+ if (isOperandInFarSpace(IC_RIGHT(dic)))
+ return NULL ;
+
+ /* for + & - operations make sure that
+ if it is on the stack it is the same
+ as one of the three operands */
+ if ((ic->op == '+' || ic->op == '-') &&
+ OP_SYMBOL(IC_RIGHT(dic))->onStack) {
+
+ if ( IC_RESULT(ic)->key != IC_RIGHT(dic)->key &&
+ IC_LEFT(ic)->key != IC_RIGHT(dic)->key &&
+ IC_RIGHT(ic)->key != IC_RIGHT(dic)->key)
+ return NULL;
+ }
+
+ break ;
+
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegsForSupport :- reduce some registers for support calls */
+/*-----------------------------------------------------------------*/
+static int packRegsForSupport (iCode *ic, eBBlock *ebp)
+{
+ int change = 0 ;
+ /* 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) {
+ iCode *dic = findAssignToSym(IC_LEFT(ic),ic);
+ iCode *sic;
+
+ if (!dic)
+ goto right ;
+
+ /* found it we need to remove it from the
+ block */
+ for ( sic = dic; sic != ic ; sic = sic->next )
+ bitVectUnSetBit(sic->rlive,IC_LEFT(ic)->key);
+
+ IC_LEFT(ic)->operand.symOperand =
+ IC_RIGHT(dic)->operand.symOperand;
+ IC_LEFT(ic)->key = IC_RIGHT(dic)->operand.symOperand->key;
+ remiCodeFromeBBlock(ebp,dic);
+ hTabDeleteItem (&iCodehTab,dic->key,dic,DELETE_ITEM,NULL);
+ change++;
+ }
+
+ /* do the same for the right operand */
+ right:
+ if (!change &&
+ IS_ITEMP(IC_RIGHT(ic)) &&
+ OP_SYMBOL(IC_RIGHT(ic))->liveTo <= ic->seq) {
+ iCode *dic = findAssignToSym(IC_RIGHT(ic),ic);
+ iCode *sic;
+
+ if (!dic)
+ return change ;
+
+ /* if this is a subtraction & the result
+ is a true symbol in far space then don't pack */
+ if (ic->op == '-' && IS_TRUE_SYMOP(IC_RESULT(dic))) {
+ link *etype =getSpec(operandType(IC_RESULT(dic)));
+ if (IN_FARSPACE(SPEC_OCLS(etype)))
+ return change ;
+ }
+ /* found it we need to remove it from the
+ block */
+ for ( sic = dic; sic != ic ; sic = sic->next )
+ bitVectUnSetBit(sic->rlive,IC_RIGHT(ic)->key);
+
+ IC_RIGHT(ic)->operand.symOperand =
+ IC_RIGHT(dic)->operand.symOperand;
+ IC_RIGHT(ic)->key = IC_RIGHT(dic)->operand.symOperand->key;
+
+ remiCodeFromeBBlock(ebp,dic);
+ hTabDeleteItem (&iCodehTab,dic->key,dic,DELETE_ITEM,NULL);
+ change ++;
+ }
+
+ return change ;
+}
+
+#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)) > (fReturnSize_390 - 2) &&
+ ic->op != RETURN &&
+ ic->op != SEND &&
+ !POINTER_SET(ic) &&
+ !POINTER_GET(ic))
+ 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 the that definition */
+ if (!(dic =
+ hTabItemWithKey(iCodehTab,
+ bitVectFirstBit(OP_DEFS(op)))))
+ 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) {
+ 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 (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 ;
+
+ sic = dic;
+
+ /* also make sure the intervenening instructions
+ don't have any thing in far space */
+ for (dic = dic->next ; dic && dic != ic ; dic = dic->next) {
+
+ /* if there is an intervening function call then no */
+ if (dic->op == CALL || dic->op == PCALL)
+ return NULL;
+ /* if pointer set then make sure the pointer
+ is one byte */
+ if (POINTER_SET(dic) &&
+ !IS_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 ;
+
+ /* 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 (( dic->op == '%' || dic->op == '/' || dic->op == '*') &&
+ getSize(operandType(op)) >= 3)
+ return NULL;
+
+ /* if left or right or result is in far space */
+ if (isOperandInFarSpace(IC_LEFT(dic)) ||
+ isOperandInFarSpace(IC_RIGHT(dic)) ||
+ isOperandInFarSpace(IC_RESULT(dic)) ||
+ IS_OP_RUONLY(IC_LEFT(dic)) ||
+ IS_OP_RUONLY(IC_RIGHT(dic)) ||
+ IS_OP_RUONLY(IC_RESULT(dic)) ) {
+ return NULL;
+ }
+ }
+
+ OP_SYMBOL(op)->ruonly = 1;
+ return sic;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */
+/*-----------------------------------------------------------------*/
+static bool isBitwiseOptimizable (iCode *ic)
+{
+ link *ltype = getSpec(operandType(IC_LEFT(ic)));
+ 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 ;
+}
+
+/*-----------------------------------------------------------------*/
+/* packRegsForAccUse - pack registers for acc use */
+/*-----------------------------------------------------------------*/
+static void packRegsForAccUse (iCode *ic)
+{
+ iCode *uic;
+
+ /* if + or - then it has to be one byte result */
+ if ((ic->op == '+' || ic->op == '-')
+ && getSize(operandType(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* if shift operation make sure right side is not a literal */
+ if (ic->op == RIGHT_OP &&
+ ( isOperandLiteral(IC_RIGHT(ic)) ||
+ getSize(operandType(IC_RESULT(ic))) > 1))
+ return ;
+
+ if (ic->op == LEFT_OP &&
+ ( isOperandLiteral(IC_RIGHT(ic)) ||
+ getSize(operandType(IC_RESULT(ic))) > 1))
+ return ;
+
+ if (IS_BITWISE_OP(ic) &&
+ getSize(operandType(IC_RESULT(ic))) > 1)
+ return ;
+
+
+ /* has only one definition */
+ if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* has only one use */
+ if (bitVectnBitsOn(OP_USES(IC_RESULT(ic))) > 1)
+ return ;
+
+ /* and the usage immediately follows this iCode */
+ if (!(uic = hTabItemWithKey(iCodehTab,
+ bitVectFirstBit(OP_USES(IC_RESULT(ic))))))
+ return ;
+
+ if (ic->next != uic)
+ return ;
+
+ /* if it is a conditional branch then we definitely can */
+ if (uic->op == IFX )
+ goto accuse;
+
+ if ( uic->op == JUMPTABLE )
+ return ;
+
+ /* if the usage is not is an assignment
+ or an arithmetic / bitwise / shift operation then not */
+ if (POINTER_SET(uic) &&
+ getSize(aggrToPtr(operandType(IC_RESULT(uic)),FALSE)) > 1)
+ return;
+
+ if (uic->op != '=' &&
+ !IS_ARITHMETIC_OP(uic) &&
+ !IS_BITWISE_OP(uic) &&
+ uic->op != LEFT_OP &&
+ uic->op != RIGHT_OP )
+ return;
+
+ /* if used in ^ operation then make sure right is not a
+ literl */
+ if (uic->op == '^' && isOperandLiteral(IC_RIGHT(uic)))
+ return ;
+
+ /* if shift operation make sure right side is not a literal */
+ if (uic->op == RIGHT_OP &&
+ ( isOperandLiteral(IC_RIGHT(uic)) ||
+ getSize(operandType(IC_RESULT(uic))) > 1))
+ return ;
+
+ if (uic->op == LEFT_OP &&
+ ( isOperandLiteral(IC_RIGHT(uic)) ||
+ getSize(operandType(IC_RESULT(uic))) > 1))
+ return ;
+
+ /* make sure that the result of this icode is not on the
+ stack, since acc is used to compute stack offset */
+ if (IS_TRUE_SYMOP(IC_RESULT(uic)) &&
+ OP_SYMBOL(IC_RESULT(uic))->onStack)
+ return ;
+
+ /* if either one of them in far space then we cannot */
+ if ((IS_TRUE_SYMOP(IC_LEFT(uic)) &&
+ isOperandInFarSpace(IC_LEFT(uic))) ||
+ (IS_TRUE_SYMOP(IC_RIGHT(uic)) &&
+ isOperandInFarSpace(IC_RIGHT(uic))))
+ return ;
+
+ /* if the usage has only one operand then we can */
+ if (IC_LEFT(uic) == NULL ||
+ IC_RIGHT(uic) == NULL)
+ goto accuse;
+
+ /* make sure this is on the left side if not
+ a '+' since '+' is commutative */
+ if (ic->op != '+' &&
+ IC_LEFT(uic)->key != IC_RESULT(ic)->key)
+ return;
+
+ /* 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 ;
+ }
+
+ /* if the other one is not on stack then we can */
+ if (IC_LEFT(uic)->key == IC_RESULT(ic)->key &&
+ (IS_ITEMP(IC_RIGHT(uic)) ||
+ (IS_TRUE_SYMOP(IC_RIGHT(uic)) &&
+ !OP_SYMBOL(IC_RIGHT(uic))->onStack)))
+ goto accuse;
+
+ if (IC_RIGHT(uic)->key == IC_RESULT(ic)->key &&
+ (IS_ITEMP(IC_LEFT(uic)) ||
+ (IS_TRUE_SYMOP(IC_LEFT(uic)) &&
+ !OP_SYMBOL(IC_LEFT(uic))->onStack)))
+ goto accuse ;
+
+ return ;
+
+ accuse:
+ OP_SYMBOL(IC_RESULT(ic))->accuse = 1;
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* packForPush - hueristics to reduce iCode for pushing */
+/*-----------------------------------------------------------------*/
+static void packForPush(iCode *ic, eBBlock *ebp)
+{
+ iCode *dic;
+
+ 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;
+
+ /* we now we know that it has one & only one def & use
+ and the that the definition is an assignment */
+ 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 *ebp)
+{
+ iCode *ic ;
+ int change = 0 ;
+
+ 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 a 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 &&
+ 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 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)) &&
+ OP_SYMBOL(IC_LEFT(ic))->remat &&
+ bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) == 1 &&
+ IS_OP_LITERAL(IC_RIGHT(ic))) ) {
+
+ int i = operandLitValue(IC_RIGHT(ic));
+ 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))
+ OP_SYMBOL(IC_LEFT(ic))->uptr = 1;
+
+ if (!SKIP_IC2(ic)) {
+ /* if we are using a symbol on the stack
+ then we should say ds390_ptrRegReq */
+ if (ic->op == IFX && IS_SYMOP(IC_COND(ic)))
+ ds390_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)))
+ ds390_ptrRegReq += ((OP_SYMBOL(IC_JTCOND(ic))->onStack ||
+ OP_SYMBOL(IC_JTCOND(ic))->iaccess) ? 1 : 0);
+ else {
+ if (IS_SYMOP(IC_LEFT(ic)))
+ ds390_ptrRegReq += ((OP_SYMBOL(IC_LEFT(ic))->onStack ||
+ OP_SYMBOL(IC_LEFT(ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP(IC_RIGHT(ic)))
+ ds390_ptrRegReq += ((OP_SYMBOL(IC_RIGHT(ic))->onStack ||
+ OP_SYMBOL(IC_RIGHT(ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP(IC_RESULT(ic)))
+ ds390_ptrRegReq += ((OP_SYMBOL(IC_RESULT(ic))->onStack ||
+ OP_SYMBOL(IC_RESULT(ic))->iaccess) ? 1 : 0);
+ }
+ }
+
+ /* if the condition of an if instruction
+ is defined in the previous instruction then
+ mark the itemp as a conditional */
+ if ((IS_CONDITIONAL(ic) ||
+ ( ( ic->op == BITWISEAND ||
+ ic->op == '|' ||
+ ic->op == '^' ) &&
+ isBitwiseOptimizable(ic))) &&
+ ic->next && ic->next->op == IFX &&
+ 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);
+
+ /* some cases the redundant moves can
+ can be eliminated for return statements */
+ if ((ic->op == RETURN || ic->op == SEND) &&
+ !isOperandInFarSpace(IC_LEFT(ic)) &&
+ !options.model)
+ 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) &&
+ !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) {
+ link *fromType = operandType(IC_RIGHT(ic));
+ link *toType = operandType(IC_LEFT(ic));
+
+ if (IS_INTEGRAL(fromType) && IS_INTEGRAL(toType) &&
+ getSize(fromType) != getSize(toType) ) {
+
+ iCode *dic = packRegsForOneuse(ic,IC_RIGHT(ic),ebp);
+ if (dic) {
+ if (IS_ARITHMETIC_OP(dic)) {
+ IC_RESULT(dic) = IC_RESULT(ic);
+ remiCodeFromeBBlock(ebp,ic);
+ 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 (checkType(operandType(IC_RIGHT(ic)),
+ operandType(IC_LEFT(ic))) == 1) {
+ iCode *dic = packRegsForOneuse (ic,IC_RIGHT(ic),ebp);
+ if (dic) {
+ IC_RESULT(dic) = IC_RESULT(ic);
+ remiCodeFromeBBlock(ebp,ic);
+ hTabDeleteItem (&iCodehTab,ic->key,ic,DELETE_ITEM,NULL);
+ OP_DEFS(IC_RESULT(dic)) = bitVectSetBit(OP_DEFS(IC_RESULT(dic)),dic->key);
+ ic = ic->prev;
+ }
+ }
+ }
+ }
+
+ /* pack for PUSH
+ iTempNN := (some variable in farspace) V1
+ push iTempNN ;
+ -------------
+ push V1
+ */
+ if (ic->op == IPUSH ) {
+ packForPush(ic,ebp);
+ }
+
+
+ /* 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_BITWISE_OP(ic)
+
+ || ic->op == LEFT_OP || ic->op == RIGHT_OP
+
+ ) &&
+ IS_ITEMP(IC_RESULT(ic)) &&
+ getSize(operandType(IC_RESULT(ic))) <= 2)
+
+ packRegsForAccUse (ic);
+
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignRegisters - assigns registers to each live range as need */
+/*-----------------------------------------------------------------*/
+void ds390_assignRegisters (eBBlock **ebbs, int count)
+{
+ iCode *ic;
+ int i ;
+
+ setToNull((void *)&_G.funcrUsed);
+ ds390_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
+ /* if not register extentions then reduce number
+ of registers */
+ if (options.regExtend)
+ ds390_nRegs = 13;
+ else
+ ds390_nRegs = 8;
+
+ /* 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(".dumppack",ebbs,count);
+
+ /* first determine for each live range the number of
+ registers & the type of registers required for each */
+ regTypeNum ();
+
+ /* and serially allocate registers */
+ serialRegAssign(ebbs,count);
+
+ /* if stack was extended then tell the user */
+ if (_G.stackExtend) {
+/* werror(W_TOOMANY_SPILS,"stack", */
+/* _G.stackExtend,currFunc->name,""); */
+ _G.stackExtend = 0 ;
+ }
+
+ if (_G.dataExtend) {
+/* werror(W_TOOMANY_SPILS,"data space", */
+/* _G.dataExtend,currFunc->name,""); */
+ _G.dataExtend = 0 ;
+ }
+
+ /* after that create the register mask
+ for each of the instruction */
+ createRegMask (ebbs,count);
+
+ /* redo that offsets for stacked automatic variables */
+ redoStackOffsets ();
+
+ if (options.dump_rassgn)
+ dumpEbbsToFileExt(".dumprassgn",ebbs,count);
+
+ /* now get back the chain */
+ ic = iCodeLabelOptimize(iCodeFromeBBlock (ebbs,count));
+
+
+ gen390Code(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 ;
+}