From: johanknol Date: Thu, 17 Jan 2002 14:23:49 +0000 (+0000) Subject: Just to make sure I don't loose them again when syncing with cvs. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=c446f6b6ad7298f2f8249f2874cd25e9d64bbf21;p=fw%2Fsdcc Just to make sure I don't loose them again when syncing with cvs. It is useless for now. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1809 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/configure b/configure index 39e206cb..8939cada 100755 --- a/configure +++ b/configure @@ -2801,9 +2801,9 @@ if test "$enable_xa51_port" = "no"; then EOF else - #echo xa51 >>ports.build // not yet + echo xa51 >>ports.build cat >> confdefs.h < peeph.rul + +# include clean.mk diff --git a/src/xa51/Makefile.dep b/src/xa51/Makefile.dep new file mode 100644 index 00000000..4635445b --- /dev/null +++ b/src/xa51/Makefile.dep @@ -0,0 +1,23 @@ +gen.o: gen.c ../SDCCglobl.h ../../sdccconf.h \ + ../../support/Util/SDCCerr.h ../../support/Util/newalloc.h \ + ../common.h ../SDCCmem.h ../SDCCast.h ../SDCCsymt.h ../SDCChasht.h \ + ../SDCCval.h ../SDCCset.h ../SDCCy.h ../SDCCbitv.h ../SDCCicode.h \ + ../SDCClabel.h ../SDCCBBlock.h ../SDCCloop.h ../SDCCcse.h \ + ../SDCCcflow.h ../SDCCdflow.h ../SDCClrange.h ../SDCCptropt.h \ + ../SDCCopt.h ../SDCCglue.h ../SDCCpeeph.h ../asm.h ../port.h ralloc.h \ + gen.h +main.o: main.c ../common.h ../SDCCglobl.h ../../sdccconf.h \ + ../../support/Util/SDCCerr.h ../SDCCmem.h ../SDCCast.h ../SDCCsymt.h \ + ../SDCChasht.h ../SDCCval.h ../SDCCset.h ../SDCCy.h ../SDCCbitv.h \ + ../SDCCicode.h ../SDCClabel.h ../SDCCBBlock.h ../SDCCloop.h \ + ../SDCCcse.h ../SDCCcflow.h ../SDCCdflow.h ../SDCClrange.h \ + ../SDCCptropt.h ../SDCCopt.h ../SDCCglue.h ../SDCCpeeph.h ../asm.h \ + ../port.h ../../support/Util/newalloc.h main.h ralloc.h gen.h \ + peeph.rul +ralloc.o: ralloc.c ../common.h ../SDCCglobl.h ../../sdccconf.h \ + ../../support/Util/SDCCerr.h ../SDCCmem.h ../SDCCast.h ../SDCCsymt.h \ + ../SDCChasht.h ../SDCCval.h ../SDCCset.h ../SDCCy.h ../SDCCbitv.h \ + ../SDCCicode.h ../SDCClabel.h ../SDCCBBlock.h ../SDCCloop.h \ + ../SDCCcse.h ../SDCCcflow.h ../SDCCdflow.h ../SDCClrange.h \ + ../SDCCptropt.h ../SDCCopt.h ../SDCCglue.h ../SDCCpeeph.h ../asm.h \ + ../port.h ../../support/Util/newalloc.h ralloc.h gen.h diff --git a/src/xa51/gen.c b/src/xa51/gen.c new file mode 100755 index 00000000..40427b9c --- /dev/null +++ b/src/xa51/gen.c @@ -0,0 +1,1213 @@ +/*------------------------------------------------------------------------- + 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) + Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + + Notes: + 000123 mlh Moved aopLiteral to SDCCglue.c to help the split + Made everything static +-------------------------------------------------------------------------*/ + +//#define D(x) +#define D(x) x + +#include +#include +#include +#include +#include "SDCCglobl.h" +#include "newalloc.h" + +#ifdef HAVE_SYS_ISA_DEFS_H +#include +#else +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#else +#ifdef HAVE_ENDIAN_H +#include +#else +#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__CYGWIN__) +#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN" +#warning "If you running sdcc on an INTEL 80x86 Platform you are okay" +#endif +#endif +#endif +#endif + +#include "common.h" +#include "SDCCpeeph.h" +#include "ralloc.h" +#include "gen.h" + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +extern int allocInfo; + +/* this is the down and dirty file with all kinds of + kludgy & hacky stuff. This is what it is all about + CODE GENERATION for a specific MCU . some of the + routines may be reusable, will have to see */ + +static struct + { + short inLine; + short debugLine; + short nRegsSaved; + set *sendSet; + } +_G; + +extern int xa51_ptrRegReq; +extern int xa51_nRegs; +extern FILE *codeOutFile; + +static lineNode *lineHead = NULL; +static lineNode *lineCurr = NULL; + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 + +/*-----------------------------------------------------------------*/ +/* emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +static void emitcode (char *inst, char *fmt,...) { + va_list ap; + char lb[INITIAL_INLINEASM]; + char *lbp = lb; + + va_start (ap, fmt); + + if (inst && *inst) + { + if (fmt && *fmt) + sprintf (lb, "%s\t", inst); + else + sprintf (lb, "%s", inst); + vsprintf (lb + (strlen (lb)), fmt, ap); + } + else + vsprintf (lb, fmt, ap); + + while (isspace ((int)*lbp)) + lbp++; + + if (lbp && *lbp) + lineCurr = (lineCurr ? + connectLine (lineCurr, newLineNode (lb)) : + (lineHead = newLineNode (lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + va_end (ap); +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop * +newAsmop (short type) +{ + asmop *aop; + + aop = Safe_calloc (1, sizeof (asmop)); + aop->type = type; + return aop; +} + +char *aopTypeName(asmop *aop) { + switch (aop->type) + { + case AOP_LIT: return "lit"; + case AOP_REG: return "reg"; + case AOP_DIR: return "dir"; + case AOP_FAR: return "far"; + case AOP_CODE: return "code"; + case AOP_STK: return "stack"; + case AOP_IMMD: return "imm"; + case AOP_CRY: return "bit"; + } + return "unknown"; +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop *aopForSym(symbol *sym, bool result) { + asmop *aop; + + sym->aop = aop = newAsmop(0); + aop->size=getSize(sym->type); + + // if it is in registers + if (sym->nRegs && sym->regs[0]) { + aop->type=AOP_REG; + if (sym->regs[1]) { + sprintf (aop->name[1], sym->regs[1]->name); + } + sprintf (aop->name[0], sym->regs[0]->name); + return aop; + } + + // if it is on stack + if (sym->onStack) { + aop->type=AOP_STK; + sprintf (aop->name[0], "[r7+%d+0+%d+%d]", sym->stack, + FUNC_ISISR(currFunc->type) ? 6 : 4, _G.nRegsSaved); + sprintf (aop->name[1], "[r7+%d+2+%d+%d]", sym->stack, + FUNC_ISISR(currFunc->type) ? 6 : 4, _G.nRegsSaved); + return aop; + } + + // if it has a spillLoc + if (sym->usl.spillLoc) { + return aopForSym (sym->usl.spillLoc, result); + } + + // if in bit space + if (IN_BITSPACE(SPEC_OCLS(sym->etype))) { + aop->type=AOP_CRY; + sprintf (aop->name[0], sym->rname); + return aop; + } + + // if in direct space + if (IN_DIRSPACE(SPEC_OCLS(sym->etype))) { + aop->type=AOP_DIR; + sprintf (aop->name[0], sym->rname); + sprintf (aop->name[1], "#0x%02x", POINTER); + return aop; + } + + // if in code space + if (IN_CODESPACE(SPEC_OCLS(sym->etype))) { + if (result) { + fprintf (stderr, "aopForSym: result can not be in code space\n"); + exit (1); + } + aop->type=AOP_CODE; + emitcode ("mov", "r0,#%s", sym->rname); + sprintf (aop->name[0], "r0"); + sprintf (aop->name[1], "#0x%02x", CPOINTER); + return aop; + } + + // if in far space + if (IN_FARSPACE(SPEC_OCLS(sym->etype))) { + aop->type=AOP_FAR; + emitcode ("mov", "r0,#%s", sym->rname); + sprintf (aop->name[0], "[r0]"); + if (result) { + sprintf (aop->name[1], "[r0+2]"); + } else { + sprintf (aop->name[1], "#0x%02x", FPOINTER); + } + return aop; + } + + // special case for a function + if (IS_FUNC (sym->type)) { + aop->type=AOP_IMMD; + sprintf (aop->name[0], sym->rname); + return aop; + } + + fprintf (stderr, "aopForSym (%s): What's up?\n", sym->name); + exit (1); +} + +/*-----------------------------------------------------------------*/ +/* aopForVal - for a value */ +/*-----------------------------------------------------------------*/ +static asmop *aopForVal(operand *op) { + asmop *aop; + long v=floatFromVal(OP_VALUE(op)); + + if (IS_OP_LITERAL(op)) { + op->aop = aop = newAsmop (AOP_LIT); + switch ((aop->size=getSize(operandType(op)))) + { + case 1: + sprintf (aop->name[0], "#0x%02lx", v); + break; + case 2: + sprintf (aop->name[0], "#0x%04lx", v); + break; + case 4: + sprintf (aop->name[0], "#(0x%08lx >> 16)", v); + sprintf (aop->name[1], "#(0x%08lx & 0xffff)", v); + break; + default: + fprintf (stderr, "aopForVal (lit): unknown size\n"); + exit (1); + } + return aop; + } + + // must be immediate + if (IS_SYMOP(op)) { + op->aop = aop = newAsmop (AOP_IMMD); + switch ((aop->size=getSize(OP_SYMBOL(op)->type))) + { + case 1: + case 2: + sprintf (aop->name[0], "#%s", OP_SYMBOL(op)->rname); + return aop; + case 3: // generic pointer + sprintf (aop->name[0], "#0x%02x", DCL_TYPE(operandType(op))); + sprintf (aop->name[1], "#%s", OP_SYMBOL(op)->rname); + return aop; + } + } + fprintf (stderr, "aopForVal: unknown type\n"); + exit (1); + return NULL; +} + +static void aopOp(operand *op, bool result) { + + if (IS_SYMOP(op)) { + op->aop=aopForSym (OP_SYMBOL(op), result); + return; + } + if (IS_VALOP(op)) { + if (result) { + fprintf (stderr, "aopOp: result can not be a value\n"); + exit (1); + } + aopForVal (op); + return; + } + + fprintf (stderr, "aopOp: unexpected operand\n"); + exit (1); +} + +char *opRegName(operand *op, int offset, char *opName) { + + if (IS_SYMOP(op)) { + if (OP_SYMBOL(op)->onStack) { + sprintf (aop->name[0], "[r7+%d+0+%d+%d]", sym->stack, + FUNC_ISISR(currFunc->type) ? 6 : 4, _G.nRegsSaved); + return opName; + } + if (IS_TRUE_SYMOP(op)) + return OP_SYMBOL(op)->rname; + else if (OP_SYMBOL(op)->regs[offset]) + return OP_SYMBOL(op)->regs[offset]->name; + else + return "NULL"; + } + + if (IS_VALOP(op)) { + switch (SPEC_NOUN(OP_VALUE(op)->type)) { + case V_BIT: + if (SPEC_CVAL(OP_VALUE(op)->type).v_int && + SPEC_CVAL(OP_VALUE(op)->type).v_int != 1) { + fprintf (stderr, "opRegName: invalid bit value (%d)\n", + SPEC_CVAL(OP_VALUE(op)->type).v_int); + exit (1); + } + // fall through + case V_CHAR: + sprintf (opName, "#0x%02x", SPEC_CVAL(OP_VALUE(op)->type).v_int); + break; + case V_INT: + if (SPEC_LONG(OP_VALUE(op)->type)) { + sprintf (opName, "#0x%02lx", SPEC_CVAL(OP_VALUE(op)->type).v_long); + } else { + sprintf (opName, "#0x%02x", SPEC_CVAL(OP_VALUE(op)->type).v_int); + } + break; + case V_FLOAT: + sprintf (opName, "#0x%02lx", SPEC_CVAL(OP_VALUE(op)->type).v_long); + break; + default: + fprintf (stderr, "opRegName: unexpected noun\n"); + exit (1); + } + return opName; + } + fprintf (stderr, "opRegName: unexpected operand type\n"); + exit (1); + return NULL; // to keep the compiler happy +} + +char * printOp (operand *op) { + static char line[132]; + bool isPtr = op->isPtr | op->isGptr; + + if (IS_SYMOP(op)) { + symbol *sym=OP_SYMBOL(op); + if (!sym->regs[0] && SYM_SPIL_LOC(sym)) { + sym=SYM_SPIL_LOC(sym); + } + if (isPtr) { + sprintf (line, "[%s]:", sym->name); + } else { + sprintf (line, "%s:", sym->name); + } + if (sym->regs[0]) { + strcat (line, sym->regs[0]->name); + if (sym->regs[1]) { + strcat (line, ","); + strcat (line, sym->regs[1]->name); + } + return line; + } + if (sym->onStack) { + sprintf (line+strlen(line), "stack+%d", sym->stack); + return line; + } + if (IN_FARSPACE(SPEC_OCLS(sym->etype))) { + strcat (line, "far"); + return line; + } + if (IN_BITSPACE(SPEC_OCLS(sym->etype))) { + strcat (line, "bit"); + return line; + } + if (IN_DIRSPACE(SPEC_OCLS(sym->etype))) { + strcat (line, "dir"); + return line; + } + strcat (line, "unknown"); + return line; + } else if (IS_VALOP(op)) { + opRegName(op, 0, line); + } else if (IS_TYPOP(op)) { + sprintf (line, "("); + // forget about static, volatile, ... for now + if (SPEC_USIGN(operandType(op))) strcat (line, "unsigned "); + if (SPEC_LONG(operandType(op))) strcat (line, "long "); + strcat (line, nounName(operandType(op))); + strcat (line, ")"); + } else { + fprintf (stderr, "printOp: unexpected operand type\n"); + exit (1); + } + return line; +} + +void printIc (char *op, iCode * ic, bool result, bool left, bool right) { + char line[132]; + + sprintf (line, "%s", op); + if (result) { + strcat (line, " result="); + strcat (line, printOp (IC_RESULT(ic))); + } + if (left) { + strcat (line, " left="); + strcat (line, printOp (IC_LEFT(ic))); + } + if (right) { + strcat (line, " right="); + strcat (line, printOp (IC_RIGHT(ic))); + } + emitcode (";", line); +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - return bit for operand!=0 */ +/*-----------------------------------------------------------------*/ +static char *toBoolean (operand * op) { + switch (AOP_SIZE(op)) + { + case 1: + case 2: + emitcode ("cmp", "%s,#0", AOP_NAME(op)); + return "z"; + } + + fprintf (stderr, "toBoolean: unknown size %d\n", AOP_SIZE(op)); + exit (1); + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* regsInCommon - two operands have some registers in common */ +/*-----------------------------------------------------------------*/ +static bool regsInCommon (operand * op1, operand * op2) { + symbol *sym1, *sym2; + int i; + + /* if they have registers in common */ + if (!IS_SYMOP (op1) || !IS_SYMOP (op2)) + return FALSE; + + sym1 = OP_SYMBOL (op1); + sym2 = OP_SYMBOL (op2); + + if (sym1->nRegs == 0 || sym2->nRegs == 0) + return FALSE; + + for (i = 0; i < sym1->nRegs; i++) + { + int j; + if (!sym1->regs[i]) + continue; + + for (j = 0; j < sym2->nRegs; j++) + { + if (!sym2->regs[j]) + continue; + + if (sym2->regs[j] == sym1->regs[i]) + return TRUE; + } + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void genNot (iCode * ic) { + printIc("genNot:", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void genCpl (iCode * ic) { + printIc("genCpl", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void genUminus (iCode * ic) { + printIc("genUminus", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void genIpush (iCode * ic) { + printIc ("genIpush", ic, 0,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void genIpop (iCode * ic) { + printIc ("genIpop", ic, 0,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void genCall (iCode * ic) { + emitcode (";", "genCall %s", OP_SYMBOL(IC_LEFT(ic))->name); +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void +genPcall (iCode * ic) +{ + emitcode (";", "genPcall %s\n", OP_SYMBOL(IC_LEFT(ic))->name); +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void genFunction (iCode * ic) { + symbol *sym=OP_SYMBOL(IC_LEFT(ic)); + sym_link *type=sym->type; + + emitcode (";", "-----------------------------------------"); + emitcode (";", " function %s", sym->name); + emitcode (";", "-----------------------------------------"); + + emitcode ("", "%s:", sym->rname); + + if (IFFUNC_ISNAKED(type)) + { + emitcode(";", "naked function: no prologue."); + return; + } + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (type)) + emitcode ("clr", "ea"); + +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void +genEndFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + + if (IFFUNC_ISNAKED(sym->type)) + { + emitcode(";", "naked function: no epilogue."); + return; + } + + printIc ("genEndFunction", ic, 0,0,0); +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void genRet (iCode * ic) { + emitcode (";", "genRet"); +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void genLabel (iCode * ic) { + /* special case never generate */ + if (IC_LABEL (ic) == entryLabel) + return; + + emitcode (";", "genLabel %s", IC_LABEL(ic)->name); + emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a ljmp */ +/*-----------------------------------------------------------------*/ +static void genGoto (iCode * ic) { + emitcode (";", "genGoto %s", IC_LABEL(ic)->name); + emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100)); +} + +/*-----------------------------------------------------------------*/ +/* genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void genPlus (iCode * ic) { + printIc ("genPlus", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static void genMinus (iCode * ic) { + printIc ("genMinus", ic, 1,1,1); +} + + +/*-----------------------------------------------------------------*/ +/* genMult - generates code for multiplication */ +/*-----------------------------------------------------------------*/ +static void genMult (iCode * ic) { + printIc ("genMult", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genDiv - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genDiv (iCode * ic) { + printIc ("genDiv", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genMod (iCode * ic) { + printIc ("genMod", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void genCmpGt (iCode * ic, iCode * ifx) { + printIc ("genCmpGt", ic, 1,1,1); +} +/*-----------------------------------------------------------------*/ +/* genCmpLt - less than comparisons */ +/*-----------------------------------------------------------------*/ +static void genCmpLt (iCode * ic, iCode * ifx) { + printIc ("genCmpLt", ic, 1,1,1); +} +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void genCmpEq (iCode * ic, iCode * ifx) { + printIc ("genCmpEq", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* hasInc - operand is incremented before any other use */ +/*-----------------------------------------------------------------*/ +static iCode *hasInc (operand *op, iCode *ic, int osize) { + sym_link *type = operandType(op); + sym_link *retype = getSpec (type); + iCode *lic = ic->next; + int isize ; + + /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */ + if (!IS_SYMOP(op)) return NULL; + + if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL; + if (IS_AGGREGATE(type->next)) return NULL; + if (osize != (isize = getSize(type->next))) return NULL; + + while (lic) { + /* if operand of the form op = op + */ + if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) && + isOperandEqual(IC_RESULT(lic),op) && + isOperandLiteral(IC_RIGHT(lic)) && + operandLitValue(IC_RIGHT(lic)) == isize) { + return lic; + } + /* if the operand used or deffed */ + if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) { + return NULL; + } + /* if GOTO or IFX */ + if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break; + lic = lic->next; + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void genAndOp (iCode * ic) { + printIc ("genAndOp(&&)", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genOrOp - for || operation */ +/*-----------------------------------------------------------------*/ +static void genOrOp (iCode * ic) { + printIc ("genOrOp(||)", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void genAnd (iCode * ic, iCode * ifx) { + printIc ("genAnd", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genOr - code for or */ +/*-----------------------------------------------------------------*/ +static void genOr (iCode * ic, iCode * ifx) { + printIc ("genOr", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void genXor (iCode * ic, iCode * ifx) { + printIc ("genXor", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genInline - write the inline code out */ +/*-----------------------------------------------------------------*/ +static void genInline (iCode * ic) { + printIc ("genInline", ic, 0,0,0); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void genRRC (iCode * ic) { + printIc ("genRRC", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genRLC - generate code for rotate left with carry */ +/*-----------------------------------------------------------------*/ +static void genRLC (iCode * ic) { + printIc ("genRLC", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void genGetHbit (iCode * ic) { + printIc ("genGetHbit", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void genLeftShift (iCode * ic) { + printIc ("genLeftShift", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void genRightShift (iCode * ic) { + printIc ("genRightShift", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genPointerGet - generate code for pointer get */ +/*-----------------------------------------------------------------*/ +static void genPointerGet (iCode * ic, iCode *pi) { + printIc ("genPointerGet", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void genPointerSet (iCode * ic, iCode *pi) { + printIc ("genPointerSet", ic, 1,0,1); +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void genIfx (iCode * ic, iCode * popIc) { + bool trueOrFalse; + symbol *jlbl, *tlbl; + operand *cond=IC_COND(ic); + + emitcode (";", "genIfx cond=%s trueLabel:%s falseLabel:%s", + printOp(cond), + IC_TRUE(ic) ? IC_TRUE(ic)->name : "NULL", + IC_FALSE(ic) ? IC_FALSE(ic)->name : "NULL"); + + aopOp(cond,FALSE); + + if (IC_TRUE(ic)) { + trueOrFalse=TRUE; + jlbl=IC_TRUE(ic); + } else { + trueOrFalse=FALSE; + jlbl=IC_FALSE(ic); + } + + switch (AOP_TYPE(cond) ) + { + case AOP_CRY: + emitcode (trueOrFalse ? "jb" : "jbc", "%s,%05d$", + AOP_NAME(cond)[0], jlbl->key+100); + return; + case AOP_REG: + case AOP_DIR: + case AOP_FAR: + tlbl=newiTempLabel(NULL); + emitcode ("cmp", "%s,#0", AOP_NAME(cond)[0]); + emitcode (trueOrFalse ? "bne" : "beq", "%05d$", tlbl->key+100); + if (*AOP_NAME(cond)[1]) { + emitcode ("cmp", "%s,#0", AOP_NAME(cond)[1]); + emitcode (trueOrFalse ? "bne" : "beq", "%05d$", tlbl->key+100); + } + emitcode ("jmp", "%05d$", jlbl->key+100); + emitcode ("", "%05d$:", tlbl->key+100); + return; + } +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void genAddrOf (iCode * ic) { + printIc ("genAddrOf", ic, 1,1,0); +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void genAssign (iCode * ic) { + operand *result=IC_RESULT(ic), *right=IC_RIGHT(ic); + + printIc ("genAssign", ic, 1,0,1); + + if (!IS_SYMOP(result)) { + fprintf (stderr, "genAssign: result is not a symbol\n"); + exit (1); + } + + aopOp(right, FALSE); + aopOp(result, TRUE); + + if (result->aop->type==AOP_REG || + right->aop->type==AOP_REG || + right->aop->type==AOP_LIT || + right->aop->type==AOP_IMMD) { + // everything will do + } else { + // they have to match + if (result->aop->type != right->aop->type) { + fprintf (stderr, "genAssign: types don't match (%s!=%s)\n", + aopTypeName(result->aop), aopTypeName(right->aop)); + exit (1); + } + } + + /* if result is a bit */ + if (AOP_TYPE(result) == AOP_CRY) { + /* if right is literal, we know what the value is */ + if (AOP_TYPE(right) == AOP_LIT) { + if (operandLitValue(right)) { + emitcode ("setb", AOP_NAME(result)[0]); + } else { + emitcode ("clr", AOP_NAME(result)[0]); + } + return; + } + /* if right is also a bit */ + if (AOP_TYPE(right) == AOP_CRY) { + emitcode ("mov", "c,%s", AOP_NAME(right)); + emitcode ("mov", "%s,c", AOP_NAME(result)); + return; + } + /* we need to or */ + emitcode ("mov", "%s,%s", AOP_NAME(result), toBoolean(right)); + return; + } + + /* general case */ + emitcode ("mov", "%s,%s", + result->aop->name[0], right->aop->name[0]); + if (IS_GENPTR(operandType(result))) { + emitcode ("mov", "%s,%s", + result->aop->name[1], right->aop->name[1]); + } + +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - genrates code for jump table */ +/*-----------------------------------------------------------------*/ +static void genJumpTab (iCode * ic) { + printIc ("genJumpTab", ic, 0,0,0); +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void genCast (iCode * ic) { + printIc ("genCast", ic, 1,1,1); +} + +/*-----------------------------------------------------------------*/ +/* genDjnz - generate decrement & jump if not zero instrucion */ +/*-----------------------------------------------------------------*/ +static bool genDjnz (iCode * ic, iCode * ifx) { + printIc ("genDjnz", ic, 0,0,0); + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void genReceive (iCode * ic) { + printIc ("genReceive", ic, 1,0,0); +} + +/*-----------------------------------------------------------------*/ +/* gen51Code - generate code for 8051 based controllers */ +/*-----------------------------------------------------------------*/ +void genXA51Code (iCode * lic) { + iCode *ic; + int cln = 0; + + fprintf (stderr, "genXA51Code\n"); + lineHead = lineCurr = NULL; + + /* print the allocation information */ + if (allocInfo) + printAllocInfo (currFunc, codeOutFile); + + /* if debug information required */ + if (options.debug && currFunc) + { + cdbSymbol (currFunc, cdbFile, FALSE, TRUE); + _G.debugLine = 1; + if (IS_STATIC (currFunc->etype)) + emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name); + else + emitcode ("", "G$%s$0$0 ==.", currFunc->name); + _G.debugLine = 0; + } + + for (ic = lic; ic; ic = ic->next) { + if (cln != ic->lineno) { + if (options.debug) { + _G.debugLine = 1; + emitcode ("", "C$%s$%d$%d$%d ==.", + FileBaseName (ic->filename), ic->lineno, + ic->level, ic->block); + _G.debugLine = 0; + } + emitcode (";", "%s %d", ic->filename, ic->lineno); + cln = ic->lineno; + } + /* if the result is marked as + spilt and rematerializable or code for + this has already been generated then + do nothing */ + if (resultRemat (ic) || ic->generated) + continue; + + /* depending on the operation */ + switch (ic->op) + { + case '!': + genNot (ic); + break; + + case '~': + genCpl (ic); + break; + + case UNARYMINUS: + genUminus (ic); + break; + + case IPUSH: + genIpush (ic); + break; + + case IPOP: + /* IPOP happens only when trying to restore a + spilt live range, if there is an ifx statement + following this pop then the if statement might + be using some of the registers being popped which + would destory the contents of the register so + we need to check for this condition and handle it */ + if (ic->next && + ic->next->op == IFX && + regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) + genIfx (ic->next, ic); + else + genIpop (ic); + break; + + case CALL: + genCall (ic); + break; + + case PCALL: + genPcall (ic); + break; + + case FUNCTION: + genFunction (ic); + break; + + case ENDFUNCTION: + genEndFunction (ic); + break; + + case RETURN: + genRet (ic); + break; + + case LABEL: + genLabel (ic); + break; + + case GOTO: + genGoto (ic); + break; + + case '+': + genPlus (ic); + break; + + case '-': + if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic))) + genMinus (ic); + break; + + case '*': + genMult (ic); + break; + + case '/': + genDiv (ic); + break; + + case '%': + genMod (ic); + break; + + case '>': + genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case '<': + genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case LE_OP: + case GE_OP: + case NE_OP: + + /* note these two are xlated by algebraic equivalence + during parsing SDCC.y */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "got '>=' or '<=' shouldn't have come here"); + break; + + case EQ_OP: + genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case AND_OP: + genAndOp (ic); + break; + + case OR_OP: + genOrOp (ic); + break; + + case '^': + genXor (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case '|': + genOr (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case BITWISEAND: + genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case INLINEASM: + genInline (ic); + break; + + case RRC: + genRRC (ic); + break; + + case RLC: + genRLC (ic); + break; + + case GETHBIT: + genGetHbit (ic); + break; + + case LEFT_OP: + genLeftShift (ic); + break; + + case RIGHT_OP: + genRightShift (ic); + break; + + case GET_VALUE_AT_ADDRESS: + genPointerGet (ic, hasInc(IC_LEFT(ic), ic, getSize(operandType(IC_LEFT(ic))))); + break; + + case '=': + if (POINTER_SET (ic)) + genPointerSet (ic, hasInc(IC_RESULT(ic), ic, getSize(operandType(IC_RIGHT(ic))))); + else + genAssign (ic); + break; + + case IFX: + genIfx (ic, NULL); + break; + + case ADDRESS_OF: + genAddrOf (ic); + break; + + case JUMPTABLE: + genJumpTab (ic); + break; + + case CAST: + genCast (ic); + break; + + case RECEIVE: + genReceive (ic); + break; + + case SEND: + addSet (&_G.sendSet, ic); + break; + + default: + ic = ic; + } + } + + + /* 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/xa51/gen.h b/src/xa51/gen.h new file mode 100755 index 00000000..bd451241 --- /dev/null +++ b/src/xa51/gen.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGEN51_H +#define SDCCGEN51_H + +enum + { + AOP_LIT = 1, + AOP_REG, + AOP_DIR, + AOP_FAR, + AOP_CODE, + AOP_STK, + AOP_IMMD, + AOP_CRY + }; + +/* 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_FAR - + AOP_CODE - + AOP_STK - on stack (with offset) + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + */ + short size; /* size of this aop */ + char name[2][64]; /* can be "r0" "r6h" [rxbw+y] "#..." */ +} asmop; + +#define AOP(x) x->aop +#define AOP_TYPE(x) x->aop->type +#define AOP_SIZE(x) x->aop->size +#define AOP_NAME(x) x->aop->name + +#endif diff --git a/src/xa51/gen.o b/src/xa51/gen.o new file mode 100644 index 00000000..2105af63 Binary files /dev/null and b/src/xa51/gen.o differ diff --git a/src/xa51/main.c b/src/xa51/main.c new file mode 100755 index 00000000..9021f599 --- /dev/null +++ b/src/xa51/main.c @@ -0,0 +1,285 @@ +/** @file main.c + xa51 specific general functions. + + Note that mlh prepended _xa51_ on the static functions. Makes + it easier to set a breakpoint using the debugger. +*/ +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "gen.h" + +static char _defaultRules[] = +{ +#include "peeph.rul" +}; + +/* list of key words used by xa51 */ +static char *_xa51_keywords[] = +{ + "at", + "bit", + "code", + "critical", + "data", + "far", + //"idata", + "interrupt", + "near", + //"pdata", + "reentrant", + "sfr", + "sbit", + "using", + //"xdata", + //"_data", + //"_code", + //"_generic", + //"_near", + //"_xdata", + //"_pdata", + //"_idata", + "_naked", + "_overlay", + NULL +}; + + +void xa51_assignRegisters (eBBlock ** ebbs, int count); + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void +_xa51_init (void) +{ + asm_addTree (&asm_asxxxx_mapping); +} + +static void +_xa51_reset_regparm () +{ + regParmFlg = 0; +} + +static int +_xa51_regparm (sym_link * l) +{ + return 0; // for now + /* for this processor it is simple + can pass only the first parameter in a register */ + if (regParmFlg) + return 0; + + regParmFlg = 1; + return 1; +} + +static bool +_xa51_parseOptions (int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void +_xa51_finaliseOptions (void) +{ + port->mem.default_local_map = istack; + port->mem.default_globl_map = xdata; +} + +static void +_xa51_setDefaultOptions (void) +{ + options.stackAuto=1; +} + +static const char * +_xa51_getRegName (struct regs *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +static void +_xa51_genAssemblerPreamble (FILE * of) +{ +} + +/* Generate interrupt vector table. */ +static int +_xa51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts) +{ + return FALSE; +} + +/* Generate code to copy XINIT to XISEG */ +static void _xa51_genXINIT (FILE * of) { + fprintf (of, "; _xa51_genXINIT() start\n"); + fprintf (of, " mov a,#l_XINIT\n"); + fprintf (of, " orl a,#l_XINIT>>8\n"); + fprintf (of, " jz 00003$\n"); + fprintf (of, " mov a,#s_XINIT\n"); + fprintf (of, " add a,#l_XINIT\n"); + fprintf (of, " mov r1,a\n"); + fprintf (of, " mov a,#s_XINIT>>8\n"); + fprintf (of, " addc a,#l_XINIT>>8\n"); + fprintf (of, " mov r2,a\n"); + fprintf (of, " mov dptr,#s_XINIT\n"); + fprintf (of, " mov r0,#s_XISEG\n"); + fprintf (of, " mov p2,#(s_XISEG >> 8)\n"); + fprintf (of, "00001$: clr a\n"); + fprintf (of, " movc a,@a+dptr\n"); + fprintf (of, " movx @r0,a\n"); + fprintf (of, " inc dptr\n"); + fprintf (of, " inc r0\n"); + fprintf (of, " cjne r0,#0,00002$\n"); + fprintf (of, " inc p2\n"); + fprintf (of, "00002$: mov a,dpl\n"); + fprintf (of, " cjne a,ar1,00001$\n"); + fprintf (of, " mov a,dph\n"); + fprintf (of, " cjne a,ar2,00001$\n"); + fprintf (of, " mov p2,#0xFF\n"); + fprintf (of, "00003$:\n"); + fprintf (of, "; _xa51_genXINIT() end\n"); +} + + +/* Do CSE estimation */ +static bool cseCostEstimation (iCode *ic, iCode *pdic) +{ + operand *result = IC_RESULT(ic); + sym_link *result_type = operandType(result); + + /* if it is a pointer then return ok for now */ + if (IC_RESULT(ic) && IS_PTR(result_type)) return 1; + + /* if bitwise | add & subtract then no since xa51 is pretty good at it + so we will cse only if they are local (i.e. both ic & pdic belong to + the same basic block */ + if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') { + /* then if they are the same Basic block then ok */ + if (ic->eBBlockNum == pdic->eBBlockNum) return 1; + else return 0; + } + + /* for others it is cheaper to do the cse */ + return 1; +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +static const char *_linkCmd[] = +{ + "{bindir}{sep}aslink", "-nf", "$1", NULL +}; + +/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */ +static const char *_asmCmd[] = +{ + "xa_asm", "$l", "$3", "$1.asm", NULL +}; + +/* Globals */ +PORT xa51_port = +{ + TARGET_ID_XA51, + "xa51", + "MCU 80C51XA", /* Target name */ + { + TRUE, /* Emit glue around main */ + MODEL_LARGE, + MODEL_LARGE + }, + { + _asmCmd, + NULL, + "-plosgffc", /* Options with debug */ + "-plosgff", /* Options without debug */ + 0, + ".asm", + NULL /* no do_assemble function */ + }, + { + _linkCmd, + NULL, + NULL, + ".rel" + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 1, 2, 3, 1, 4, 4 + }, + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + "XISEG (XDATA)", // initialized xdata + "XINIT (CODE)", // a code copy of xiseg + NULL, // default local map + NULL, // default global map + 1 + }, + { + -1, // stack grows down + 0, // bank overhead NUY + 6, // isr overhead + 4, // function call overhead + 0, // reentrant overhead NUY + 0 // banked overhead NUY + }, + /* xa51 has an 16 bit mul */ + { + 2, -2 + }, + "_", + _xa51_init, + _xa51_parseOptions, + _xa51_finaliseOptions, + _xa51_setDefaultOptions, + xa51_assignRegisters, + _xa51_getRegName, + _xa51_keywords, + _xa51_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _xa51_genIVT, + _xa51_genXINIT, + _xa51_reset_regparm, + _xa51_regparm, + NULL, + NULL, + NULL, + FALSE, + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + cseCostEstimation, + NULL, /* no builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + PORT_MAGIC +}; diff --git a/src/xa51/main.h b/src/xa51/main.h new file mode 100644 index 00000000..65552254 --- /dev/null +++ b/src/xa51/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/xa51/main.o b/src/xa51/main.o new file mode 100644 index 00000000..305d8cdf Binary files /dev/null and b/src/xa51/main.o differ diff --git a/src/xa51/peeph.def b/src/xa51/peeph.def new file mode 100644 index 00000000..e69de29b diff --git a/src/xa51/peeph.rul b/src/xa51/peeph.rul new file mode 100644 index 00000000..7e86f108 --- /dev/null +++ b/src/xa51/peeph.rul @@ -0,0 +1,3 @@ +/* Generated file, DO NOT Edit! */ +/* To Make changes to rules edit */ +/* /peeph.def instead. */ diff --git a/src/xa51/port.a b/src/xa51/port.a new file mode 100644 index 00000000..5d6cc01b Binary files /dev/null and b/src/xa51/port.a differ diff --git a/src/xa51/ralloc.c b/src/xa51/ralloc.c new file mode 100755 index 00000000..abd08afa --- /dev/null +++ b/src/xa51/ralloc.c @@ -0,0 +1,2163 @@ +/*------------------------------------------------------------------------ + + SDCCralloc.c - source file for register allocation. (xa51) specific + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "ralloc.h" +#include "gen.h" + +/*-----------------------------------------------------------------*/ +/* At this point we start getting processor specific although */ +/* some routines are non-processor specific & can be reused when */ +/* targetting other processors. The decision for this will have */ +/* to be made on a routine by routine basis */ +/* routines used to pack registers are most definitely not reusable */ +/* since the pack the registers depending strictly on the MCU */ +/*-----------------------------------------------------------------*/ + +extern void genXA51Code (iCode *); +#define D(x) + +/* Global data */ +static struct + { + bitVect *spiltSet; + set *stackSpil; + bitVect *regAssigned; + bitVect *totRegAssigned; /* final set of LRs that got into registers */ + short blockSpil; + int slocNum; + bitVect *funcrUsed; /* registers used in a function */ + int stackExtend; + int dataExtend; + } +_G; + +/* xa51 registers */ +regs regsXA51[]={ + // index size type name regMask offset isFree symbol + {0x20, 2, REG_SCR, "r0", 0x0003, 0, 1, NULL}, // r0 used for scratch + {0x21, 2, REG_SCR, "r1", 0x000c, 2, 1, NULL}, // r1 used for scratch + {0x22, 2, REG_PTR, "r2", 0x0030, 4, 1, NULL}, + {0x23, 2, REG_PTR, "r3", 0x00c0, 6, 1, NULL}, + {0x24, 2, REG_PTR, "r4", 0x0300, 8, 1, NULL}, + {0x25, 2, REG_PTR, "r5", 0x0c00, 10, 1, NULL}, + {0x26, 2, REG_PTR, "r6", 0x3000, 12, 1, NULL}, + {0x27, 2, REG_STK, "r7", 0xc000, 14, 1, NULL}, // r7=SP +#if 0 // some derivates have even more! (only word access and gpr use) + {0x28, 2, REG_GPR, "r8", 0x10000, 16, 1, NULL}, + {0x29, 2, REG_GPR, "r9", 0x20000, 18, 1, NULL}, + {0x2a, 2, REG_GPR, "r10", 0x40000, 20, 1, NULL}, + {0x2b, 2, REG_GPR, "r11", 0x80000, 22, 1, NULL}, + {0x2c, 2, REG_GPR, "r12", 0x100000, 24, 1, NULL}, + {0x2d, 2, REG_GPR, "r13", 0x200000, 26, 1, NULL}, + {0x2e, 2, REG_GPR, "r14", 0x400000, 28, 1, NULL}, + {0x2f, 2, REG_GPR, "r15", 0x800000, 20, 1, NULL}, +#endif + {0x10, 1, REG_SCR, "r0h", 0x0001, 1, 1, NULL}, // r0h used for scratch + {0x11, 1, REG_SCR, "r0l", 0x0002, 1, 1, NULL}, // r0l used for scratch + {0x12, 1, REG_SCR, "r1h", 0x0004, 2, 1, NULL}, // r1h used for scratch + {0x13, 1, REG_SCR, "r1l", 0x0008, 3, 1, NULL}, // r1l used for scratch + {0x14, 1, REG_PTR, "r2h", 0x0010, 4, 1, NULL}, + {0x15, 1, REG_PTR, "r2l", 0x0020, 5, 1, NULL}, + {0x16, 1, REG_PTR, "r3h", 0x0040, 6, 1, NULL}, + {0x17, 1, REG_PTR, "r3l", 0x0080, 7, 1, NULL}, + {0x18, 1, REG_PTR, "r4h", 0x0100, 8, 1, NULL}, + {0x19, 1, REG_PTR, "r4l", 0x0200, 9, 1, NULL}, + {0x1a, 1, REG_PTR, "r5h", 0x0400, 10, 1, NULL}, + {0x1b, 1, REG_PTR, "r5l", 0x0800, 11, 1, NULL}, + {0x1c, 1, REG_PTR, "r6h", 0x1000, 12, 1, NULL}, + {0x1d, 1, REG_PTR, "r6l", 0x2000, 13, 1, NULL}, + {0x1e, 1, REG_STK, "r7h", 0x4000, 14, 1, NULL}, // r7=SP + {0x1f, 1, REG_STK, "r7l", 0x8000, 15, 1, NULL}, // r7=SP +}; + +int xa51_nRegs=sizeof(regsXA51)/sizeof(regs); + +udword xa51RegsInUse=0; + +// this should be set with a command line switch +bool xa51HasGprRegs=0; + +/*-----------------------------------------------------------------*/ +/* xa51_regWithMask - returns pointer to register with mask */ +/*-----------------------------------------------------------------*/ +regs *xa51_regWithMask (udword mask) { + int i; + for (i=0; iname, + xa51_regWithMask(regMask)->sym->name); + + exit(1); + return; + } +} + +char *regTypeToStr(short type) { + switch (type) + { + case REG_PTR: return "ptr"; break; // pointer + case REG_GPR: return "gpr"; break; // general purpose + case REG_CND: return "cnd"; break; // condition (bit) + case REG_STK: return "stk"; break; // stack + case REG_SCR: return "scr"; break; // scratch + default: return "???"; break; + } +} + +/*-----------------------------------------------------------------*/ +/* freeReg - frees a previous allocated register */ +/*-----------------------------------------------------------------*/ +static void freeReg (regs * reg, bool silent) { + + checkRegMask(__FUNCTION__); + + if (!reg) { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "freeReg - freeing NULL register"); + return; + } + + if (!silent) { + fprintf (stderr, "freeReg: (%08x) %s ", xa51RegsInUse, reg->name); + } + + if (reg->isFree || ((xa51RegsInUse®->regMask)!=reg->regMask)) { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "freeReg - freeing unused register(s)"); + return; + } + xa51RegsInUse &= ~reg->regMask; + reg->isFree = 1; + reg->sym = NULL; + if (!silent) fprintf (stderr, "(%08x)\n", xa51RegsInUse); + + checkRegMask(__FUNCTION__); +} + +/*-----------------------------------------------------------------*/ +/* allocReg - allocates register of given size (byte, word) */ +/* and type (ptr, gpr, cnd) */ +/*-----------------------------------------------------------------*/ +static bool allocReg (short size, short type, symbol *sym, + short offset, bool silent) { + int i; + + checkRegMask(__FUNCTION__); + + if (!silent) { + fprintf (stderr, "allocReg (0x%08x) for %s size:%d, type:%s ", + xa51RegsInUse, + sym->name, + size, regTypeToStr(type)); + } + + switch (size) + { + // TODO: gaps should be filled for dwords too + case 1: + // let's see if we can fill a gap + for (i=0; iregs[offset]=reg; + xa51RegsInUse |= mask; + reg->isFree=0; // redundant + reg->sym = sym; + if (!silent) { + fprintf (stderr, "(using gap) %s\n", reg->name); + } + checkRegMask(__FUNCTION__); + return TRUE; + } + } + } + // no we can't, fall through + case 2: + for (i=0; iregs[offset]=®sXA51[i]; + checkRegMask(__FUNCTION__); + return TRUE; + } + } + if (!silent) { + fprintf (stderr, "failed (%08x)\n", xa51RegsInUse); + } + checkRegMask(__FUNCTION__); + return FALSE; + break; + case 3: + // this must be a generic pointer + if (!silent) { + fprintf (stderr, "trying 2+1\n"); + } + // get the pointer part + if (allocReg (2, REG_PTR, sym, offset, silent)) { + // get the generic part + if ((xa51HasGprRegs && allocReg (1, REG_GPR, sym, offset+1, silent)) || + allocReg (1, REG_PTR, sym, offset+1, silent)) { + checkRegMask(__FUNCTION__); + return TRUE; + } + freeReg(sym->regs[offset], silent); + sym->regs[offset]=NULL; + } + checkRegMask(__FUNCTION__); + return FALSE; + break; + case 4: // this is a dword + if (!silent) { + fprintf (stderr, "trying 2+2\n"); + } + if ((xa51HasGprRegs && allocReg (2, REG_GPR, sym, offset, silent)) || + allocReg (2, REG_PTR, sym, offset, silent)) { + if ((xa51HasGprRegs && allocReg (2, REG_GPR, sym, offset+1, silent)) || + allocReg (2, REG_PTR, sym, offset+1, silent)) { + checkRegMask(__FUNCTION__); + return TRUE; + } + } + freeReg(sym->regs[offset], FALSE); + sym->regs[offset]=NULL; + checkRegMask(__FUNCTION__); + return FALSE; + break; + default: + fprintf (stderr, "\nallocReg: cannot allocate reg of size %d\n", size); + exit (1); + break; + } + // we should never come here + return FALSE; +} + +/*-------------------------------------------------------------------*/ +/* freeAllRegs - frees all registers */ +/*-------------------------------------------------------------------*/ +// just to be sure, this should not be needed +static void freeAllRegs (void) { + char regsFreed[132]; + int i; + int nfr = 0; + + checkRegMask(__FUNCTION__); + + regsFreed[0]=0; + for (i=0; isize; i++) + { + iCode *ic; + + if (bitVectBitValue (defs, i) && + (ic = hTabItemWithKey (iCodehTab, i)) && + (ic->seq >= fseq && ic->seq <= toseq)) + return FALSE; + } + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* computeSpillable - given a point find the spillable live ranges */ +/*-----------------------------------------------------------------*/ +static bitVect *computeSpillable (iCode * ic) { + bitVect *spillable; + + /* spillable live ranges are those that are live at this + point . the following categories need to be subtracted + from this set. + a) - those that are already spilt + b) - if being used by this one + c) - defined by this one */ + + spillable = bitVectCopy (ic->rlive); + spillable = + bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */ + spillable = + bitVectCplAnd (spillable, ic->uses); /* used in this one */ + bitVectUnSetBit (spillable, ic->defKey); /* defined by this one */ + spillable = bitVectIntersect (spillable, _G.regAssigned); + return spillable; + +} + +/*-----------------------------------------------------------------*/ +/* noSpilLoc - return true if a variable has no spil location */ +/*-----------------------------------------------------------------*/ +static int +noSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (sym->usl.spillLoc ? 0 : 1); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLoc - will return 1 if the symbol has spil location */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (sym->usl.spillLoc ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLocnoUptr - will return 1 if the symbol has spil location */ +/* but is not used as a pointer */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* rematable - will return 1 if the remat flag is set */ +/*-----------------------------------------------------------------*/ +static int +rematable (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return sym->remat; +} + +/*-----------------------------------------------------------------*/ +/* notUsedInBlock - not used in this block */ +/*-----------------------------------------------------------------*/ +static int +notUsedInBlock (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (!bitVectBitsInCommon (sym->defs, ebp->usesDefs) && + allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq)); +/* return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs)); */ +} + +/*-----------------------------------------------------------------*/ +/* notUsedInRemaining - not used or defined in remain of the block */ +/*-----------------------------------------------------------------*/ +static int +notUsedInRemaining (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return ((usedInRemaining (operandFromSymbol (sym), ic) ? 0 : 1) && + allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq)); +} + +/*-----------------------------------------------------------------*/ +/* allLRs - return true for all */ +/*-----------------------------------------------------------------*/ +static int +allLRs (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* liveRangesWith - applies function to a given set of live range */ +/*-----------------------------------------------------------------*/ +static set * +liveRangesWith (bitVect * lrs, int (func) (symbol *, eBBlock *, iCode *), + eBBlock * ebp, iCode * ic) +{ + set *rset = NULL; + int i; + + if (!lrs || !lrs->size) + return NULL; + + for (i = 1; i < lrs->size; i++) + { + symbol *sym; + if (!bitVectBitValue (lrs, i)) + continue; + + /* if we don't find it in the live range + hash table we are in serious trouble */ + if (!(sym = hTabItemWithKey (liveRanges, i))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "liveRangesWith could not find liveRange"); + exit (1); + } + + if (func (sym, ebp, ic) && bitVectBitValue (_G.regAssigned, sym->key)) + addSetHead (&rset, sym); + } + + return rset; +} + + +/*-----------------------------------------------------------------*/ +/* leastUsedLR - given a set determines which is the least used */ +/*-----------------------------------------------------------------*/ +static symbol * +leastUsedLR (set * sset) +{ + symbol *sym = NULL, *lsym = NULL; + + sym = lsym = setFirstItem (sset); + + if (!lsym) + return NULL; + + for (; lsym; lsym = setNextItem (sset)) + { + + /* if usage is the same then prefer + the spill the smaller of the two */ + if (lsym->used == sym->used) + if (getSize (lsym->type) < getSize (sym->type)) + sym = lsym; + + /* if less usage */ + if (lsym->used < sym->used) + sym = lsym; + + } + + setToNull ((void **) &sset); + sym->blockSpil = 0; + return sym; +} + +/*-----------------------------------------------------------------*/ +/* noOverLap - will iterate through the list looking for over lap */ +/*-----------------------------------------------------------------*/ +static int +noOverLap (set * itmpStack, symbol * fsym) +{ + symbol *sym; + + + for (sym = setFirstItem (itmpStack); sym; + sym = setNextItem (itmpStack)) + { + if (bitVectBitValue(sym->clashes,fsym->key)) return 0; + } + + return 1; +} + +/*-----------------------------------------------------------------*/ +/* isFree - will return 1 if the a free spil location is found */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (isFree) +{ + symbol *sym = item; + V_ARG (symbol **, sloc); + V_ARG (symbol *, fsym); + + /* if already found */ + if (*sloc) + return 0; + + /* if it is free && and the itmp assigned to + this does not have any overlapping live ranges + with the one currently being assigned and + the size can be accomodated */ + if (sym->isFree && + noOverLap (sym->usl.itmpStack, fsym) && + getSize (sym->type) >= getSize (fsym->type)) + { + *sloc = sym; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +static symbol * +createStackSpil (symbol * sym) +{ + symbol *sloc = NULL; + int useXstack, model; + + char slocBuffer[30]; + + fprintf (stderr, " createStackSpil: %s\n", sym->name); + + /* first go try and find a free one that is already + existing on the stack */ + if (applyToSet (_G.stackSpil, isFree, &sloc, sym)) + { + /* found a free one : just update & return */ + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + sloc->isFree = 0; + addSetHead (&sloc->usl.itmpStack, sym); + return sym; + } + + /* could not then have to create one , this is the hard part + we need to allocate this on the stack : this is really a + hack!! but cannot think of anything better at this time */ + + if (sprintf (slocBuffer, "sloc%d", _G.slocNum++) >= sizeof (slocBuffer)) + { + fprintf (stderr, "***Internal error: slocBuffer overflowed: %s:%d\n", + __FILE__, __LINE__); + exit (1); + } + + sloc = newiTemp (slocBuffer); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain (sym->type); + sloc->etype = getSpec (sloc->type); + SPEC_SCLS (sloc->etype) = S_STACK; + SPEC_EXTR (sloc->etype) = 0; + SPEC_STAT (sloc->etype) = 0; + SPEC_VOLATILE(sloc->etype) = 0; + SPEC_ABSA(sloc->etype) = 0; + + /* we don't allow it to be allocated` + onto the external stack since : so we + temporarily turn it off ; we also + turn off memory model to prevent + the spil from going to the external storage + */ + + useXstack = options.useXstack; + model = options.model; +/* noOverlay = options.noOverlay; */ +/* options.noOverlay = 1; */ + options.model = options.useXstack = 0; + + allocLocal (sloc); + + options.useXstack = useXstack; + options.model = model; +/* options.noOverlay = noOverlay; */ + sloc->isref = 1; /* to prevent compiler warning */ + + /* if it is on the stack then update the stack */ + if (IN_STACK (sloc->etype)) + { + currFunc->stack += getSize (sloc->type); + _G.stackExtend += getSize (sloc->type); + } + else + _G.dataExtend += getSize (sloc->type); + + /* add it to the _G.stackSpil set */ + addSetHead (&_G.stackSpil, sloc); + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + + /* add it to the set of itempStack set + of the spill location */ + addSetHead (&sloc->usl.itmpStack, sym); + return sym; +} + +/*-----------------------------------------------------------------*/ +/* spillThis - spils a specific operand */ +/*-----------------------------------------------------------------*/ +static void +spillThis (symbol * sym) +{ + int i; + + fprintf (stderr, " spillThis: %s\n", sym->name); + + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ + if (!(sym->remat || sym->usl.spillLoc)) + createStackSpil (sym); + + + /* mark it has spilt & put it in the spilt set */ + sym->isspilt = sym->spillA = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key); + + bitVectUnSetBit (_G.regAssigned, sym->key); + bitVectUnSetBit (_G.totRegAssigned, sym->key); + + for (i = 0; i < sym->nRegs; i++) + + if (sym->regs[i]) + { + freeReg (sym->regs[i], FALSE); + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq++; + return; +} + +/*-----------------------------------------------------------------*/ +/* selectSpil - select a iTemp to spil : rather a simple procedure */ +/*-----------------------------------------------------------------*/ +static symbol * +selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + bitVect *lrcs = NULL; + set *selectS; + symbol *sym; + + /* get the spillable live ranges */ + lrcs = computeSpillable (ic); + + /* get all live ranges that are rematerizable */ + if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic))) + { + /* return the least used of these */ + return leastUsedLR (selectS); + } + + /* if the symbol is local to the block then */ + if (forSym->liveTo < ebp->lSeq) + { + + /* check if there are any live ranges allocated + to registers that are not used in this block */ + if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInBlock, ebp, ic))) + { + sym = leastUsedLR (selectS); + /* if this is not rematerializable */ + if (!sym->remat) + { + _G.blockSpil++; + sym->blockSpil = 1; + } + return sym; + } + + /* check if there are any live ranges that not + used in the remainder of the block */ + if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInRemaining, ebp, ic))) + { + sym = leastUsedLR (selectS); + if (sym != forSym) + { + if (!sym->remat) + { + sym->remainSpil = 1; + _G.blockSpil++; + } + return sym; + } + } + } + + /* find live ranges with spillocation && not used as pointers */ + if ((selectS = liveRangesWith (lrcs, hasSpilLocnoUptr, ebp, ic))) + { + + sym = leastUsedLR (selectS); + /* mark this as allocation required */ + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* find live ranges with spillocation */ + if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic))) + { + + sym = leastUsedLR (selectS); + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* couldn't find then we need to create a spil + location on the stack , for which one? the least + used ofcourse */ + if ((selectS = liveRangesWith (lrcs, noSpilLoc, ebp, ic))) + { + + /* return a created spil location */ + sym = createStackSpil (leastUsedLR (selectS)); + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* this is an extreme situation we will spill + this one : happens very rarely but it does happen */ + spillThis (forSym); + return forSym; +} + +/*-----------------------------------------------------------------*/ +/* spillSomething - spil some variable & mark registers as free */ +/*-----------------------------------------------------------------*/ +static bool +spillSomething (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + symbol *ssym; + int i; + + /* get something we can spil */ + ssym = selectSpil (ic, ebp, forSym); + + fprintf (stderr, " spillSomething: spilling %s\n", ssym->name); + + /* mark it as spilt */ + ssym->isspilt = ssym->spillA = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key); + + /* mark it as not register assigned & + take it away from the set */ + bitVectUnSetBit (_G.regAssigned, ssym->key); + bitVectUnSetBit (_G.totRegAssigned, ssym->key); + + /* mark the registers as free */ + for (i = 0; i < ssym->nRegs; i++) { + if (ssym->regs[i]) { + freeReg (ssym->regs[i], FALSE); + // dont NULL ssym->regs[i], it might be used later + } + } + + /* if this was a block level spil then insert push & pop + at the start & end of block respectively */ + if (ssym->blockSpil) + { + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push to the start of the block */ + addiCodeToeBBlock (ebp, nic, (ebp->sch->op == LABEL ? + ebp->sch->next : ebp->sch)); + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + /* if spilt because not used in the remainder of the + block then add a push before this instruction and + a pop at the end of the block */ + if (ssym->remainSpil) + { + + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push just before this instruction */ + addiCodeToeBBlock (ebp, nic, ic); + + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + if (ssym == forSym) + return FALSE; + else + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* getRegPtr - will try for PTR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static bool getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym, short offset) { + + fprintf (stderr, "getRegPtr: %s ", sym->name); + printTypeChain(sym->type, stderr); + fprintf (stderr, "\n"); + +tryAgain: + /* try for a ptr type */ + if (allocReg (getSize(sym->type), REG_PTR, sym, offset, FALSE)) + return TRUE; + + /* try for gpr type */ + if (xa51HasGprRegs && allocReg (getSize(sym->type), + REG_GPR, sym, offset, FALSE)) + return TRUE; + + /* we have to spil */ + if (!spillSomething (ic, ebp, sym)) + return FALSE; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegGpr - will try for GPR if not spil */ +/*-----------------------------------------------------------------*/ +static bool getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym, short offset) { + + fprintf (stderr, "getRegGpr: %s ", sym->name); + printTypeChain(sym->type, stderr); + fprintf (stderr, "\n"); + +tryAgain: + /* try for gpr type */ + if (xa51HasGprRegs && allocReg (getSize(sym->type), + REG_GPR, sym, offset, FALSE)) + return TRUE; + + if (allocReg (getSize(sym->type), REG_PTR, sym, offset, FALSE)) + return TRUE; + + /* we have to spil */ + if (!spillSomething (ic, ebp, sym)) + return FALSE; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* deassignLRs - check the live to and if they have registers & are */ +/* not spilt then free up the registers */ +/*-----------------------------------------------------------------*/ +static void +deassignLRs (iCode * ic, eBBlock * ebp) +{ + symbol *sym; + int k; + + for (sym = hTabFirstItem (liveRanges, &k); sym; + sym = hTabNextItem (liveRanges, &k)) + { + /* if it does not end here */ + if (sym->liveTo > ic->seq) + continue; + + /* if it was spilt on stack then we can + mark the stack spil location as free */ + if (sym->isspilt) + { + if (sym->stackSpil) + { + sym->usl.spillLoc->isFree = 1; + sym->stackSpil = 0; + } + continue; + } + + if (!bitVectBitValue (_G.regAssigned, sym->key)) + continue; + + if (sym->nRegs) { + int i; + + bitVectUnSetBit (_G.regAssigned, sym->key); + + /* free the regs */ + for (i=0; i < sym->nRegs; i++) { + freeReg (sym->regs[i], FALSE); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* willCauseSpill - determines if allocating will cause a spill */ +/*-----------------------------------------------------------------*/ +static bool willCauseSpill (symbol *sym) { + int i; + // do it the rude way + if (allocReg (getSize(sym->type), sym->regType, sym, 0, TRUE) || + allocReg (getSize(sym->type), sym->regType==REG_PTR?REG_GPR:REG_PTR, + sym, 0, TRUE)) { + // so we can, but we won't + for (i=0; inRegs; i++) { + freeReg (sym->regs[i], TRUE); + sym->regs[i]=NULL; + } + return FALSE; + } + fprintf (stderr, " %s will cause a spill\n", sym->name); + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* positionRegs - the allocator can allocate same registers to res- */ +/* ult and operand, if this happens make sure they are in the same */ +/* position as the operand otherwise chaos results */ +/*-----------------------------------------------------------------*/ +static int +positionRegs (symbol * result, symbol * opsym) +{ + int count = min (result->nRegs, opsym->nRegs); + int i, j = 0, shared = 0; + int change = 0; + + /* if the result has been spilt then cannot share */ + if (opsym->isspilt) + return 0; +again: + shared = 0; + /* first make sure that they actually share */ + for (i = 0; i < count; i++) + { + for (j = 0; j < count; j++) + { + if (result->regs[i] == opsym->regs[j] && i != j) + { + shared = 1; + goto xchgPositions; + } + } + } +xchgPositions: + if (shared) + { + regs *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + change ++; + goto again; + } + return change; +} + +/*-----------------------------------------------------------------*/ +/* serialRegAssign - serially allocate registers to the variables */ +/*-----------------------------------------------------------------*/ +static void +serialRegAssign (eBBlock ** ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count; i++) { + + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel)) + continue; + + /* of all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) { + + /* if result is present && is a true symbol */ + if (IC_RESULT (ic) && ic->op != IFX && + IS_TRUE_SYMOP (IC_RESULT (ic))) + OP_SYMBOL (IC_RESULT (ic))->allocreq++; + + /* take away registers from live + ranges that end at this instruction */ + deassignLRs (ic, ebbs[i]); + + /* some don't need registers */ + if (SKIP_IC2 (ic) || + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + (IC_RESULT (ic) && POINTER_SET (ic))) + continue; + + /* now we need to allocate registers + only for the result */ + if (IC_RESULT (ic)) { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + bitVect *spillable; + int willCS; + + /* if it does not need or is spilt + or is already assigned to registers + or will not live beyond this instructions */ + if (!sym->nRegs || + sym->isspilt || + bitVectBitValue (_G.regAssigned, sym->key) || + sym->liveTo <= ic->seq) + continue; + + /* if some liverange has been spilt at the block level + and this one live beyond this block then spil this + to be safe */ + if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq) { + spillThis (sym); + continue; + } + /* if trying to allocate this will cause + a spill and there is nothing to spill + or this one is rematerializable then + spill this one */ + willCS = willCauseSpill (sym); + spillable = computeSpillable (ic); + if (sym->remat || (willCS && bitVectIsZero (spillable))) { + spillThis (sym); + continue; + } + + /* if it has a spillocation & is used less than + all other live ranges then spill this */ + if (willCS) { + if (sym->usl.spillLoc) { + symbol *leastUsed = leastUsedLR (liveRangesWith (spillable, + allLRs, ebbs[i], ic)); + if (leastUsed && leastUsed->used > sym->used) { + spillThis (sym); + continue; + } + } else { + /* if none of the liveRanges have a spillLocation then better + to spill this one than anything else already assigned to registers */ + if (liveRangesWith(spillable,noSpilLoc,ebbs[i],ic)) { + /* if this is local to this block then we might find a block spil */ + if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq)) { + spillThis (sym); + continue; + } + } + } + } + + /* else we assign registers to it */ + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key); + + if (sym->regType == REG_PTR) + getRegPtr (ic, ebbs[i], sym, 0); + else + getRegGpr (ic, ebbs[i], sym, 0); + + /* if it shares registers with operands make sure + that they are in the same position */ + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->nRegs && ic->op != '=') { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), + OP_SYMBOL (IC_LEFT (ic))); + } + /* do the same for the right operand */ + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->nRegs) { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), + OP_SYMBOL (IC_RIGHT (ic))); + } + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +bitVect *xa51_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 || !sym->regs[0]) + return NULL; + + rumask = newBitVect (xa51_nRegs); + + for (j = 0; j < sym->nRegs; j++) { + rumask = bitVectSetBit (rumask, + sym->regs[j]->rIdx); + } + return rumask; +} + +/*-----------------------------------------------------------------*/ +/* regsUsedIniCode :- returns bit vector of registers used in iCode */ +/*-----------------------------------------------------------------*/ +static bitVect * +regsUsedIniCode (iCode * ic) +{ + bitVect *rmask = newBitVect (xa51_nRegs); + + /* do the special cases first */ + if (ic->op == IFX) + { + rmask = bitVectUnion (rmask, + xa51_rUmaskForOp (IC_COND (ic))); + goto ret; + } + + /* for the jumptable */ + if (ic->op == JUMPTABLE) + { + rmask = bitVectUnion (rmask, + xa51_rUmaskForOp (IC_JTCOND (ic))); + + goto ret; + } + + /* of all other cases */ + if (IC_LEFT (ic)) + rmask = bitVectUnion (rmask, + xa51_rUmaskForOp (IC_LEFT (ic))); + + + if (IC_RIGHT (ic)) + rmask = bitVectUnion (rmask, + xa51_rUmaskForOp (IC_RIGHT (ic))); + + if (IC_RESULT (ic)) + rmask = bitVectUnion (rmask, + xa51_rUmaskForOp (IC_RESULT (ic))); + +ret: + return rmask; +} + +/*-----------------------------------------------------------------*/ +/* createRegMask - for each instruction will determine the regsUsed */ +/*-----------------------------------------------------------------*/ +static void +createRegMask (eBBlock ** ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel)) + continue; + + /* for all instructions */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + + int j; + + if (SKIP_IC2 (ic) || !ic->rlive) + continue; + + /* first mark the registers used in this + instruction */ + ic->rUsed = regsUsedIniCode (ic); + _G.funcrUsed = bitVectUnion (_G.funcrUsed, ic->rUsed); + + /* now create the register mask for those + registers that are in use : this is a + super set of ic->rUsed */ + ic->rMask = newBitVect (xa51_nRegs + 1); + + /* for all live Ranges alive at this point */ + for (j = 1; j < ic->rlive->size; j++) + { + symbol *sym; + int k; + + /* if not alive then continue */ + if (!bitVectBitValue (ic->rlive, j)) + continue; + + /* find the live range we are interested in */ + if (!(sym = hTabItemWithKey (liveRanges, j))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "createRegMask cannot find live range"); + exit (0); + } + + /* if no register assigned to it */ + if (!sym->nRegs || sym->isspilt) + continue; + + /* for all the registers allocated to it */ + for (k = 0; k < sym->nRegs; k++) + if (sym->regs[k]) + ic->rMask = + bitVectSetBit (ic->rMask, sym->regs[k]->rIdx); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static char * +rematStr (symbol * sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + + while (1) + { + + /* if plus or minus print the right hand side */ + if (ic->op == '+' || ic->op == '-') + { + sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)), + ic->op); + s += strlen (s); + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + continue; + } + + /* cast then continue */ + if (IS_CAST_ICODE(ic)) { + ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + continue; + } + /* we reached the end */ + sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname); + break; + } + + return buffer; +} + +/*-----------------------------------------------------------------*/ +/* regTypeNum - computes the type & number of registers required */ +/*-----------------------------------------------------------------*/ +static void +regTypeNum (eBBlock *ebbs) +{ + symbol *sym; + int k; + iCode *ic; + + /* for each live range do */ + for (sym = hTabFirstItem (liveRanges, &k); sym; + sym = hTabNextItem (liveRanges, &k)) + { + + /* if used zero times then no registers needed */ + if ((sym->liveTo - sym->liveFrom) == 0) + continue; + + + /* if the live range is a temporary */ + if (sym->isitmp) + { + + /* if the type is marked as a conditional */ + if (sym->regType == REG_CND) + continue; + + /* if used in return only then we don't + need registers */ +#if 0 // not yet + if (sym->ruonly || sym->accuse) + { + if (IS_AGGREGATE (sym->type) || sym->isptr) + sym->type = aggrToPtr (sym->type, FALSE); + continue; + } +#endif + + /* if the symbol has only one definition & + that definition is a get_pointer and the + pointer we are getting is rematerializable and + in "data" space */ + + if (bitVectnBitsOn (sym->defs) == 1 && + (ic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (sym->defs))) && + POINTER_GET (ic) && + !sym->noSpilLoc && + !IS_BITVAR (sym->etype)) + { + + + /* if remat in data space */ + if (OP_SYMBOL (IC_LEFT (ic))->remat && + !IS_CAST_ICODE(OP_SYMBOL (IC_LEFT (ic))->rematiCode) && + DCL_TYPE (aggrToPtr (sym->type, FALSE)) == POINTER) + { + /* create a psuedo symbol & force a spil */ + symbol *psym = newSymbol (rematStr (OP_SYMBOL (IC_LEFT (ic))), 1); + psym->type = sym->type; + psym->etype = sym->etype; + strcpy (psym->rname, psym->name); + sym->isspilt = 1; + sym->usl.spillLoc = psym; +#if 0 // an alternative fix for bug #480076 + /* now this is a useless assignment to itself */ + remiCodeFromeBBlock (ebbs, ic); +#else + /* now this really is an assignment to itself, make it so; + it will be optimized out later */ + ic->op='='; + IC_RIGHT(ic)=IC_RESULT(ic); + IC_LEFT(ic)=NULL; +#endif + continue; + } + + /* if in data space or idata space then try to + allocate pointer register */ + + } + + /* if not then we require registers */ +#if 0 + sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ? + getSize (sym->type = aggrToPtr (sym->type, FALSE)) : + getSize (sym->type)); +#else + { + int size=((IS_AGGREGATE (sym->type) || sym->isptr) ? + getSize (sym->type = aggrToPtr (sym->type, FALSE)) : + getSize (sym->type)); + switch (size) + { + case 1: // byte + case 2: // word or pointer + sym->nRegs=1; + break; + case 3: // generic pointer + sym->nRegs=2; + break; + case 4: // dword or float + sym->nRegs=2; + break; + default: + fprintf (stderr, "regTypeNum: unknown size\n"); + exit (1); + } + } +#endif + + if (sym->nRegs > 4) + { + fprintf (stderr, "allocated more than 4 or 0 registers for type "); + printTypeChain (sym->type, stderr); + fprintf (stderr, "\n"); + } + + /* determine the type of register required */ + if (IS_PTR (sym->type)) + sym->regType = REG_PTR; + else + sym->regType = REG_GPR; + + } + else + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + sym->nRegs = 0; + } + +} + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal (sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAssign - register reduction for assignment */ +/*-----------------------------------------------------------------*/ +static int +packRegsForAssign (iCode * ic, eBBlock * ebp) +{ + iCode *dic, *sic; + + if (!IS_ITEMP (IC_RIGHT (ic)) || + OP_LIVETO (IC_RIGHT (ic)) > ic->seq) { + return 0; + } + + /* find the definition of iTempNN scanning backwards */ + for (dic = ic->prev; dic; dic = dic->prev) { + + /* if there is a function call then don't pack it */ + if ((dic->op == CALL || dic->op == PCALL)) { + dic = NULL; + break; + } + + if (SKIP_IC2 (dic)) + continue; + + if (IS_SYMOP (IC_RESULT (dic)) && + IC_RESULT (dic)->key == IC_RIGHT (ic)->key) { + break; + } + + } + + if (!dic) + return 0; /* did not find */ + + /* found the definition */ + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + 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); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + return 1; + +} + +/*-----------------------------------------------------------------*/ +/* findAssignToSym : scanning backwards looks for first assig found */ +/*-----------------------------------------------------------------*/ +static iCode * +findAssignToSym (operand * op, iCode * ic) +{ + iCode *dic; + + 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 + FALSE */ + if (!IS_SYMOP (IC_RIGHT (dic))) + return NULL; + + /* if the symbol is in far space then + we should not */ + if (isOperandInFarSpace (IC_RIGHT (dic))) + return NULL; + + /* for + & - operations make sure that + if it is on the stack it is the same + as one of the three operands */ + if ((ic->op == '+' || ic->op == '-') && + OP_SYMBOL (IC_RIGHT (dic))->onStack) + { + + if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key && + IC_LEFT (ic)->key != IC_RIGHT (dic)->key && + IC_RIGHT (ic)->key != IC_RIGHT (dic)->key) + return NULL; + } + + break; + + } + + /* if we find an usage then we cannot delete it */ + if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key) + return NULL; + + if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key) + return NULL; + + if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key) + return NULL; + } + + /* now make sure that the right side of dic + is not defined between ic & dic */ + if (dic) + { + iCode *sic = dic->next; + + for (; sic != ic; sic = sic->next) + if (IC_RESULT (sic) && + IC_RESULT (sic)->key == IC_RIGHT (dic)->key) + return NULL; + } + + return dic; + + +} + +/*-----------------------------------------------------------------*/ +/* packRegsForSupport :- reduce some registers for support calls */ +/*-----------------------------------------------------------------*/ +static int +packRegsForSupport (iCode * ic, eBBlock * ebp) +{ + int change = 0; + iCode *dic, *sic; + + /* for the left & right operand :- look to see if the + left was assigned a true symbol in far space in that + case replace them */ + + if (IS_ITEMP (IC_LEFT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq) + { + dic = findAssignToSym (IC_LEFT (ic), ic); + + if (!dic) + 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); + + OP_SYMBOL(IC_LEFT (ic))=OP_SYMBOL(IC_RIGHT (dic)); + IC_LEFT (ic)->key = OP_SYMBOL(IC_RIGHT (dic))->key; + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + /* do the same for the right operand */ + right: + if (!change && + IS_ITEMP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq) + { + iCode *dic = findAssignToSym (IC_RIGHT (ic), ic); + iCode *sic; + + if (!dic) + return change; + + /* if this is a subtraction & the result + is a true symbol in far space then don't pack */ + if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic))) + { + sym_link *etype = getSpec (operandType (IC_RESULT (dic))); + if (IN_FARSPACE (SPEC_OCLS (etype))) + return change; + } + /* found it we need to remove it from the + block */ + for (sic = dic; sic != ic; sic = sic->next) + bitVectUnSetBit (sic->rlive, IC_RIGHT (ic)->key); + + IC_RIGHT (ic)->operand.symOperand = + IC_RIGHT (dic)->operand.symOperand; + IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key; + + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + return change; +} + +#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly) + + +/*-----------------------------------------------------------------*/ +/* packRegsForOneuse : - will reduce some registers for single Use */ +/*-----------------------------------------------------------------*/ +static iCode * +packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp) +{ + bitVect *uses; + iCode *dic, *sic; + + /* if returning a literal then do nothing */ + if (!IS_SYMOP (op)) + return NULL; + + if (ic->op != RETURN && + ic->op != SEND && + !POINTER_SET (ic) && + !POINTER_GET (ic)) + return NULL; + + /* this routine will mark the a symbol as used in one + instruction use only && if the defintion is local + (ie. within the basic block) && has only one definition && + that definiion is either a return value from a + function or does not contain any variables in + far space */ + uses = bitVectCopy (OP_USES (op)); + bitVectUnSetBit (uses, ic->key); /* take away this iCode */ + if (!bitVectIsZero (uses)) /* has other uses */ + return NULL; + + /* if it has only one defintion */ + if (bitVectnBitsOn (OP_DEFS (op)) > 1) + return NULL; /* has more than one definition */ + + /* get that definition */ + if (!(dic = + hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_DEFS (op))))) + return NULL; + + /* if that only usage is a cast */ + if (dic->op == CAST) { + /* to a bigger type */ + if (getSize(OP_SYM_TYPE(IC_RESULT(dic))) > + getSize(OP_SYM_TYPE(IC_RIGHT(dic)))) { + /* than we can not, since we cannot predict the usage of b & acc */ + return NULL; + } + } + + /* found the definition now check if it is local */ + if (dic->seq < ebp->fSeq || + dic->seq > ebp->lSeq) + return NULL; /* non-local */ + + /* now check if it is the return from + a function call */ + if (dic->op == CALL || dic->op == PCALL) + { + if (ic->op != SEND && ic->op != RETURN && + !POINTER_SET(ic) && !POINTER_GET(ic)) + { + OP_SYMBOL (op)->ruonly = 1; + return dic; + } + dic = dic->next; + } + + + /* otherwise check that the definition does + not contain any symbols in far space */ + if (isOperandInFarSpace (IC_LEFT (dic)) || + isOperandInFarSpace (IC_RIGHT (dic)) || + IS_OP_RUONLY (IC_LEFT (ic)) || + IS_OP_RUONLY (IC_RIGHT (ic))) + { + return NULL; + } + + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE))) + return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE))) + return NULL; + + sic = dic; + + /* also make sure the intervenening instructions + don't have any thing in far space */ + for (dic = dic->next; dic && dic != ic && sic != ic; dic = dic->next) + { + + /* if there is an intervening function call then no */ + if (dic->op == CALL || dic->op == PCALL) + return NULL; + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE))) + return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE))) + return NULL; + + /* if address of & the result is remat the okay */ + if (dic->op == ADDRESS_OF && + OP_SYMBOL (IC_RESULT (dic))->remat) + continue; + + /* if operand has size of three or more & this + operation is a '*','/' or '%' then 'b' may + cause a problem */ + if ((dic->op == '%' || dic->op == '/' || dic->op == '*') && + getSize (operandType (op)) >= 3) + return NULL; + + /* if left or right or result is in far space */ + if (isOperandInFarSpace (IC_LEFT (dic)) || + isOperandInFarSpace (IC_RIGHT (dic)) || + isOperandInFarSpace (IC_RESULT (dic)) || + IS_OP_RUONLY (IC_LEFT (dic)) || + IS_OP_RUONLY (IC_RIGHT (dic)) || + IS_OP_RUONLY (IC_RESULT (dic))) + { + return NULL; + } + /* if left or right or result is on stack */ + if (isOperandOnStack(IC_LEFT(dic)) || + isOperandOnStack(IC_RIGHT(dic)) || + isOperandOnStack(IC_RESULT(dic))) { + return NULL; + } + } + + OP_SYMBOL (op)->ruonly = 1; + return sic; + +} + +/*-----------------------------------------------------------------*/ +/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */ +/*-----------------------------------------------------------------*/ +static bool +isBitwiseOptimizable (iCode * ic) +{ + sym_link *ltype = getSpec (operandType (IC_LEFT (ic))); + sym_link *rtype = getSpec (operandType (IC_RIGHT (ic))); + + /* bitwise operations are considered optimizable + under the following conditions (Jean-Louis VERN) + + x & lit + bit & bit + bit & x + bit ^ bit + bit ^ x + x ^ lit + x | lit + bit | bit + bit | x + */ + if (IS_LITERAL(rtype) || + (IS_BITVAR (ltype) && IN_BITSPACE (SPEC_OCLS (ltype)))) + return TRUE; + else + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* packForPush - hueristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void +packForPush (iCode * ic, eBBlock * ebp) +{ + iCode *dic, *lic; + bitVect *dbv; + + if (ic->op != IPUSH || !IS_ITEMP (IC_LEFT (ic))) + return; + + /* must have only definition & one usage */ + if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic))) != 1 || + bitVectnBitsOn (OP_USES (IC_LEFT (ic))) != 1) + return; + + /* find the definition */ + if (!(dic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_DEFS (IC_LEFT (ic)))))) + return; + + if (dic->op != '=' || POINTER_SET (dic)) + return; + + /* make sure the right side does not have any definitions + inbetween */ + dbv = OP_DEFS(IC_RIGHT(dic)); + for (lic = ic; lic && lic != dic ; lic = lic->prev) { + if (bitVectBitValue(dbv,lic->key)) + return ; + } + /* make sure they have the same type */ + { + sym_link *itype=operandType(IC_LEFT(ic)); + sym_link *ditype=operandType(IC_RIGHT(dic)); + + if (SPEC_USIGN(itype)!=SPEC_USIGN(ditype) || + SPEC_LONG(itype)!=SPEC_LONG(ditype)) + return; + } + /* extend the live range of replaced operand if needed */ + if (OP_SYMBOL(IC_RIGHT(dic))->liveTo < ic->seq) { + OP_SYMBOL(IC_RIGHT(dic))->liveTo = ic->seq; + } + /* we now know that it has one & only one def & use + and the that the definition is an assignment */ + IC_LEFT (ic) = IC_RIGHT (dic); + + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); +} + +/*-----------------------------------------------------------------*/ +/* packRegisters - does some transformations to reduce register */ +/* pressure */ +/*-----------------------------------------------------------------*/ +static void packRegisters (eBBlock * ebp) { + iCode *ic; + int change = 0; + + while (1) { + change = 0; + + for (ic = ebp->sch; ic; ic = ic->next) { + if (ic->op == '=') + change += packRegsForAssign (ic, ebp); + } + + if (!change) + break; + } + return; // that's it for now + + for (ic = ebp->sch; ic; ic = ic->next) + { + /* if this is an itemp & result of an address of a true sym + then mark this as rematerialisable */ + if (ic->op == ADDRESS_OF && + IS_ITEMP (IC_RESULT (ic)) && + IS_TRUE_SYMOP (IC_LEFT (ic)) && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && + !OP_SYMBOL (IC_LEFT (ic))->onStack) + { + + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + + } + + /* if straight assignment then carry remat flag if + this is the only definition */ + if (ic->op == '=' && + !POINTER_SET (ic) && + IS_SYMOP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->remat && + !IS_CAST_ICODE(OP_SYMBOL (IC_RIGHT (ic))->rematiCode) && + bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1) + { + + OP_SYMBOL (IC_RESULT (ic))->remat = + OP_SYMBOL (IC_RIGHT (ic))->remat; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = + OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + } + + /* if cast to a generic pointer & the pointer being + cast is remat, then we can remat this cast as well */ + if (ic->op == CAST && + IS_SYMOP(IC_RIGHT(ic)) && + OP_SYMBOL(IC_RIGHT(ic))->remat ) { + sym_link *to_type = operandType(IC_LEFT(ic)); + sym_link *from_type = operandType(IC_RIGHT(ic)); + if (IS_GENPTR(to_type) && IS_PTR(from_type)) { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + } + + /* if this is a +/- operation with a rematerizable + then mark this as rematerializable as well */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + IS_OP_LITERAL (IC_RIGHT (ic))) && + OP_SYMBOL (IC_LEFT (ic))->remat && + (!IS_SYMOP (IC_RIGHT (ic)) || !IS_CAST_ICODE(OP_SYMBOL (IC_RIGHT (ic))->rematiCode)) && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* mark the pointer usages */ + if (POINTER_SET (ic)) + OP_SYMBOL (IC_RESULT (ic))->uptr = 1; + + if (POINTER_GET (ic)) + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + + /* if the condition of an if instruction + is defined in the previous instruction and + this is the only usage then + mark the itemp as a conditional */ + if ((IS_CONDITIONAL (ic) || + (IS_BITWISE_OP(ic) && isBitwiseOptimizable (ic))) && + ic->next && ic->next->op == IFX && + bitVectnBitsOn (OP_USES(IC_RESULT(ic)))==1 && + isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) && + OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq) + { + OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND; + continue; + } + + /* reduce for support function calls */ + if (ic->supportRtn || ic->op == '+' || ic->op == '-') + packRegsForSupport (ic, ebp); + + /* 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 == MODEL_SMALL) { + if (0 && options.stackAuto) { + /* we should check here if acc will be clobbered for stack + offset calculations */ + } else { + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + } + } + + /* if pointer set & left has a size more than + one and right is not in far space */ + if (POINTER_SET (ic) && + !isOperandInFarSpace (IC_RIGHT (ic)) && + !OP_SYMBOL (IC_RESULT (ic))->remat && + !IS_OP_RUONLY (IC_RIGHT (ic)) && + getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1) + + packRegsForOneuse (ic, IC_RESULT (ic), ebp); + + /* if pointer get */ + if (POINTER_GET (ic) && + !isOperandInFarSpace (IC_RESULT (ic)) && + !OP_SYMBOL (IC_LEFT (ic))->remat && + !IS_OP_RUONLY (IC_RESULT (ic)) && + getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1) + + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + + + /* if this is cast for intergral promotion then + check if only use of the definition of the + operand being casted/ if yes then replace + the result of that arithmetic operation with + this result and get rid of the cast */ + if (ic->op == CAST) + { + sym_link *fromType = operandType (IC_RIGHT (ic)); + sym_link *toType = operandType (IC_LEFT (ic)); + + if (IS_INTEGRAL (fromType) && IS_INTEGRAL (toType) && + getSize (fromType) != getSize (toType) && + SPEC_USIGN (fromType) == SPEC_USIGN (toType)) + { + + iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp); + if (dic) + { + if (IS_ARITHMETIC_OP (dic)) + { + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } + else + OP_SYMBOL (IC_RIGHT (ic))->ruonly = 0; + } + } + else + { + + /* if the type from and type to are the same + then if this is the only use then packit */ + if (compareType (operandType (IC_RIGHT (ic)), + operandType (IC_LEFT (ic))) == 1) + { + iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp); + if (dic) + { + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } + } + } + } + + /* pack for PUSH + iTempNN := (some variable in farspace) V1 + push iTempNN ; + ------------- + push V1 + */ + if (ic->op == IPUSH) + { + packForPush (ic, ebp); + } + } +} + +/*-----------------------------------------------------------------*/ +/* assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void +xa51_assignRegisters (eBBlock ** ebbs, int count) +{ + iCode *ic; + int i; + + setToNull ((void *) &_G.funcrUsed); + setToNull ((void *) &_G.totRegAssigned); + _G.stackExtend = _G.dataExtend = 0; + + /* change assignments this will remove some + live ranges reducing some register pressure */ + for (i = 0; i < count; i++) + packRegisters (ebbs[i]); + + if (options.dump_pack) + dumpEbbsToFileExt (DUMP_PACK, ebbs, count); + + /* first determine for each live range the number of + registers & the type of registers required for each */ + regTypeNum (*ebbs); + + /* and serially allocate registers */ + serialRegAssign (ebbs, count); + + freeAllRegs (); + + /* if stack was extended then tell the user */ + if (_G.stackExtend) + { +/* werror(W_TOOMANY_SPILS,"stack", */ +/* _G.stackExtend,currFunc->name,""); */ + _G.stackExtend = 0; + } + + if (_G.dataExtend) + { +/* werror(W_TOOMANY_SPILS,"data space", */ +/* _G.dataExtend,currFunc->name,""); */ + _G.dataExtend = 0; + } + + /* after that create the register mask + for each of the instruction */ + createRegMask (ebbs, count); + + /* redo that offsets for stacked automatic variables */ + redoStackOffsets (); + + if (options.dump_rassgn) + { + dumpEbbsToFileExt (DUMP_RASSGN, ebbs, count); + dumpLiveRanges (DUMP_LRANGE, liveRanges); + } + + /* do the overlaysegment stuff SDCCmem.c */ + doOverlays (ebbs, count); + + /* now get back the chain */ + ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); + + genXA51Code (ic); + + /* free up any _G.stackSpil locations allocated */ + applyToSet (_G.stackSpil, deallocStackSpil); + _G.slocNum = 0; + setToNull ((void **) &_G.stackSpil); + setToNull ((void **) &_G.spiltSet); + /* mark all registers as free */ + freeAllRegs (); + + return; +} diff --git a/src/xa51/ralloc.h b/src/xa51/ralloc.h new file mode 100755 index 00000000..bddd52b3 --- /dev/null +++ b/src/xa51/ralloc.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +#define ubyte unsigned char +#define byte ubyte +#define sbyte signed char +#define uword unsigned char +#define word uword +#define sword signed char +#define udword unsigned int +#define dword udword +#define sdword signed int + +#define REG_PTR 0x01 // pointer register +#define REG_GPR 0x02 // general purpose register +#define REG_CND 0x04 // condition (bit) register +#define REG_SCR 0x40 // scratch register +#define REG_STK 0x80 // stack pointer register + +typedef struct regs { + ubyte rIdx; // a unique # for this one + ubyte size; // size of register (0,1,2,4) + ubyte type; // pointer, general purpose, condition (bit) + char *name; + udword regMask; + uword offset; + bool isFree; + symbol *sym; +} regs; + +#if 0 +/* definition for the registers */ +typedef struct regs + { + short type; /* can have value REG_CND, REG_8BITS, + REG_16BITS or REG_32BITS */ + short rIdx; /* index into register table */ + short otype; + char *name; /* name */ + char *dname; /* name when direct access needed */ + char *base; /* base address */ + short offset; /* offset from the base */ + unsigned isFree:1; /* is currently unassigned */ + } +regs; +#endif + +extern regs regsXA51[]; +extern udword xa51RegsInUse; + +regs *xa51_regWithIdx (int); + +bitVect *xa51_rUmaskForOp (operand * op); + +#endif diff --git a/src/xa51/ralloc.o b/src/xa51/ralloc.o new file mode 100644 index 00000000..6e686e8a Binary files /dev/null and b/src/xa51/ralloc.o differ