From: michaelh Date: Mon, 17 Jan 2000 06:04:16 +0000 (+0000) Subject: Added z80 port (links, may not work). mcs51 still works. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=5f832da0b82bc7a78f14b96f9e7892f19ac88126;hp=a3d1759c37fa399c45561eda23f696dd25cd5b62;p=fw%2Fsdcc Added z80 port (links, may not work). mcs51 still works. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@11 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/Makefile b/Makefile index 4c8a0976..fee44c81 100644 --- a/Makefile +++ b/Makefile @@ -43,9 +43,7 @@ uninstall: # -------------------------------------------------- clean: $(MAKE) -f clean.mk clean - @for pkg in $(PKGS); do\ - cd $$pkg && $(MAKE) -f clean.mk clean; cd ..;\ - done + for pkg in $(PKGS); do $(MAKE) -C $$pkg clean; done @for prj in $(PRJS); do\ cd $$prj && $(MAKE) clean; cd ..;\ done diff --git a/clean.mk b/clean.mk index 154ae72d..0eba397e 100644 --- a/clean.mk +++ b/clean.mk @@ -3,7 +3,7 @@ clean: rm -f *core *[%~] *.[oa] rm -f .[a-z]*~ - rm -f bin/* + -rm -f bin/* # Deleting all files created by configuring or building the program diff --git a/src/SDCCglobl.h b/src/SDCCglobl.h index 62068c3e..c4e9c977 100644 --- a/src/SDCCglobl.h +++ b/src/SDCCglobl.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "sdccconf.h" #include "SDCCerr.h" @@ -203,6 +204,60 @@ struct options { int iram_size ; /* internal ram size (used only for error checking) */ } ; +/* Processor specific names */ +typedef struct { + /** Target name string, used for --help */ + const char *target_name; + struct { + /** Command to run (eg as-z80) */ + const char *exec_name; + /** Arguments for debug mode */ + const char *debug_opts; + /** Arguments for normal assembly mode */ + const char *plain_opts; + /** TRUE if the output file name should be pre-pended to the args */ + bool requires_output_name; + } assembler; + struct { + /** Command to run (eg link-z80) */ + const char *exec_name; + } linker; + /** Basic type sizes */ + struct { + int char_size; + int short_size; + int int_size; + int long_size; + int ptr_size; + int fptr_size; + int gptr_size; + int bit_size; + int float_size; + int max_base_size; + } s; + struct { + /** -1 for grows down (z80), +1 for grows up (mcs51) */ + int direction; + /** Extra overhead when calling between banks */ + int bank_overhead; + /** Extra overhead when the function is an ISR */ + int isr_overhead; + /** Standard overhead for a function call */ + int call_overhead; + /** Initial SP offset */ + int start_sp; + } stack; + struct { + /** One more than the smallest mul/div operation the processor can do nativley + Eg if the processor has an 8 bit mul, nativebelow is 2 */ + int nativebelow; + + } muldiv; + +} PROCESSOR_CONSTANTS; + +extern const PROCESSOR_CONSTANTS port; + /* forward definition for variables accessed globally */ extern char *currFname ; extern char *srcFileName; /* source file name without the extenstion */ diff --git a/src/mcs51/Makefile b/src/mcs51/Makefile index ccf2b5b7..b8f9ab40 100644 --- a/src/mcs51/Makefile +++ b/src/mcs51/Makefile @@ -2,7 +2,7 @@ PRJDIR = ../.. include $(PRJDIR)/Makefile.common -OBJ = gen.o ralloc.o +OBJ = gen.o ralloc.o main.o LIB = port.a CFLAGS = -ggdb -Wall diff --git a/src/mcs51/main.c b/src/mcs51/main.c new file mode 100644 index 00000000..dfba2348 --- /dev/null +++ b/src/mcs51/main.c @@ -0,0 +1,28 @@ +#include "SDCCglobl.h" +#include "main.h" + +/* Globals */ +PROCESSOR_CONSTANTS port = { + "MCU 8051", /* Target name */ + { + "asx8051", /* Assembler executable name */ + "-plosgffc", /* Options with debug */ + "-plosgff", /* Options without debug */ + FALSE /* TRUE if the assembler requires an output name */ + }, + { + "aslink", /* Linker executable name */ + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 1, 2, 4, 1, 2, 3, 1, 4, 4 + }, + { + +1, 1, 4, 0, 0 + }, + /* mcs51 has an 8 bit mul */ + { + 1 + } +}; + diff --git a/src/mcs51/main.h b/src/mcs51/main.h new file mode 100644 index 00000000..c4d16020 --- /dev/null +++ b/src/mcs51/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions(char **argv, int *pargc); +void x_setDefaultOptions(void); +void x_finaliseOptions(void); + +#endif diff --git a/src/z80/Makefile b/src/z80/Makefile new file mode 100644 index 00000000..77f51e6d --- /dev/null +++ b/src/z80/Makefile @@ -0,0 +1,19 @@ +PRJDIR = ../.. + +include $(PRJDIR)/Makefile.common + +OBJ = icode.o gen.o ralloc.o main.o glue.o mem.o +LIB = port.a + +CFLAGS = -ggdb -Wall +CFLAGS += -I.. -I. -I../.. + +all: $(LIB) + +$(LIB): $(OBJ) + rm -f $(LIB) + ar r $(LIB) $(OBJ) + ranlib $(LIB) + +clean: + rm -f $(LIB) *.o *~ diff --git a/src/z80/gen.c b/src/z80/gen.c new file mode 100644 index 00000000..41d9cdfc --- /dev/null +++ b/src/z80/gen.c @@ -0,0 +1,3754 @@ +/*------------------------------------------------------------------------- + SDCCgen51.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) + + 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 +#include +#include +#include +#include "SDCCglobl.h" + +#ifdef HAVE_SYS_ISA_DEFS_H +#include +#endif + +#include "SDCCast.h" +#include "SDCCmem.h" +#include "SDCCy.h" +#include "SDCChasht.h" +#include "SDCCbitv.h" +#include "SDCCset.h" +#include "SDCCicode.h" +#include "SDCClabel.h" +#include "SDCCBBlock.h" +#include "SDCCloop.h" +#include "SDCCcse.h" +#include "SDCCcflow.h" +#include "SDCCdflow.h" +#include "SDCClrange.h" +#include "ralloc.h" +#include "gen.h" +#include "SDCCpeeph.h" + +/* 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 ; +static char *fReturn[] = {"l", "h", "e", "d" }; +static char *accUse[] = {"a" }; +short rbank = -1; +short accInUse = 0 ; +short inLine = 0; +short debugLine = 0; +short nregssaved = 0; +extern int ptrRegReq ; +extern int nRegs; +extern FILE *codeOutFile; +set *sendSet = NULL; +#define RESULTONSTACK(x) \ + (IC_RESULT(x) && IC_RESULT(x)->aop && \ + IC_RESULT(x)->aop->type == AOP_STK ) + +#define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x); +#define CLRC emitcode("xor","a,a"); + +#define LABEL_STR "%05d$" + +lineNode *lineHead = NULL; +lineNode *lineCurr = NULL; + +unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, +0xE0, 0xC0, 0x80, 0x00}; +unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, +0x07, 0x03, 0x01, 0x00}; + +static int _lastStack = 0; + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 + +/* Stack frame: + + IX+4 param0 LH + IX+2 ret LH + IX+0 ix LH + IX-2 temp0 LH +*/ + +/*-----------------------------------------------------------------*/ +/* emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +void emitcode (const char *inst, const char *fmt, ...) +{ + va_list ap; + char lb[MAX_INLINEASM]; + char *lbp = lb; + + va_start(ap,fmt); + + if (*inst != '\0') { + sprintf(lb,"%s\t",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 = inLine; + lineCurr->isDebug = debugLine; + va_end(ap); +} + +const char *getPairName(asmop *aop) +{ + if (aop->type == AOP_REG) { + switch (aop->aopu.aop_reg[0]->rIdx) { + case C_IDX: + return "bc"; + break; + case E_IDX: + return "de"; + break; + case L_IDX: + return "hl"; + break; + } + } + else if (aop->type == AOP_STR) { + switch (*aop->aopu.aop_str[0]) { + case 'c': + return "bc"; + break; + case 'e': + return "de"; + break; + case 'l': + return "hl"; + break; + } + } + assert(0); + return NULL; +} + +/** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */ +bool isPair(asmop *aop) +{ + if (aop->size == 2) { + if (aop->type == AOP_REG) { + if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) { + return TRUE; + } + if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) { + return TRUE; + } + if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) { + return TRUE; + } + } + if (aop->type == AOP_STR) { + if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) { + return TRUE; + } + if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) { + return TRUE; + } + if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) { + return TRUE; + } + } + } + return FALSE; +} + +/** Push a register pair onto the stack */ +void genPairPush(asmop *aop) +{ + emitcode("push", "%s", getPairName(aop)); +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop *newAsmop (short type) +{ + asmop *aop; + + ALLOC(aop,sizeof(asmop)); + aop->type = type; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop *aopForSym (iCode *ic,symbol *sym,bool result) +{ + 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 (sym->onStack || sym->iaccess) { + sym->aop = aop = newAsmop(AOP_STK); + aop->size = getSize(sym->type); + + aop->aopu.aop_stk = sym->stack; + 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 = 2; + return aop; + } + + /* only remaining is far space */ + /* in which case DPTR gets the address */ + sym->aop = aop = newAsmop(AOP_IY); + emitcode ("ld","iy,#%s", sym->rname); + aop->size = getSize(sym->type); + aop->aopu.aop_dir = sym->rname; + + /* if it is in code space */ + if (IN_CODESPACE(space)) + aop->code = 1; + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop *aopForRemat (symbol *sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + asmop *aop = newAsmop(AOP_IMMD); + + 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; + } + + 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 */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +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 && + (sym2->usl.spillLoc == sym1)) + return TRUE ; + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +bool sameRegs (asmop *aop1, asmop *aop2 ) +{ + int i; + + if (aop1 == aop2) + 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) +{ + 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); + 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 < 4 ; i++ ) + aop->aopu.aop_str[i] = fReturn[i]; + return; + } + + /* else spill location */ + sym->aop = op->aop = aop = + aopForSym(ic,sym->usl.spillLoc,result); + 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) +{ + asmop *aop ; + + if (!op) + aop = aaop; + else + aop = op->aop; + + if (!aop) + return ; + + if (aop->freed) + goto dealloc; + + aop->freed = 1; + + switch (aop->type) { + case AOP_STK : + break; + } + +dealloc: + /* all other cases just dealloc */ + if (op ) { + op->aop = NULL; + if (IS_SYMOP(op)) { + OP_SYMBOL(op)->aop = NULL; + /* if the symbol has a spill */ + if (SPIL_LOC(op)) + SPIL_LOC(op)->aop = NULL; + } + } +} + +/*-----------------------------------------------------------------*/ +/* aopLiteral - string from a literal value */ +/*-----------------------------------------------------------------*/ +char *aopLiteral (value *val, int offset) +{ + char *rs; + + /* if it is a float then it gets tricky */ + /* otherwise it is fairly simple */ + if (!IS_FLOAT(val->type)) { + unsigned long v = floatFromVal(val); + + v >>= (offset * 8); + sprintf(buffer,"#0x%02x",((char) v) & 0xff); + ALLOC_ATOMIC(rs,strlen(buffer)+1); + return strcpy (rs,buffer); + } + + assert(0); +} + +char *aopGetWord(asmop *aop, int offset) +{ + char *s = buffer ; + char *rs; + + assert(aop->size == 2); + assert(offset == 0); + + /* depending on type */ + switch (aop->type) { + case AOP_IMMD: + sprintf (s,"#%s",aop->aopu.aop_immd); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_LIT: { + value * val = aop->aopu.aop_lit; + /* if it is a float then it gets tricky */ + /* otherwise it is fairly simple */ + if (!IS_FLOAT(val->type)) { + unsigned long v = floatFromVal(val); + + sprintf(buffer,"#0x%04lx", v); + ALLOC_ATOMIC(rs,strlen(buffer)+1); + return strcpy (rs,buffer); + } + assert(0); + return NULL; + } + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* aopGet - for fetching value of the aop */ +/*-----------------------------------------------------------------*/ +static char *aopGet (asmop *aop, int offset, bool bit16) +{ + 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_IMMD: + if (bit16) + sprintf (s,"#%s",aop->aopu.aop_immd); + else + if (offset) { + assert(offset == 1); + sprintf(s,"#>%s", + aop->aopu.aop_immd); + } + else + sprintf(s,"#<%s", + aop->aopu.aop_immd); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_DIR: + assert(0); + emitcode("ld", "a,(%s+%d)", aop->aopu.aop_dir, offset); + sprintf(s, "a"); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_REG: + return aop->aopu.aop_reg[offset]->name; + + case AOP_IY: + sprintf(s,"%d(iy)", offset); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_STK: + sprintf(s,"%d(ix) ; %u", aop->aopu.aop_stk+offset, offset); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_CRY: + assert(0); + + case AOP_ACC: + if (!offset) { + return "a"; + } + return "#0x00"; + + case AOP_LIT: + return aopLiteral (aop->aopu.aop_lit,offset); + + case AOP_STR: + aop->coff = offset; + return aop->aopu.aop_str[offset]; + } + + fprintf(stderr, "Type %u\n", aop->type); + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopget got unsupported aop->type"); + exit(0); +} + +bool isRegString(char *s) +{ + if (!strcmp(s, "b") || + !strcmp(s, "c") || + !strcmp(s, "d") || + !strcmp(s, "e") || + !strcmp(s, "a") || + !strcmp(s, "h") || + !strcmp(s, "l")) + return TRUE; + return FALSE; +} + +bool isConstant(char *s) +{ + return (*s == '#'); +} + +bool canAssignToPtr(char *s) +{ + if (isRegString(s)) + return TRUE; + if (isConstant(s)) + return TRUE; + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +static void aopPut (asmop *aop, char *s, int offset) +{ + char *d = buffer ; + + 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: + assert(0); + /* Direct. Hmmm. */ + emitcode("ld", "a,%s", s); + emitcode("ld", "(%s+%d),a", d, offset); + break; + + case AOP_REG: + /* Dont bother if it's a ld x,x */ + if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0) { + emitcode("ld","%s,%s", + aop->aopu.aop_reg[offset]->name,s); + } + break; + + case AOP_IY: + if (!canAssignToPtr(s)) { + emitcode("ld", "a,%s", s); + emitcode("ld", "%d(iy),a", offset); + } + else + emitcode("ld", "%d(iy),%s", offset, s); + break; + + case AOP_STK: + if (!canAssignToPtr(s)) { + emitcode("ld", "a,%s", s); + emitcode("ld", "%d(ix),a", aop->aopu.aop_stk+offset); + } + else + emitcode("ld", "%d(ix),%s", aop->aopu.aop_stk+offset, s); + break; + + case AOP_CRY: + /* if bit variable */ + if (!aop->aopu.aop_dir) { + emitcode("ld", "a,#0"); + emitcode("rla", ""); + } else { + /* In bit space but not in C - cant happen */ + assert(0); + } + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp(aop->aopu.aop_str[offset],s)) { + emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s); + } + break; + + case AOP_ACC: + aop->coff = offset; + if (!offset && (strcmp(s,"acc") == 0)) + break; + if (offset>0) { + emitcode("", "; Error aopPut AOP_ACC"); + } + else { + if (strcmp(aop->aopu.aop_str[offset],s)) + emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s); + } + break; + + default : + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopPut got unsupported aop->type"); + exit(0); + } +} + +#define AOP(op) op->aop +#define AOP_TYPE(op) AOP(op)->type +#define AOP_SIZE(op) AOP(op)->size +#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY)) + +/*-----------------------------------------------------------------*/ +/* getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +int getDataSize(operand *op) +{ + int size; + size = AOP_SIZE(op); + if(size == 3) { + /* pointer */ + assert(0); + } + return size; +} + +/*-----------------------------------------------------------------*/ +/* 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); + + if (!sign) { + aopPut(AOP(result),l,offr); + } + else { + assert(0); + } + } +} + + +/** Put Acc into a register set + */ +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++); + } + } +} + +/** Take the value in carry and put it into a register + */ +void outBitC(operand *result) +{ + /* if the result is bit */ + if (AOP_TYPE(result) == AOP_CRY) { + emitcode("", "; Note: outBitC form 1"); + aopPut(AOP(result),"blah",0); + } + else { + emitcode("ld", "a,#0"); + emitcode("rla", ""); + outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +void toBoolean(operand *oper) +{ + int size = AOP_SIZE(oper); + int offset = 0; + if (size>1) { + emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE)); + size--; + while (size--) + emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE)); + } + else { + CLRC; + emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE)); + } +} + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void genNot (iCode *ic) +{ + link *optype = operandType(IC_LEFT(ic)); + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* if in bit space then a special case */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) { + assert(0); + } + + /* if type float then do float */ + if (IS_FLOAT(optype)) { + assert(0); + } + + toBoolean(IC_LEFT(ic)); + + /* Not of A: + If A == 0, !A = 1 + else A = 0 + So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */ + emitcode("sub", "a,#0x01"); + outBitC(IC_RESULT(ic)); + + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic); + freeAsmop(IC_RESULT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void genCpl (iCode *ic) +{ + int offset = 0; + int size ; + + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* 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 ) { + assert(0); + } + + size = AOP_SIZE(IC_RESULT(ic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE); + MOVA(l); + emitcode("cpl",""); + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic); + freeAsmop(IC_RESULT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void genUminus (iCode *ic) +{ + assert(0); +} + + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +void assignResultValue(operand * oper) +{ + int offset = 0; + int size = AOP_SIZE(oper); + while (size--) { + aopPut(AOP(oper),fReturn[offset],offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void genIpush (iCode *ic) +{ + int size, offset = 0 ; + char *l; + + + /* if this is not a parm push : ie. it is spill push + and spill push is always done on the local stack */ + if (!ic->parmPush) { + /* and the item is spilt then do nothing */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + /* push it on the stack */ + if (isPair(AOP(IC_LEFT(ic)))) { + emitcode("push", getPairName(AOP(IC_LEFT(ic)))); + } + else { + offset = size; + while (size--) { + l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE); + /* Simple for now - load into A and PUSH AF */ + emitcode("ld", "a,%s", l); + emitcode("push", "af"); + emitcode("inc", "sp"); + } + } + return ; + } + + /* Hmmm... what about saving the currently used registers + at this point? */ + + /* then do the push */ + aopOp(IC_LEFT(ic),ic,FALSE); + + size = AOP_SIZE(IC_LEFT(ic)); + + if (isPair(AOP(IC_LEFT(ic)))) { + emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic)))); + } + else { + if (size == 2) { + char *s = aopGetWord(AOP(IC_LEFT(ic)), 0); + if (s) { + emitcode("ld", "hl,%s", s); + emitcode("push", "hl"); + goto release; + } + } + offset = size; + while (size--) { + l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE); + emitcode("ld", "a,%s", l); + emitcode("push", "af"); + emitcode("inc", "sp"); + } + } + release: + freeAsmop(IC_LEFT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void genIpop (iCode *ic) +{ + int size,offset ; + + + /* if the temp was not pushed then */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + offset = (size-1); + if (isPair(AOP(IC_LEFT(ic)))) { + emitcode("pop", getPairName(AOP(IC_LEFT(ic)))); + } + else { + while (size--) { + emitcode("dec", "sp"); + emitcode("pop", "hl"); + aopPut(AOP(IC_LEFT(ic)), "l", offset--); + } + } + + freeAsmop(IC_LEFT(ic),NULL,ic); +} + +/** Emit the code for a call statement + */ +static void emitCall (iCode *ic, bool ispcall) +{ + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) { + /* PENDING */ + } + + /* if send set is not empty then assign */ + if (sendSet) { + iCode *sic ; + + for (sic = setFirstItem(sendSet) ; sic ; + sic = setNextItem(sendSet)) { + int size, offset = 0; + aopOp(IC_LEFT(sic),sic,FALSE); + size = AOP_SIZE(IC_LEFT(sic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(sic)),offset, + FALSE); + if (strcmp(l,fReturn[offset])) + emitcode("ld","%s,%s", + fReturn[offset], + l); + offset++; + } + freeAsmop (IC_LEFT(sic),NULL,sic); + } + sendSet = NULL; + } + + if (ispcall) { + symbol *rlbl = newiTempLabel(NULL); + + emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100)); + emitcode("push", "hl"); + + aopOp(IC_LEFT(ic),ic,FALSE); + emitcode("ld", "l,%s", aopGet(AOP(IC_LEFT(ic)), 0,FALSE)); + emitcode("ld", "h,%s", aopGet(AOP(IC_LEFT(ic)), 1,FALSE)); + freeAsmop(IC_LEFT(ic),NULL,ic); + + emitcode("jp", "(hl)"); + emitcode("","%05d$:",(rlbl->key+100)); + } + else { + /* make the call */ + emitcode("call", "%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)) ) { + + accInUse++; + aopOp(IC_RESULT(ic),ic,FALSE); + accInUse--; + + assignResultValue(IC_RESULT(ic)); + + freeAsmop(IC_RESULT(ic),NULL, ic); + } + + /* adjust the stack for parameters if required */ + if (IC_LEFT(ic)->parmBytes) { + int i = IC_LEFT(ic)->parmBytes; + /* PENDING: do better */ + while (i>1) { + emitcode("pop", "hl"); + i-=2; + } + if (i) + emitcode("inc", "sp"); + } + +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void genCall (iCode *ic) +{ + emitCall(ic, FALSE); +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void genPcall (iCode *ic) +{ + emitCall(ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int resultRemat (iCode *ic) +{ + if (SKIP_IC(ic) || ic->op == IFX) + return 0; + + if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) { + symbol *sym = OP_SYMBOL(IC_RESULT(ic)); + if (sym->remat && !POINTER_SET(ic)) + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void genFunction (iCode *ic) +{ + symbol *sym; + link *fetype; + + 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("di",""); + + /* if this is an interrupt service routine then + save acc, b, dpl, dph */ + if (IS_ISR(sym->etype)) { + emitcode("push", "af"); + emitcode("push", "bc"); + emitcode("push", "de"); + emitcode("push", "hl"); + } else { + /* if callee-save to be used for this function + then save the registers being used in this function */ + if (sym->calleeSave) { + /* Handled by ncsv/csv */ + } + else { + assert(0); + } + } + + /* adjust the stack for the function */ + emitcode("push", "de"); + emitcode("push", "bc"); + emitcode("push", "ix"); + emitcode("ld", "ix,#0"); + emitcode("add", "ix,sp"); + + _lastStack = sym->stack; + + if (sym->stack) { + emitcode("ld", "hl,#-%d", sym->stack); + emitcode("add", "hl,sp"); + emitcode("ld", "sp,hl"); + } +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void genEndFunction (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_LEFT(ic)); + + if (IS_ISR(sym->etype)) { + assert(0); + } + else { + if (SPEC_CRTCL(sym->etype)) + emitcode("ei", ""); + + if (sym->calleeSave) { + /* Handled by cret */ + } + else { + assert(0); + } + + /* if debug then send end of function */ + if (options.debug && currFunc) { + 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); + debugLine = 0; + } + emitcode("ld", "sp,ix"); + emitcode("pop", "ix"); + emitcode("pop", "bc"); + emitcode("pop", "de"); + emitcode("ret", ""); + } + +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void genRet (iCode *ic) +{ + char *l; + /* Errk. This is a hack until I can figure out how + to cause dehl to spill on a call */ + int size,offset = 0; + + /* if we have no return value then + just generate the "ret" */ + if (!IC_LEFT(ic)) + goto jumpret; + + /* we have something to return then + move the return value into place */ + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + + if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) { + emitcode("ld", "hl,%s", l); + } + else { + while (size--) { + l = aopGet(AOP(IC_LEFT(ic)),offset, + FALSE); + if (strcmp(fReturn[offset],l)) + emitcode("ld","%s,%s",fReturn[offset++],l); + } + } + freeAsmop (IC_LEFT(ic),NULL,ic); + + 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("jp", LABEL_STR ,(returnLabel->key+100)); +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void genLabel (iCode *ic) +{ + /* special case never generate */ + if (IC_LABEL(ic) == entryLabel) + return ; + + emitcode("", LABEL_STR ":",(IC_LABEL(ic)->key+100)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a ljmp */ +/*-----------------------------------------------------------------*/ +static void genGoto (iCode *ic) +{ + emitcode ("jp", LABEL_STR ,(IC_LABEL(ic)->key+100)); +} + +/*-----------------------------------------------------------------*/ +/* 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 ; + + /* Inc a pair */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + isPair(AOP(IC_RESULT(ic)))) { + while (icount--) { + emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic)))); + } + return TRUE; + } + /* if increment 16 bits in register */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + (size > 1) && + (icount == 1)) { + symbol *tlbl = newiTempLabel(NULL); + emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE)); + emitcode("jp", "nz," LABEL_STR ,tlbl->key+100); + + emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE)); + if(size == 4) { + assert(0); + } + emitcode("", LABEL_STR ":",tlbl->key+100); + return TRUE; + } + + /* If result is a pair */ + if (isPair(AOP(IC_RESULT(ic)))) { + movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0); + movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0); + while (icount--) + emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic)))); + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ + if (AOP_SIZE(IC_RESULT(ic)) > 1 || + AOP_SIZE(IC_LEFT(ic)) > 1 ) + return FALSE ; + + /* we can if the aops of the left & result match or + if they are in registers and the registers are the + same */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + while (icount--) + emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE)); + + return TRUE ; + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* outBitAcc - output a bit in acc */ +/*-----------------------------------------------------------------*/ +void outBitAcc(operand *result) +{ + symbol *tlbl = newiTempLabel(NULL); + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY){ + assert(0); + } + else { + emitcode("jp","z," LABEL_STR ,tlbl->key+100); + emitcode("ld","a,%s",one); + emitcode("", LABEL_STR ":",tlbl->key+100); + outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void genPlus (iCode *ic) +{ + int size, offset = 0; + + /* special cases :- */ + + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RIGHT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* Swap the left and right operands if: + + 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) { + /* Cant happen */ + assert(0); + } + + /* if left in bit space & right literal */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) { + /* Can happen I guess */ + assert(0); + } + + /* if I can do an increment instead + of add then GOOD for ME */ + if (genPlusIncr (ic) == TRUE) + goto release; + + size = getDataSize(IC_RESULT(ic)); + + while(size--) { + if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) { + MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE)); + if(offset == 0) + emitcode("add","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE)); + else + emitcode("adc","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE)); + } else { + MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE)); + if(offset == 0) + emitcode("add","a,%s", + aopGet(AOP(IC_LEFT(ic)),offset,FALSE)); + else + emitcode("adc","a,%s", + aopGet(AOP(IC_LEFT(ic)),offset,FALSE)); + } + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + /* Some kind of pointer arith. */ + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_LEFT(ic)) == 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)))) + assert(0); + + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_RIGHT(ic)) == 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) + assert(0); + + +release: + freeAsmop(IC_LEFT(ic),NULL,ic); + freeAsmop(IC_RIGHT(ic),NULL,ic); + freeAsmop(IC_RESULT(ic),NULL,ic); + +} + +/*-----------------------------------------------------------------*/ +/* 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)) > 2) + return FALSE; + + size = getDataSize(IC_RESULT(ic)); + /* if decrement 16 bits in register */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + (size > 1) && isPair(AOP(IC_RESULT(ic)))) { + while (icount--) + emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic)))); + return TRUE; + } + + /* If result is a pair */ + if (isPair(AOP(IC_RESULT(ic)))) { + movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0); + movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0); + while (icount--) + emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic)))); + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ + if (AOP_SIZE(IC_RESULT(ic)) > 1 || + AOP_SIZE(IC_LEFT(ic)) > 1 ) + return FALSE ; + + /* we can if the aops of the left & result match or if they are in + registers and the registers are the same */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) { + while (icount--) + emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE)); + return TRUE ; + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static void genMinus (iCode *ic) +{ + int size, offset = 0; + unsigned long lit = 0L; + + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RIGHT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* special cases :- */ + /* if both left & right are in bit space */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + assert(0); + goto release ; + } + + /* if I can do an decrement instead of subtract then GOOD for ME */ + if (genMinusDec (ic) == TRUE) + goto release; + + size = getDataSize(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)); + if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) + emitcode("sbc","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE)); + else{ + /* first add without previous c */ + if (!offset) + emitcode("add","a,#0x%02x", + (unsigned int)(lit & 0x0FFL)); + else + emitcode("adc","a,#0x%02x", + (unsigned int)((lit >> (offset*8)) & 0x0FFL)); + } + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_LEFT(ic)) == 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)))) + assert(0); + +release: + freeAsmop(IC_LEFT(ic),NULL,ic); + freeAsmop(IC_RIGHT(ic),NULL,ic); + freeAsmop(IC_RESULT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genMult - generates code for multiplication */ +/*-----------------------------------------------------------------*/ +static void genMult (iCode *ic) +{ + /* Shouldn't occur - all done through function calls */ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* genDiv - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genDiv (iCode *ic) +{ + /* Shouldn't occur - all done through function calls */ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genMod (iCode *ic) +{ + /* Shouldn't occur - all done through function calls */ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* genIfxJump :- will create a jump depending on the ifx */ +/*-----------------------------------------------------------------*/ +static void genIfxJump (iCode *ic, char *jval) +{ + symbol *jlbl ; + const char *inst; + + /* if true label then we jump if condition + supplied is true */ + if ( IC_TRUE(ic) ) { + jlbl = IC_TRUE(ic); + if (!strcmp(jval, "a")) { + inst = "nz"; + } + else if (!strcmp(jval, "c")) { + inst = "c"; + } + else { + /* The buffer contains the bit on A that we should test */ + inst = "nz"; + } + } + else { + /* false label is present */ + jlbl = IC_FALSE(ic) ; + if (!strcmp(jval, "a")) { + inst = "z"; + } + else if (!strcmp(jval, "c")) { + inst = "nc"; + } + else { + /* The buffer contains the bit on A that we should test */ + inst = "z"; + } + } + /* Z80 can do a conditional long jump */ + if (!strcmp(jval, "a")) { + emitcode("or", "a,a"); + } + else if (!strcmp(jval, "c")) { + } + else { + emitcode("bit", "%s,a", jval); + } + emitcode("jp", "%s," LABEL_STR , inst, jlbl->key+100); + + /* mark the icode as generated */ + ic->generated = 1; +} + +/** Generic compare for > or < + */ +static void genCmp (operand *left,operand *right, + operand *result, iCode *ifx, int sign) +{ + int size, offset = 0 ; + unsigned long lit = 0L; + + /* if left & right are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + /* Cant happen on the Z80 */ + assert(0); + } 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, just compare */ + if((size == 1) && !sign && + (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){ + emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE)); + emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE)); + } + 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) { + /* No sign so it's always false */ + CLRC; + } + else{ + /* Just load in the top most bit */ + MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE)); + if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) { + assert(0); + genIfxJump (ifx,"acc.7"); + return; + } + else + emitcode("rlc","a"); + } + goto release; + } + } + while (size--) { + /* Do a long subtract */ + MOVA(aopGet(AOP(left),offset,FALSE)); + if (sign && size == 0) { + /* Case where it's signed and we've hit the end */ + assert(0); + } else { + /* Subtract through, propagating the carry */ + if (offset==0) { + emitcode("sub","a,%s",aopGet(AOP(right),offset++,FALSE)); + } + else + emitcode("sbc","a,%s",aopGet(AOP(right),offset++,FALSE)); + } + } + } + } + +release: + 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 ; + + 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 */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + genCmp(right, left, result, ifx, sign); + + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genCmpLt - less than comparisons */ +/*-----------------------------------------------------------------*/ +static void genCmpLt (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + link *letype , *retype; + int sign ; + + 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 */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + genCmp(left, right, result, ifx, sign); + + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* 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; + + /* Swap the left and right if it makes the computation easier */ + if (AOP_TYPE(left) == AOP_LIT) { + operand *t = right; + right = left; + left = t; + } + + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + /* if the right side is a literal then anything goes */ + if (AOP_TYPE(right) == AOP_LIT && + AOP_TYPE(left) != AOP_DIR ) { + while (size--) { + emitcode("ld", "a,%s", aopGet(AOP(left),offset,FALSE)); + emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE)); + emitcode("jp", "nz," LABEL_STR , 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)) { + while (size--) { + MOVA(aopGet(AOP(left),offset,FALSE)); + if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) && + ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0)) + /* PENDING */ + emitcode("jp","nz," LABEL_STR ,lbl->key+100); + else { + emitcode("cp", "%s", aopGet(AOP(right),offset,FALSE)); + emitcode("jp", "nz," LABEL_STR , lbl->key+100); + } + offset++; + } + } else { + assert(0); + } +} + +/*-----------------------------------------------------------------*/ +/* gencjne - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjne(operand *left, operand *right, symbol *lbl) +{ + symbol *tlbl = newiTempLabel(NULL); + + gencjneshort(left, right, lbl); + + /* PENDING: ?? */ + emitcode("ld","a,%s",one); + emitcode("jp", LABEL_STR ,tlbl->key+100); + emitcode("", LABEL_STR ":",lbl->key+100); + emitcode("xor","a,a"); + emitcode("", LABEL_STR ":",tlbl->key+100); +} + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void genCmpEq (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + + /* Swap operands if it makes the operation easier. ie if: + 1. Left is a literal. + */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) { + operand *t = IC_RIGHT(ic); + IC_RIGHT(ic) = IC_LEFT(ic); + IC_LEFT(ic) = t; + } + + if (ifx && !AOP_SIZE(result)){ + symbol *tlbl; + /* if they are both bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) { + assert(0); + } else { + tlbl = newiTempLabel(NULL); + gencjneshort(left, right, tlbl); + if ( IC_TRUE(ifx) ) { + emitcode("jp", LABEL_STR ,IC_TRUE(ifx)->key+100); + emitcode("", LABEL_STR ":",tlbl->key+100); + } else { + /* PENDING: do this better */ + symbol *lbl = newiTempLabel(NULL); + emitcode("jp", LABEL_STR ,lbl->key+100); + emitcode("", LABEL_STR ":",tlbl->key+100); + emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100); + emitcode("", LABEL_STR ":",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))) { + assert(0); + } else { + gencjne(left,right,newiTempLabel(NULL)); + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) { + assert(0); + } + 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); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* 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; + + /* note here that && operations that are in an if statement are + taken away by backPatchLabels only those used in arthmetic + operations remain */ + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,FALSE); + + /* if both are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + assert(0); + } else { + tlbl = newiTempLabel(NULL); + toBoolean(left); + emitcode("jp","z," LABEL_STR ,tlbl->key+100); + toBoolean(right); + emitcode("", LABEL_STR ":",tlbl->key+100); + outBitAcc(result); + } + + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genOrOp - for || operation */ +/*-----------------------------------------------------------------*/ +static void genOrOp (iCode *ic) +{ + operand *left,*right, *result; + symbol *tlbl; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,FALSE); + + /* if both are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + assert(0); + } else { + tlbl = newiTempLabel(NULL); + toBoolean(left); + emitcode("jp","nz," LABEL_STR,tlbl->key+100); + toBoolean(right); + emitcode("", LABEL_STR,tlbl->key+100); + outBitAcc(result); + } + + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* isLiteralBit - test if lit == 2^n */ +/*-----------------------------------------------------------------*/ +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; +} + +/*-----------------------------------------------------------------*/ +/* 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; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + +#ifdef DEBUG_TYPE + emitcode("","; Type res[%d] = l[%d]&r[%d]", + AOP_TYPE(result), + AOP_TYPE(left), AOP_TYPE(right)); + emitcode("","; Size res[%d] = l[%d]&r[%d]", + AOP_SIZE(result), + AOP_SIZE(left), AOP_SIZE(right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + AOP_NEEDSACC(left)) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange 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 (AOP_TYPE(left) == AOP_CRY){ + assert(0); + 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)); + // bit = left & 2^n + if(size) { + assert(0); + emitcode("mov","c,acc.%d",posbit&0x07); + } + // if(left & 2^n) + else{ + if (ifx) { + sprintf(buffer, "%d", posbit&0x07); + genIfxJump(ifx, buffer); + } + else { + assert(0); + } + goto release; + } + } else { + symbol *tlbl = newiTempLabel(NULL); + int sizel = AOP_SIZE(left); + if(size) { + assert(0); + emitcode("setb","c"); + } + while(sizel--){ + if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){ + MOVA( aopGet(AOP(left),offset,FALSE)); + // byte == 2^n ? + if((posbit = isLiteralBit(bytelit)) != 0) { + assert(0); + emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100); + } + else{ + if(bytelit != 0x0FFL) + emitcode("and","a,%s", + aopGet(AOP(right),offset,FALSE)); + emitcode("jr","nz, %05d$",tlbl->key+100); + } + } + offset++; + } + // bit = left & literal + if (size){ + emitcode("clr","c"); + emitcode("","%05d$:",tlbl->key+100); + } + // if(left & literal) + else{ + if(ifx) +#if 0 + jmpTrueOrFalse(ifx, tlbl); +#else + assert(0); +#endif + 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 { + MOVA(aopGet(AOP(left),offset,FALSE)); + emitcode("and","a,%s", + aopGet(AOP(right),offset,FALSE)); + emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE)); + } + } + + } else { + if (AOP_TYPE(left) == AOP_ACC) { + assert(0); + } + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("and","%s,a", + aopGet(AOP(left),offset,FALSE)); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + assert(0); + } 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), + 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("and","a,%s",aopGet(AOP(right),offset,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("and","a,%s", + aopGet(AOP(left),offset,FALSE)); + } + aopPut(AOP(result),"a",offset); + } + } + + } + +release : + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genOr - code for or */ +/*-----------------------------------------------------------------*/ +static void genOr (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + +#ifdef DEBUG_TYPE + emitcode("","; Type res[%d] = l[%d]&r[%d]", + AOP_TYPE(result), + AOP_TYPE(left), AOP_TYPE(right)); + emitcode("","; Size res[%d] = l[%d]&r[%d]", + AOP_SIZE(result), + AOP_SIZE(left), AOP_SIZE(right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + AOP_NEEDSACC(left)) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange 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 (AOP_TYPE(left) == AOP_CRY){ + assert(0); + goto release ; + } + + if((AOP_TYPE(right) == AOP_LIT) && + (AOP_TYPE(result) == AOP_CRY) && + (AOP_TYPE(left) != AOP_CRY)){ + assert(0); + 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 + emitcode("or","%s,%s", + aopGet(AOP(left),offset,FALSE), + aopGet(AOP(right),offset,FALSE)); + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("or","a,%s", + aopGet(AOP(left),offset,FALSE)); + aopPut(AOP(result),"a",0); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + assert(0); + } 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), + offset); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE(left) == AOP_ACC) + emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("or","a,%s", + aopGet(AOP(left),offset,FALSE)); + aopPut(AOP(result),"a",0); + } + aopPut(AOP(result),"a",offset); + } + } + +release : + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void genXor (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + + /* 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 (AOP_TYPE(left) == AOP_CRY){ + assert(0); + goto release ; + } + + if((AOP_TYPE(right) == AOP_LIT) && + (AOP_TYPE(result) == AOP_CRY) && + (AOP_TYPE(left) != AOP_CRY)){ + assert(0); + 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 { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("xor","a,%s", + aopGet(AOP(left),offset,FALSE)); + aopPut(AOP(result),"a",0); + } + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("xor","a,%s", + aopGet(AOP(left),offset,FALSE)); + aopPut(AOP(result),"a",0); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + assert(0); + } 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), + offset); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE(left) == AOP_ACC) + emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE)); + emitcode("xor","a,%s", + aopGet(AOP(left),offset,FALSE)); + aopPut(AOP(result),"a",0); + } + aopPut(AOP(result),"a",offset); + } + } + +release : + freeAsmop(left,NULL,ic); + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genInline - write the inline code out */ +/*-----------------------------------------------------------------*/ +static void genInline (iCode *ic) +{ + char buffer[MAX_INLINEASM]; + char *bp = buffer; + char *bp1= buffer; + + 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); */ + inLine -= (!options.asmpeep); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void genRRC (iCode *ic) +{ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* genRLC - generate code for rotate left with carry */ +/*-----------------------------------------------------------------*/ +static void genRLC (iCode *ic) +{ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* shiftR2Left2Result - shift right two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void shiftR2Left2Result (operand *left, int offl, + operand *result, int offr, + int shCount, int sign) +{ + if(sameRegs(AOP(result), AOP(left)) && + ((offl + MSB16) == offr)){ + assert(0); + } else { + movLeft2Result(left, offl, result, offr, 0); + movLeft2Result(left, offl+1, result, offr+1, 0); + } + + if (sign) { + assert(0); + } + else { + /* if (AOP(result)->type == AOP_REG) {*/ + int size = 2; + int offset = 0; + symbol *tlbl , *tlbl1; + char *l; + + /* Left is already in result - so now do the shift */ + if (shCount>1) { + emitcode("ld","a,#%u+1", shCount); + tlbl = newiTempLabel(NULL); + tlbl1 = newiTempLabel(NULL); + emitcode("jp", LABEL_STR ,tlbl1->key+100); + emitcode("", LABEL_STR ":",tlbl->key+100); + } + + emitcode("or", "a,a"); + offset = size; + while (size--) { + l = aopGet(AOP(result), --offset, FALSE); + emitcode("rr","%s", l); + } + if (shCount>1) { + emitcode("", LABEL_STR ":",tlbl1->key+100); + emitcode("dec", "a"); + emitcode("jp","nz," LABEL_STR ,tlbl->key+100); + } + } +} + +/*-----------------------------------------------------------------*/ +/* 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)){ + assert(0); + } else { + /* Copy left into result */ + movLeft2Result(left,offl, result, offr, 0); + } + if (AOP(result)->type == AOP_REG) { + int size = 2; + int offset = 0; + symbol *tlbl , *tlbl1; + char *l; + + /* Left is already in result - so now do the shift */ + if (shCount>1) { + emitcode("ld","a,#%u+1", shCount); + tlbl = newiTempLabel(NULL); + tlbl1 = newiTempLabel(NULL); + emitcode("jp", LABEL_STR ,tlbl1->key+100); + emitcode("", LABEL_STR ":",tlbl->key+100); + } + + emitcode("or", "a,a"); + while (size--) { + l = aopGet(AOP(result),offset++,FALSE); + emitcode("rl","%s", l); + } + if (shCount>1) { + emitcode("", LABEL_STR ":",tlbl1->key+100); + emitcode("dec", "a"); + emitcode("jp","nz," LABEL_STR ,tlbl->key+100); + } + } + else { + /* PENDING: do something */ + assert(0); + } +} + +/*-----------------------------------------------------------------*/ +/* AccRol - rotate left accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccRol (int shCount) +{ + shCount &= 0x0007; // shCount : 0..7 + switch(shCount){ + case 0 : + break; + case 1 : + emitcode("rl","a"); + break; + case 2 : + emitcode("rl","a"); + emitcode("rl","a"); + break; + case 3 : + emitcode("rl","a"); + emitcode("rl","a"); + emitcode("rl","a"); + break; + case 4 : + emitcode("rl","a"); + emitcode("rl","a"); + emitcode("rl","a"); + emitcode("rl","a"); + break; + case 5 : + emitcode("rr","a"); + emitcode("rr","a"); + emitcode("rr","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,a"); + else + if(shCount == 2) { + emitcode("add","a,a"); + emitcode("add","a,a"); + } else { + /* rotate left accumulator */ + AccRol(shCount); + /* and kill the lower order bits */ + emitcode("and","a,#0x%02x", SLMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* 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); + MOVA(l); + /* shift left accumulator */ + AccLsh(shCount); + aopPut(AOP(result),"a",offr); +} + + +/*-----------------------------------------------------------------*/ +/* genlshTwo - left shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genlshTwo (operand *result,operand *left, int shCount) +{ + int size = AOP_SIZE(result); + + assert(size==2); + + /* if shCount >= 8 */ + if (shCount >= 8) { + shCount -= 8 ; + + if (size > 1){ + if (shCount) { + movLeft2Result(left, LSB, result, MSB16, 0); + aopPut(AOP(result),zero, 0); + shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8); + } + else { + movLeft2Result(left, LSB, result, MSB16, 0); + aopPut(AOP(result),zero, 0); + } + } + aopPut(AOP(result),zero,LSB); + } + /* 1 <= shCount <= 7 */ + else { + if(size == 1) { + assert(0); + } + else { + shiftL2Left2Result(left, LSB, result, LSB, shCount); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genlshOne - left shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void genlshOne (operand *result, operand *left, int shCount) +{ + shiftL1Left2Result(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; + + freeAsmop(right,NULL,ic); + + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + 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) { + assert(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: + genlshTwo (result,left,shCount); + break; + case 4: + assert(0); + break; + default: + assert(0); + } + } + freeAsmop(left,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void genLeftShift (iCode *ic) +{ + int size, offset; + char *l; + symbol *tlbl , *tlbl1; + operand *left,*right, *result; + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genLeftShiftLiteral (left,right,result,ic); + return ; + } + + /* shift count is unknown then we have to form a loop get the loop + count in B : Note: we take only the lower order byte since + shifting more that 32 bits make no sense anyway, ( the largest + size of an object can be only 32 bits ) */ + emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE)); + emitcode("inc","a"); + freeAsmop (right,NULL,ic); + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ +#if 1 + if (!sameRegs(AOP(left),AOP(result))) { + + size = AOP_SIZE(result); + offset = 0; + while (size--) { + l = aopGet(AOP(left),offset,FALSE); + aopPut(AOP(result),l,offset); + offset++; + } + } +#else + size = AOP_SIZE(result); + offset = 0; + while (size--) { + l = aopGet(AOP(left),offset,FALSE); + aopPut(AOP(result),l,offset); + offset++; + } +#endif + + + tlbl = newiTempLabel(NULL); + size = AOP_SIZE(result); + offset = 0 ; + tlbl1 = newiTempLabel(NULL); + + emitcode("jp", LABEL_STR ,tlbl1->key+100); + emitcode("", LABEL_STR ":",tlbl->key+100); + l = aopGet(AOP(result),offset,FALSE); + emitcode("or", "a,a"); + while (size--) { + l = aopGet(AOP(result),offset++,FALSE); + emitcode("rl","%s", l); + } + emitcode("", LABEL_STR ":",tlbl1->key+100); + emitcode("dec", "a"); + emitcode("jp","nz," LABEL_STR ,tlbl->key+100); + + freeAsmop(left,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/* genlshTwo - left shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genrshOne (operand *result,operand *left, int shCount) +{ + /* Errk */ + int size = AOP_SIZE(result); + char *l; + + assert(size==1); + assert(shCount<8); + + l = aopGet(AOP(left),0,FALSE); + if (AOP(result)->type == AOP_REG) { + aopPut(AOP(result), l, 0); + l = aopGet(AOP(result), 0, FALSE); + while (shCount--) + emitcode("srl", "%s", l); + } + else { + MOVA(l); + while (shCount--) { + emitcode("srl", "a"); + } + aopPut(AOP(result),"a",0); + } +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccRsh (int shCount) +{ + if(shCount != 0){ + if(shCount == 1){ + CLRC; + emitcode("rr","a"); + } else { + /* rotate right accumulator */ + AccRol(8 - shCount); + /* and kill the higher order bits */ + emitcode("and","a,#0x%02x", SRMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* 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)); + if (sign) { + assert(0); + } + else { + AccRsh(shCount); + } + aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* genrshTwo - right shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genrshTwo (operand *result,operand *left, + int shCount, int sign) +{ + /* if shCount >= 8 */ + if (shCount >= 8) { + shCount -= 8 ; + if (shCount) { + assert(0); + shiftR1Left2Result(left, MSB16, result, LSB, + shCount, sign); + } + else { + movLeft2Result(left, MSB16, result, LSB, sign); + aopPut(AOP(result),zero,1); + } + } + /* 1 <= shCount <= 7 */ + else { + shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); + } +} + +/*-----------------------------------------------------------------*/ +/* genRightShiftLiteral - left shifting by known count */ +/*-----------------------------------------------------------------*/ +static void genRightShiftLiteral (operand *left, + operand *right, + operand *result, + iCode *ic) +{ + int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit); + int size; + + freeAsmop(right,NULL,ic); + + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + size = getSize(operandType(result)); + + emitcode("; shift right ","result %d, left %d",size, + AOP_SIZE(left)); + + /* I suppose that the left size >= result size */ + if (shCount == 0) { + assert(0); + } + + else if(shCount >= (size * 8)) + while(size--) + aopPut(AOP(result),zero,size); + else{ + switch (size) { + case 1: + genrshOne(result, left, shCount); + break; + case 2: + /* PENDING: sign support */ + genrshTwo(result, left, shCount, FALSE); + break; + case 4: + assert(0); + break; + default: + assert(0); + } + } + freeAsmop(left,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void genRightShift (iCode *ic) +{ + operand *left,*right, *result; + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genRightShiftLiteral (left,right,result,ic); + return ; + } + else { + assert(0); + } +} + +/*-----------------------------------------------------------------*/ +/* 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); + aopOp(result,ic,FALSE); + + if (isPair(AOP(left)) && (AOP_SIZE(result)==1)) { + /* Just do it */ + emitcode("ld", "a,(%s)", getPairName(AOP(left))); + aopPut(AOP(result),"a", 0); + freeAsmop(left,NULL,ic); + goto release; + } + + /* For now we always load into IY */ + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) + emitcode("ld","hl,%s",aopGet(AOP(left),0,TRUE)); + else { /* we need to get it byte by byte */ + emitcode("ld", "l,%s", aopGet(AOP(left), 0, FALSE)); + emitcode("ld", "h,%s", aopGet(AOP(left), 1, FALSE)); + } + /* so iy now contains the address */ + freeAsmop(left,NULL,ic); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) { + assert(0); + } + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + /* PENDING: make this better */ + if (AOP(result)->type == AOP_REG) { + aopPut(AOP(result),"(hl)",offset++); + } + else { + emitcode("ld", "a,(hl)", offset); + aopPut(AOP(result),"a",offset++); + } + if (size) { + emitcode("inc", "hl"); + } + } + } + + release: + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genPointerGet - generate code for pointer get */ +/*-----------------------------------------------------------------*/ +static void genPointerGet (iCode *ic) +{ + operand *left, *result ; + link *type, *etype; + + 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); + + genGenPointerGet (left,result,ic); +} + +bool isRegOrLit(asmop *aop) +{ + if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD) + return TRUE; + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void genGenPointerSet (operand *right, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(right)); + + aopOp(result,ic,FALSE); + aopOp(right,ic,FALSE); + + /* Handle the exceptions first */ + if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) { + /* Just do it */ + char *l = aopGet(AOP(right), 0, FALSE); + MOVA(l); + emitcode("ld", "(%s),a", getPairName(AOP(result))); + freeAsmop(result,NULL,ic); + goto release; + } + + /* 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("", "; Error 2"); + emitcode("ld", "hl,%s", aopGet(AOP(result), 0, TRUE)); + } + else { /* we need to get it byte by byte */ + /* PENDING: do this better */ + emitcode("ld", "l,%s", aopGet(AOP(result), 0, FALSE)); + emitcode("ld", "h,%s", aopGet(AOP(result), 1, FALSE)); + } + } + /* so hl know contains the address */ + freeAsmop(result,NULL,ic); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) { + assert(0); + } + else { + size = AOP_SIZE(right); + offset = 0 ; + + while (size--) { + char *l = aopGet(AOP(right),offset,FALSE); + + if (isRegOrLit(AOP(right))) { + emitcode("ld", "(hl),%s", l); + } + else { + MOVA(l); + emitcode("ld", "(hl),a", offset); + } + if (size) { + emitcode("inc", "hl"); + } + offset++; + } + } + release: + freeAsmop(right,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void genPointerSet (iCode *ic) +{ + operand *right, *result ; + link *type, *etype; + + 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); + + genGenPointerSet (right,result,ic); +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void genIfx (iCode *ic, iCode *popIc) +{ + operand *cond = IC_COND(ic); + int isbit =0; + + aopOp(cond,ic,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); + + /* 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)); + + aopOp(IC_RESULT(ic),ic,FALSE); + + /* if the operand is on the stack then we + need to get the stack offset of this + variable */ + if (sym->onStack) { + /* if it has an offset then we need to compute it */ + emitcode("push", "de"); + emitcode("push", "ix"); + emitcode("pop", "hl"); + emitcode("ld", "de,#%d", sym->stack); + emitcode("add", "hl,de"); + emitcode("pop", "de"); + } + else { + emitcode("ld", "hl,#%s", sym->rname); + } + aopPut(AOP(IC_RESULT(ic)), "l", 0); + aopPut(AOP(IC_RESULT(ic)), "h", 1); + + freeAsmop(IC_RESULT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void genAssign (iCode *ic) +{ + operand *result, *right; + int size, offset ; + unsigned long lit = 0L; + + result = IC_RESULT(ic); + right = IC_RIGHT(ic) ; + + /* Dont bother assigning if they are the same */ + if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) { + emitcode("", "; (operands are equal)"); + return; + } + + aopOp(right,ic,FALSE); + aopOp(result,ic,TRUE); + + /* if they are the same registers */ + if (sameRegs(AOP(right),AOP(result))) { + emitcode("", "; (registers are the same)"); + goto release; + } + + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY) { + assert(0); + } + + /* 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("xor","a,a"); + /* Work from the top down. + Done this way so that we can use the cached copy of 0 + in A for a fast clear */ + while (size--) { + if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0) + aopPut(AOP(result),"a",size); + else + aopPut(AOP(result), + aopGet(AOP(right),size,FALSE), + size); + } + } else { + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE), + offset); + offset++; + } + } + +release: + freeAsmop(right,NULL,ic); + freeAsmop(result,NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - genrates code for jump table */ +/*-----------------------------------------------------------------*/ +static void genJumpTab (iCode *ic) +{ + assert(0); +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void genCast (iCode *ic) +{ + operand *result = IC_RESULT(ic); + link *ctype = operandType(IC_LEFT(ic)); + operand *right = IC_RIGHT(ic); + int size, offset ; + + /* if they are equivalent then do nothing */ + if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + aopOp(right,ic,FALSE) ; + aopOp(result,ic,FALSE); + + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY) { + assert(0); + } + + /* 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), + offset); + offset++; + } + goto release; + } + + /* if the result is of type pointer */ + if (IS_PTR(ctype)) { + assert(0); + } + + /* 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), + offset); + offset++; + } + + /* now depending on the sign of the destination */ + size = AOP_SIZE(result) - AOP_SIZE(right); + /* Unsigned or not an integral type - right fill with zeros */ + if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) { + while (size--) + aopPut(AOP(result),zero,offset++); + } else { + /* we need to extend the sign :{ */ + char *l = aopGet(AOP(right),AOP_SIZE(right) - 1, + FALSE); + MOVA(l); + emitcode("", "; genCast: sign extend untested."); + emitcode("rla", ""); + emitcode("sbc", "a,a"); + while (size--) + aopPut(AOP(result),"a",offset++); + } + +release: + freeAsmop(right, NULL, ic); + freeAsmop(result, NULL, ic); +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void genReceive (iCode *ic) +{ + if (isOperandInFarSpace(IC_RESULT(ic)) && + ( OP_SYMBOL(IC_RESULT(ic))->isspilt || + IS_TRUE_SYMOP(IC_RESULT(ic))) ) { + assert(0); + } else { + accInUse++; + aopOp(IC_RESULT(ic),ic,FALSE); + accInUse--; + assignResultValue(IC_RESULT(ic)); + } + + freeAsmop(IC_RESULT(ic),NULL,ic); +} + +/*-----------------------------------------------------------------*/ +/* genZ80Code - generate code for Z80 based controllers */ +/*-----------------------------------------------------------------*/ +void genZ80Code (iCode *lic) +{ + iCode *ic; + int cln = 0; + + lineHead = lineCurr = NULL; + + /* if debug information required */ + if (options.debug && currFunc) { + cdbSymbol(currFunc,cdbFile,FALSE,TRUE); + debugLine = 1; + if (IS_STATIC(currFunc->etype)) + emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); + else + emitcode("","G$%s$0$0 ==.",currFunc->name); + debugLine = 0; + } + /* stack pointer name */ + spname = "sp"; + + + for (ic = lic ; ic ; ic = ic->next ) { + + if ( cln != ic->lineno ) { + if ( options.debug ) { + debugLine = 1; + emitcode("","C$%s$%d$%d$%d ==.", + ic->filename,ic->lineno, + ic->level,ic->block); + 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 '!' : + emitcode("", "; genNot"); + genNot(ic); + break; + + case '~' : + emitcode("", "; genCpl"); + genCpl(ic); + break; + + case UNARYMINUS: + emitcode("", "; genUminus"); + genUminus (ic); + break; + + case IPUSH: + emitcode("", "; genIpush"); + 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))) { + emitcode("", "; genIfx"); + genIfx (ic->next,ic); + } + else { + emitcode("", "; genIpop"); + genIpop (ic); + } + break; + + case CALL: + emitcode("", "; genCall"); + genCall (ic); + break; + + case PCALL: + emitcode("", "; genPcall"); + genPcall (ic); + break; + + case FUNCTION: + emitcode("", "; genFunction"); + genFunction (ic); + break; + + case ENDFUNCTION: + emitcode("", "; genEndFunction"); + genEndFunction (ic); + break; + + case RETURN: + emitcode("", "; genRet"); + genRet (ic); + break; + + case LABEL: + emitcode("", "; genLabel"); + genLabel (ic); + break; + + case GOTO: + emitcode("", "; genGoto"); + genGoto (ic); + break; + + case '+' : + emitcode("", "; genPlus"); + genPlus (ic) ; + break; + + case '-' : + emitcode("", "; genMinus"); + genMinus (ic); + break; + + case '*' : + emitcode("", "; genMult"); + genMult (ic); + break; + + case '/' : + emitcode("", "; genDiv"); + genDiv (ic) ; + break; + + case '%' : + emitcode("", "; genMod"); + genMod (ic); + break; + + case '>' : + emitcode("", "; genCmpGt"); + genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case '<' : + emitcode("", "; genCmpLt"); + 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: + emitcode("", "; genCmpEq"); + genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case AND_OP: + emitcode("", "; genAndOp"); + genAndOp (ic); + break; + + case OR_OP: + emitcode("", "; genOrOp"); + genOrOp (ic); + break; + + case '^' : + emitcode("", "; genXor"); + genXor (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case '|' : + emitcode("", "; genOr"); + genOr (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case BITWISEAND: + emitcode("", "; genAnd"); + genAnd (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case INLINEASM: + emitcode("", "; genInline"); + genInline (ic); + break; + + case RRC: + emitcode("", "; genRRC"); + genRRC (ic); + break; + + case RLC: + emitcode("", "; genRLC"); + genRLC (ic); + break; + + case GETHBIT: + emitcode("", "; genHBIT"); + assert(0); + + case LEFT_OP: + emitcode("", "; genLeftShift"); + genLeftShift (ic); + break; + + case RIGHT_OP: + emitcode("", "; genRightShift"); + genRightShift (ic); + break; + + case GET_VALUE_AT_ADDRESS: + emitcode("", "; genPointerGet"); + genPointerGet(ic); + break; + + case '=' : + + if (POINTER_SET(ic)) { + emitcode("", "; genAssign (pointer)"); + genPointerSet(ic); + } + else { + emitcode("", "; genAssign"); + genAssign(ic); + } + break; + + case IFX: + emitcode("", "; genIfx"); + genIfx (ic,NULL); + break; + + case ADDRESS_OF: + emitcode("", "; genAddrOf"); + genAddrOf (ic); + break; + + case JUMPTABLE: + emitcode("", "; genJumpTab"); + genJumpTab (ic); + break; + + case CAST: + emitcode("", "; genCast"); + genCast (ic); + break; + + case RECEIVE: + emitcode("", "; genReceive"); + genReceive(ic); + break; + + case SEND: + emitcode("", "; addSet"); + addSet(&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; +} diff --git a/src/z80/gen.h b/src/z80/gen.h new file mode 100644 index 00000000..9af52073 --- /dev/null +++ b/src/z80/gen.h @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGEN51_H +#define SDCCGEN51_H + +enum { + /* Is a literal */ + AOP_LIT = 1, + /* Is in a register */ + AOP_REG, + /* Is in direct space */ + AOP_DIR, + /* Is on the stack */ + AOP_STK , + /* Is an immediate value */ + AOP_IMMD, + /* Is a string (?) */ + AOP_STR, + /* Is in the carry register */ + AOP_CRY, + /* Is pointed to by IY */ + AOP_IY, + /* Is in A */ + AOP_ACC }; + +/* type asmop : a homogenised type for + all the different spaces an operand can be + in */ +typedef struct asmop { + + short type ; /* can have values + AOP_LIT - operand is a literal value + AOP_REG - is in registers + AOP_DIR - direct just a name + AOP_DPTR - dptr contains address of operand + AOP_R0/R1 - r0/r1 contains address of operand + AOP_STK - should be pushed on stack this + can happen only for the result + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + AOP_STR - array of strings + AOP_ACC - result is in the acc:b pair + */ + short coff ; /* current offset */ + short size ; /* total size */ + unsigned code :1 ; /* is in Code space */ + unsigned paged:1 ; /* in paged memory */ + unsigned freed:1 ; /* already freed */ + union { + value *aop_lit ; /* if literal */ + regs *aop_reg[4]; /* array of registers */ + char *aop_dir ; /* if direct */ + char *aop_immd; /* if immediate others are implied */ + int aop_stk ; /* stack offset when AOP_STK */ + char *aop_str[4]; /* just a string array containing the location */ + } aopu; +} asmop; + +void genZ80Code (iCode *); + + +#endif diff --git a/src/z80/global.h b/src/z80/global.h new file mode 100644 index 00000000..f20caa2c --- /dev/null +++ b/src/z80/global.h @@ -0,0 +1,3 @@ +typedef struct { +} PROCESSOR_OPTIONS; + diff --git a/src/z80/glue.c b/src/z80/glue.c new file mode 100644 index 00000000..878e082b --- /dev/null +++ b/src/z80/glue.c @@ -0,0 +1,22 @@ +#include "SDCCglue.h" +#include "glue.h" + +extern int maxRegBank ; + +/* Not yet ported */ +#if 0 +void x_glue(FILE *asmFile) +{ + assert(asmFile); +} + +void x_insertMainHook(FILE *asmFile) +{ + assert(asmFile); + + if (mainf && mainf->fbody) { + fprintf (asmFile,"__sdcc_gsinit_startup:\n"); + } + +} +#endif diff --git a/src/z80/glue.h b/src/z80/glue.h new file mode 100644 index 00000000..03d38b91 --- /dev/null +++ b/src/z80/glue.h @@ -0,0 +1,9 @@ +#ifndef GLUE_INCLUDE +#define GLUE_INCLUDE + +#include + +void x_glue(FILE *asmFile); +void x_insertMainHook(FILE *asmFile); + +#endif diff --git a/src/z80/icode.c b/src/z80/icode.c new file mode 100644 index 00000000..e569685a --- /dev/null +++ b/src/z80/icode.c @@ -0,0 +1,153 @@ +#include "SDCCglobl.h" +#include "SDCCast.h" +#include "SDCCmem.h" +#include "SDCCy.h" +#include "SDCChasht.h" +#include "SDCCicode.h" +#include "SDCCerr.h" +#include "ralloc.h" + +/* Not ported yet */ +#if 0 +/*-----------------------------------------------------------------*/ +/* aggrToPtr - changes an aggregate to pointer to an aggregate */ +/*-----------------------------------------------------------------*/ +link *aggrToPtr ( link *type, bool force) +{ + link *etype ; + link *ptype ; + + + if (IS_PTR(type) && !force) + return type; + + etype = getSpec(type); + ptype = newLink(); + + ptype->next = type; + /* if the output class is generic */ + if (SPEC_OCLS(etype) == generic) + DCL_TYPE(ptype) = GPOINTER; + else + if (SPEC_OCLS(etype)->codesp ) { + DCL_TYPE(ptype) = POINTER ; + DCL_PTR_CONST(ptype) = 1; + } + else + DCL_TYPE(ptype) = POINTER ; + + /* if the variable was declared a constant */ + /* then the pointer points to a constant */ + if (IS_CONSTANT(etype) ) + DCL_PTR_CONST(ptype) = 1; + + /* the variable was volatile then pointer to volatile */ + if (IS_VOLATILE(etype)) + DCL_PTR_VOLATILE(ptype) = 1; + return ptype; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeArray2Ptr - array to pointer */ +/*-----------------------------------------------------------------*/ +operand *geniCodeArray2Ptr (operand *op) +{ + link *optype = operandType(op); + link *opetype = getSpec(optype); + + /* set the pointer depending on the storage class */ + if (SPEC_OCLS(opetype)->codesp ) { + DCL_TYPE(optype) = POINTER ; + DCL_PTR_CONST(optype) = 1; + } + else { + DCL_TYPE(optype) = POINTER; + } + + /* if the variable was declared a constant */ + /* then the pointer points to a constant */ + if (IS_CONSTANT(opetype) ) + DCL_PTR_CONST(optype) = 1; + + /* the variable was volatile then pointer to volatile */ + if (IS_VOLATILE(opetype)) + DCL_PTR_VOLATILE(optype) = 1; + op->isaddr = 0; + return op; +} + +/*-----------------------------------------------------------------*/ +/* geniCodeAddressOf - gens icode for '&' address of operator */ +/*-----------------------------------------------------------------*/ +operand *geniCodeAddressOf (operand *op) +{ + iCode *ic; + link *p ; + link *optype = operandType(op); + link *opetype= getSpec(optype); + + /* this must be a lvalue */ + if (!op->isaddr && !IS_AGGREGATE(optype)) { + werror (E_LVALUE_REQUIRED,"&"); + return op; + } + + p = newLink(); + p->class = DECLARATOR ; + /* set the pointer depending on the storage class */ + if (SPEC_OCLS(opetype)->codesp ) { + DCL_TYPE(p) = POINTER ; + DCL_PTR_CONST(p) = 1; + } + else { + DCL_TYPE(p) = POINTER ; + } + + /* make sure we preserve the const & volatile */ + if (IS_CONSTANT(opetype)) + DCL_PTR_CONST(p) = 1; + + if (IS_VOLATILE(opetype)) + DCL_PTR_VOLATILE(p) = 1; + + p->next = copyLinkChain(optype); + + /* if already a temp */ + if (IS_ITEMP(op)) { + setOperandType (op,p); + op->isaddr= 0; + return op; + } + + /* other wise make this of the type coming in */ + ic = newiCode(ADDRESS_OF,op,NULL); + IC_RESULT(ic) = newiTempOperand(p,1); + IC_RESULT(ic)->isaddr = 0; + ADDTOCHAIN(ic); + return IC_RESULT(ic); +} + +/*-----------------------------------------------------------------*/ +/* setOClass - sets the output class depending on the pointer type */ +/*-----------------------------------------------------------------*/ +void setOClass (link *ptr, link *spec) +{ + switch (DCL_TYPE(ptr)) { + case POINTER: + SPEC_OCLS(spec) = data ; + break ; + + case CPOINTER: + SPEC_OCLS(spec) = code ; + break ; + + case GPOINTER: + SPEC_OCLS(spec) = generic; + break; + + default: + assert(0); + } +} + +#endif diff --git a/src/z80/main.c b/src/z80/main.c new file mode 100644 index 00000000..c22fc0c9 --- /dev/null +++ b/src/z80/main.c @@ -0,0 +1,45 @@ +#include "SDCCglobl.h" +#include "main.h" + +/* Globals */ +PROCESSOR_CONSTANTS port = { + "Zilog Z80", /* Target name */ + { + "as-z80", /* Assembler executable name */ + "-plosgff", /* Options with debug */ + "-plosgff", /* Options without debug */ + TRUE /* TRUE if the assembler requires an output name */ + }, + { + "link-z80", /* Linker executable name */ + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 1, 2, 4, 2, 2, 2, 1, 4, 4 + }, + { + -1, 0, 0, 8, 0 + }, + /* Z80 has no native mul/div commands */ + { + 0 + } +}; + +bool x_parseOptions(char **argv, int *pargc) +{ + int i = *pargc; + bool fRecognised = FALSE; + + *pargc = i; + return fRecognised; +} + +void x_finaliseOptions(void) +{ +} + +void x_setDefaultOptions(void) +{ +} + diff --git a/src/z80/main.h b/src/z80/main.h new file mode 100644 index 00000000..c4d16020 --- /dev/null +++ b/src/z80/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions(char **argv, int *pargc); +void x_setDefaultOptions(void); +void x_finaliseOptions(void); + +#endif diff --git a/src/z80/mem.c b/src/z80/mem.c new file mode 100644 index 00000000..adc7e727 --- /dev/null +++ b/src/z80/mem.c @@ -0,0 +1,16 @@ +#include "SDCCglobl.h" +#include "SDCCmem.h" +#include "mem.h" + +memmap *xstack= NULL ; /* xternal stack data */ +memmap *xdata = NULL; /* external data */ +memmap *idata = NULL; /* internal data upto 256 */ +memmap *bit = NULL; /* bit addressable space */ +memmap *sfr = NULL; /* register space */ +memmap *sfrbit= NULL; /* sfr bit space */ +memmap *overlay=NULL; /* overlay segment */ + +void x_initMem(void) +{ +} + diff --git a/src/z80/mem.h b/src/z80/mem.h new file mode 100644 index 00000000..78b5f606 --- /dev/null +++ b/src/z80/mem.h @@ -0,0 +1,18 @@ +#ifndef MEM_INCLUDE +#define MEM_INCLUDE + +/* memory map prefixes MOF added the DATA,CODE,XDATA,BIT */ +#define OVERLAY_NAME "_OVERLAY" +#define CODE_NAME "_CODE" +#define DATA_NAME "_DATA" +#define STATIC_NAME "GSINIT" +#define GENERIC_NAME "GENERIC" +#define ISTACK_NAME "_STACK" + +#define IN_STACK(x) (IS_SPEC(x) && (SPEC_OCLS(x) == istack )) +#define IN_FARSPACE(x) FALSE + +typedef struct { +} X_MEMMAP; + +#endif diff --git a/src/z80/memmaps.h b/src/z80/memmaps.h new file mode 100644 index 00000000..e69de29b diff --git a/src/z80/port.h b/src/z80/port.h new file mode 100644 index 00000000..aa265dc4 --- /dev/null +++ b/src/z80/port.h @@ -0,0 +1,21 @@ +/** Set to target the 8051 */ +#define PROCESSOR_Z80 1 + +#define HAS_BITSPACE 0 +#define HAS_REGSPACE 0 +#define HAS_PAGEDSPACE 0 +#define HAS_DIRECTSPACE 0 +#define HAS_XDATA 0 +#define HAS_OVERLAY 0 +#define HAS_IDATA 0 +#define HAS_SFRSPACE 0 +#define HAS_SFRBITSPACE 0 +#define HAS_XSTACK 0 + +#define HAS_INTERRUPT_TABLE 0 + +/** Setting this is equivalent to --stack-auto --no-peep --main-return --callee-saves --noregparms --xstack */ +#define USE_CLEAN_OPTIONS 1 +/** Set if the callee should save _all_ registers */ +#define USE_CALLEE_SAVES_ALL 1 + diff --git a/src/z80/ralloc.c b/src/z80/ralloc.c new file mode 100644 index 00000000..17318289 --- /dev/null +++ b/src/z80/ralloc.c @@ -0,0 +1,1979 @@ +/** @name Z80 Register allocation functions. + @author Michael Hope + + Note: much of this is ripped straight from Sandeep's mcs51 code. + + This code maps the virtual symbols and code onto the real + hardware. It allocates based on usage and how long the varible + lives into registers or temporary memory on the stack. + + On the Z80 hl, ix, iy, and a are reserved for the code generator, + leaving bc and de for allocation. The extra register pressure + from reserving hl is made up for by how much easier the sub + operations become. You could swap hl for iy if the undocumented + iyl/iyh instructions are available. + + The stack frame is the common ix-bp style. Basically: + + ix+4+n: param 1 + ix+4: param 0 + ix+2: return address + ix+0: calling functions ix + ix-n: local varibles + ... + sp: end of local varibles + + There is currently no support for bit spaces or banked functions. + + 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 +#include +#include "SDCCglobl.h" +#include "SDCCast.h" +#include "SDCCmem.h" +#include "SDCCy.h" +#include "SDCChasht.h" +#include "SDCCbitv.h" +#include "SDCCset.h" +#include "SDCCicode.h" +#include "SDCClabel.h" +#include "SDCCBBlock.h" +#include "SDCCloop.h" +#include "SDCCcse.h" +#include "SDCCcflow.h" +#include "SDCCdflow.h" +#include "SDCClrange.h" +#include "ralloc.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 */ +/*-----------------------------------------------------------------*/ + +bitVect *spiltSet = NULL ; +set *stackSpil = NULL; +bitVect *regAssigned = NULL; +short blockSpil = 0; +int slocNum = 0 ; +extern void genZ80Code(iCode *); +int ptrRegReq = 0; /* one byte pointer register required */ +bitVect *funcrUsed = NULL; /* registers used in a function */ +int stackExtend = 0; +int dataExtend = 0; + +/** Set to help debug register pressure related problems */ +#define DEBUG_FAKE_EXTRA_REGS 0 + +regs regsZ80[] = +{ + { REG_GPR, C_IDX , "c", 1 }, + { REG_GPR, B_IDX , "b", 1 }, + { REG_GPR, E_IDX , "e", 1 }, + { REG_GPR, D_IDX , "d", 1 }, + /* { REG_GPR, L_IDX , "l", 1 }, + { REG_GPR, H_IDX , "h", 1 },*/ +#if DEBUG_FAKE_EXTRA_REGS + { REG_GPR, M_IDX , "m", 1 }, + { REG_GPR, N_IDX , "n", 1 }, + { REG_GPR, O_IDX , "o", 1 }, + { REG_GPR, P_IDX , "p", 1 }, + { REG_GPR, Q_IDX , "q", 1 }, + { REG_GPR, R_IDX , "r", 1 }, + { REG_GPR, S_IDX , "s", 1 }, + { REG_GPR, T_IDX , "t", 1 }, +#endif + { REG_CND, CND_IDX, "c", 1} +}; + +/** Number of usable registers (all but C) */ +#define MAX_REGS ((sizeof(regsZ80)/sizeof(regs))-1) + +int nRegs = MAX_REGS; + +void spillThis (symbol *); + +/** Allocates register of given type. + 'type' is not used on the z80 version. It was used to select + between pointer and general purpose registers on the mcs51 version. + + @return Pointer to the newly allocated register. + */ +regs *allocReg (short type) +{ + int i; + + for ( i = 0 ; i < nRegs ; i++ ) { + /* For now we allocate from any free */ + if (regsZ80[i].isFree ) { + regsZ80[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = + bitVectSetBit(currFunc->regsUsed,i); + return ®sZ80[i]; + } + } + return NULL; +} + +/** Returns pointer to register wit index number + */ +regs *regWithIdx (int idx) +{ + int i; + + for (i=0;i < nRegs;i++) + if (regsZ80[i].rIdx == idx) + return ®sZ80[i]; + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "regWithIdx not found"); + exit(1); +} + +/** Frees a register. + */ +void freeReg (regs *reg) +{ + assert(!reg->isFree); + reg->isFree = 1; +} + + +/** Returns number of free registers. + */ +int nFreeRegs (int type) +{ + int i; + int nfr=0; + + for (i = 0 ; i < nRegs; i++ ) { + /* For now only one reg type */ + if (regsZ80[i].isFree) + nfr++; + } + return nfr; +} + +/** Free registers with type. + */ +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 */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +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,spiltSet); /* those already spilt */ + spillable = + bitVectCplAnd(spillable,ic->uses); /* used in this one */ + bitVectUnSetBit(spillable,ic->defKey); + spillable = bitVectIntersect(spillable,regAssigned); + return spillable; + +} + +/*-----------------------------------------------------------------*/ +/* noSpilLoc - return true if a variable has no spil location */ +/*-----------------------------------------------------------------*/ +int noSpilLoc (symbol *sym, eBBlock *ebp,iCode *ic) +{ + return (sym->usl.spillLoc ? 0 : 1); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLoc - will return 1 if the symbol has spil location */ +/*-----------------------------------------------------------------*/ +int hasSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return (sym->usl.spillLoc ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* directSpilLoc - will return 1 if the splilocation is in direct */ +/*-----------------------------------------------------------------*/ +int directSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic) +{ + /* No such thing as direct space */ + return 0; +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLocnoUptr - will return 1 if the symbol has spil location*/ +/* but is not used as a pointer */ +/*-----------------------------------------------------------------*/ +int hasSpilLocnoUptr (symbol *sym, eBBlock *ebp, iCode *ic) +{ +#if 0 + return sym->usl.spillLoc ? 1:0; +#else + return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0); +#endif +} + +/** Will return 1 if the remat flag is set. + A symbol is rematerialisable if it doesnt need to be allocated + into registers at creation as it can be re-created at any time - + i.e. it's constant in some way. +*/ +int rematable (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return sym->remat; +} + +/*-----------------------------------------------------------------*/ +/* notUsedInBlock - not used in this block */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +int notUsedInRemaining (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return ((usedInRemaining (operandFromSymbol(sym),ic) ? 0 : 1) && + allDefsOutOfRange (sym->defs,ic->seq,ebp->lSeq)); +} + +/*-----------------------------------------------------------------*/ +/* allLRs - return true for all */ +/*-----------------------------------------------------------------*/ +int allLRs (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* liveRangesWith - applies function to a given set of live range */ +/*-----------------------------------------------------------------*/ +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(regAssigned,sym->key)) + addSetHead(&rset,sym); + } + + return rset; +} + + +/*-----------------------------------------------------------------*/ +/* leastUsedLR - given a set determines which is the least used */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +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 */ +/*-----------------------------------------------------------------*/ +void spillLRWithPtrReg (symbol *forSym) +{ + /* Always just return */ +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +symbol *createStackSpil (symbol *sym) +{ + symbol *sloc= NULL; + + /* first go try and find a free one that is already + existing on the stack */ + if (applyToSet(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 */ + + sprintf(buffer,"sloc%d",slocNum++); + sloc = newiTemp(buffer); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain(sym->type); + sloc->etype = getSpec(sloc->type); + SPEC_SCLS(sloc->etype) = S_AUTO ; + + /* 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 + */ + allocLocal(sloc); + + 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); + stackExtend += getSize(sloc->type); + } else + dataExtend += getSize(sloc->type); + + /* add it to the stackSpil set */ + addSetHead(&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 */ +/*-----------------------------------------------------------------*/ +bool isSpiltOnStack (symbol *sym) +{ + link *etype; + + if (!sym) + return FALSE ; + + if (!sym->isspilt) + return FALSE ; + +/* if (sym->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 */ +/*-----------------------------------------------------------------*/ +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; + spiltSet = bitVectSetBit(spiltSet,sym->key); + + bitVectUnSetBit(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 (!ptrRegReq && isSpiltOnStack(sym)) { + ptrRegReq++ ; + spillLRWithPtrReg(sym); + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq = 1; + return; +} + +/** Select a iTemp to spil : rather a simple procedure. + */ +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); + } + +#if 0 + /* 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 (!blockSpil && (selectS = liveRangesWith(lrcs,notUsedInBlock,ebp,ic))) { + sym = leastUsedLR(selectS); + /* if this is not rematerializable */ + if (!sym->remat) { + blockSpil++; + sym->blockSpil = 1; + } + return sym; + } + + /* check if there are any live ranges that not + used in the remainder of the block */ + if (!blockSpil && (selectS = liveRangesWith(lrcs,notUsedInRemaining,ebp,ic))) { + sym = leastUsedLR (selectS); + if (!sym->remat) { + sym->remainSpil = 1; + 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; + } +#endif + + /* 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; + +} + +/** Spil some variable & mark registers as free. + A spill occurs when an iTemp wont fit into the available registers. + */ +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; + spiltSet = bitVectSetBit(spiltSet,ssym->key); + + /* mark it as not register assigned & + take it away from the set */ + bitVectUnSetBit(regAssigned,ssym->key); + + /* mark the registers as free */ + for (i = 0 ; i < ssym->nRegs ;i++ ) + if (ssym->regs[i]) + freeReg(ssym->regs[i]); + +#if 0 + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to as gprs */ + if (!ptrRegReq && isSpiltOnStack(ssym) ) { + 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); + } +#endif + + if (ssym == forSym ) + return FALSE ; + else + return TRUE ; +} + +/** Will try for GPR if not spil. + */ +regs *getRegGpr (iCode *ic, eBBlock *ebp,symbol *sym) +{ + regs *reg; + + tryAgain: + /* try for gpr type */ + if ((reg = allocReg(REG_GPR))) + return reg; + + if (!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 ; +} + +/** 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; +} + +/** Check the live to and if they have registers & are not spilt then + free up the registers +*/ +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(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(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) && + (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(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); + + regAssigned = bitVectSetBit(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]); + } + } + } +} + + +/** Reassign this to registers. + */ +void reassignLR (operand *op) +{ + symbol *sym = OP_SYMBOL(op); + int i; + + /* not spilt any more */ + sym->isspilt = sym->blockSpil = sym->remainSpil = 0; + bitVectUnSetBit(spiltSet,sym->key); + + regAssigned = bitVectSetBit(regAssigned,sym->key); + + blockSpil--; + + for (i=0;inRegs;i++) + sym->regs[i]->isFree = 0; +} + +/** Determines if allocating will cause a spill. + */ +int willCauseSpill ( int nr, int rt) +{ + /* first check if there are any avlb registers + of te type required */ + if (nFreeRegs(0) >= nr) + return 0; + + /* it will cause a spil */ + return 1; +} + +/** The allocator can allocate same registers to result and operand, + if this happens make sure they are in the same position as the operand + otherwise chaos results. +*/ +static 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; + } +} + +/** Try to allocate a pair of registers to the symbol. + */ +bool tryAllocatingRegPair(symbol *sym) +{ + int i; + assert(sym->nRegs == 2); + for ( i = 0 ; i < nRegs ; i+=2 ) { + if ((regsZ80[i].isFree)&&(regsZ80[i+1].isFree)) { + regsZ80[i].isFree = 0; + sym->regs[0] = ®sZ80[i]; + regsZ80[i+1].isFree = 0; + sym->regs[1] = ®sZ80[i+1]; + if (currFunc) { + currFunc->regsUsed = + bitVectSetBit(currFunc->regsUsed,i); + currFunc->regsUsed = + bitVectSetBit(currFunc->regsUsed,i+1); + } + return TRUE; + } + } + return FALSE; +} + +/** Serially allocate registers to the variables. + This is the main register allocation function. It is called after + packing. + */ +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 */ + /* MLH: removed RESULT and POINTER_SET condition */ + if (SKIP_IC2(ic) || + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP) + 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; + + /* 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(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 (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; + } + } + + /* else we assign registers to it */ + regAssigned = bitVectSetBit(regAssigned,sym->key); + + /* Special case: Try to fit into a reg pair if + available */ + if ((sym->nRegs == 2)&&tryAllocatingRegPair(sym)) { + } + else { + for (j = 0 ; j < sym->nRegs ;j++ ) { + 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 && ic->op != '=') + positionRegs(OP_SYMBOL(IC_RESULT(ic)), + OP_SYMBOL(IC_RIGHT(ic)),ic->lineno); + + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +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(nRegs); + + for (j = 0; j < sym->nRegs; j++) { + rumask = bitVectSetBit(rumask, + sym->regs[j]->rIdx); + } + + return rumask; +} + +/** Returns bit vector of registers used in iCode. + */ +bitVect *regsUsedIniCode (iCode *ic) +{ + bitVect *rmask = newBitVect(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; +} + +/** For each instruction will determine the regsUsed. + */ +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); + funcrUsed = bitVectUnion(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(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); + } + } + } +} + +/** Returns the rematerialized string for a remat var. + */ +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 */ +/*-----------------------------------------------------------------*/ +void regTypeNum () +{ + symbol *sym; + int k; + + /* 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 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 */ + /* Always general purpose */ + 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 ; + } + +} + +/** Mark all registers as free. + */ +void freeAllRegs() +{ + int i; + + for (i=0;i< nRegs;i++ ) + regsZ80[i].isFree = 1; +} + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +DEFSETFUNC(deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal(sym); + return 0; +} + +/** Register reduction for assignment. + */ +int packRegsForAssign (iCode *ic,eBBlock *ebp) +{ + iCode *dic, *sic; + + if ( + !IS_TRUE_SYMOP(IC_RESULT(ic)) || + !IS_ITEMP(IC_RIGHT(ic)) || + OP_LIVETO(IC_RIGHT(ic)) > ic->seq || + OP_SYMBOL(IC_RIGHT(ic))->isind) + return 0; + +#if 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; + } +#endif + + /* find the definition of iTempNN scanning backwards if we find a + a use of the true symbol in before we find the definition then + we cannot */ + for ( dic = ic->prev ; dic ; dic = dic->prev) { + + /* if 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 0 + 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; + } +#endif + } + + 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); + return 1; + +} + +/** Scanning backwards looks for first assig found. + */ +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 */ +/*-----------------------------------------------------------------*/ +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); + 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 ; + + /* 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); + change ++; + } + + return change ; +} + +#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly) + +/** 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)) > 2 && + ic->op != RETURN && + ic->op != SEND) + 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)) + return NULL; + + if (POINTER_GET(dic)) + 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)) + return NULL ; + + if (POINTER_GET(dic)) + return NULL ; + + /* if address of & the result is remat the okay */ + if (dic->op == ADDRESS_OF && + OP_SYMBOL(IC_RESULT(dic))->remat) + continue ; + + /* 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 *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)) + return TRUE; + return FALSE; +} + +/** Pack registers for acc use. + When the result of this operation is small and short lived it may + be able to be stored in the accumelator. + */ +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 ; + + /* has only one definition */ + if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1) + return ; + + /* has only one use */ + if (bitVectnBitsOn(OP_USES(IC_RESULT(ic))) > 1) + return ; + + /* and the usage immediately follows this iCode */ + if (!(uic = hTabItemWithKey(iCodehTab, + bitVectFirstBit(OP_USES(IC_RESULT(ic)))))) + return ; + + if (ic->next != uic) + return ; + + /* if it is a conditional branch then we definitely can */ + if (uic->op == IFX ) + goto accuse; + + if ( uic->op == JUMPTABLE ) + return ; + +#if 0 + /* if 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; +#endif + + 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 ; + +#if 0 + /* 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 ; +#endif + +#if 0 + /* 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 ; +#endif + + /* 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 ; + } + + /** This is confusing :) Guess for now */ + if (IC_LEFT(uic)->key == IC_RESULT(ic)->key && + (IS_ITEMP(IC_RIGHT(uic)) || + (IS_TRUE_SYMOP(IC_RIGHT(uic))))) + goto accuse; + + if (IC_RIGHT(uic)->key == IC_RESULT(ic)->key && + (IS_ITEMP(IC_LEFT(uic)) || + (IS_TRUE_SYMOP(IC_LEFT(uic))))) + goto accuse ; + return ; + accuse: + OP_SYMBOL(IC_RESULT(ic))->accuse = 1; +} + +/** Does some transformations to reduce register pressure. + */ +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 ) { + /* Safe: address of a true sym is always constant. */ + /* 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; + } + + /* Safe: just propagates the remat flag */ + /* 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 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 ; + } + +#if 0 + /* reduce for support function calls */ + if (ic->supportRtn || ic->op == '+' || ic->op == '-' ) + packRegsForSupport(ic,ebp); +#endif + +#if 0 + /* 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); +#endif + +#if 0 + /* 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); +#endif + +#if 0 + /* 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); +#endif + + /* 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 assignRegisters (eBBlock **ebbs, int count) +{ + iCode *ic; + int i ; + + setToNull((void *)&funcrUsed); + ptrRegReq = stackExtend = dataExtend = 0; + /* if not register extentions then reduce number + of registers */ + nRegs = MAX_REGS; + + /* 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 (stackExtend) { +/* werror(W_TOOMANY_SPILS,"stack", */ +/* stackExtend,currFunc->name,""); */ + stackExtend = 0 ; + } + + if (dataExtend) { +/* werror(W_TOOMANY_SPILS,"data space", */ +/* dataExtend,currFunc->name,""); */ + dataExtend = 0 ; + } + + if (options.dump_rassgn) + dumpEbbsToFileExt(".dumprassgn",ebbs,count); + + /* after that create the register mask + for each of the instruction */ + createRegMask (ebbs,count); + + /* now get back the chain */ + ic = iCodeLabelOptimize(iCodeFromeBBlock (ebbs,count)); + + /* redo that offsets for stacked automatic variables */ + redoStackOffsets (); + + genZ80Code(ic); + + /* free up any stackSpil locations allocated */ + applyToSet(stackSpil,deallocStackSpil); + slocNum = 0; + setToNull((void **)&stackSpil); + setToNull((void **)&spiltSet); + /* mark all registers as free */ + freeAllRegs(); + + return ; +} diff --git a/src/z80/ralloc.h b/src/z80/ralloc.h new file mode 100644 index 00000000..d3af0525 --- /dev/null +++ b/src/z80/ralloc.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +#define DEBUG_FAKE_EXTRA_REGS 0 + +enum { C_IDX = 0, + B_IDX, + E_IDX, + D_IDX, + L_IDX, + H_IDX, +#if DEBUG_FAKE_EXTRA_REGS + M_IDX, + N_IDX, + O_IDX, + P_IDX, + Q_IDX, + R_IDX, + S_IDX, + T_IDX, +#endif + CND_IDX }; + +#define REG_PTR 0x01 +#define REG_GPR 0x02 +#define REG_CND 0x04 +/* definition for the registers */ +typedef struct regs +{ + short type; /* can have value + REG_GPR, REG_PTR or REG_CND */ + short rIdx ; /* index into register table */ + char *name ; /* name */ + unsigned isFree :1; /* is currently unassigned */ +} regs; + +extern regs regsZ80[]; + +void assignRegisters (eBBlock **, int ); +regs *regWithIdx (int); + +#endif