--- /dev/null
+/*-------------------------------------------------------------------------
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "SDCCglobl.h"
+#include "newalloc.h"
+
+#ifdef HAVE_SYS_ISA_DEFS_H
+#include <sys/isa_defs.h>
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#else
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#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 + <sizeof *op> */
+ if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
+ isOperandEqual(IC_RESULT(lic),op) &&
+ isOperandLiteral(IC_RIGHT(lic)) &&
+ operandLitValue(IC_RIGHT(lic)) == isize) {
+ return lic;
+ }
+ /* if the operand used or deffed */
+ if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
+ return NULL;
+ }
+ /* if GOTO or IFX */
+ if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
+ lic = lic->next;
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAndOp - for && operation */
+/*-----------------------------------------------------------------*/
+static void genAndOp (iCode * ic) {
+ 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;
+}
--- /dev/null
+/*------------------------------------------------------------------------
+
+ 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; i<xa51_nRegs; i++) {
+ if (regsXA51[i].regMask==mask) {
+ return ®sXA51[i];
+ }
+ }
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* checkRegsMask - check the consistancy of the regMask redundancy */
+/*-----------------------------------------------------------------*/
+
+void checkRegMask(char *f) { // for debugging purposes only
+ int i;
+ udword regMask=0;
+
+ for (i=0; i<xa51_nRegs; i++) {
+ if (!regsXA51[i].isFree) {
+ regMask |= regsXA51[i].regMask;
+ }
+ }
+
+ if (regMask != xa51RegsInUse) {
+ fprintf (stderr, "error(%s): regMask inconsistent 0x%08x != 0x%08x\n",
+ f, regMask, xa51RegsInUse);
+ regMask=regMask^xa51RegsInUse;
+ fprintf (stderr, "%s used by %s\n",
+ xa51_regWithMask(regMask)->name,
+ 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; i<xa51_nRegs; i++) {
+ if (regsXA51[i].size==2 && regsXA51[i].type==type) {
+ udword mask=regsXA51[i].regMask & ~xa51RegsInUse;
+ if (mask && mask!=regsXA51[i].regMask) {
+ regs *reg=xa51_regWithMask(mask);
+ // found a gap
+ sym->regs[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; i<xa51_nRegs; i++) {
+ if (regsXA51[i].size==size &&
+ regsXA51[i].type==type &&
+ (regsXA51[i].regMask & xa51RegsInUse)==0) {
+ xa51RegsInUse |= regsXA51[i].regMask;
+ regsXA51[i].isFree = 0; // redundant
+ regsXA51[i].sym = sym;
+ if (!silent) {
+ fprintf (stderr, "%s\n", regsXA51[i].name);
+ }
+ sym->regs[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; i<xa51_nRegs; i++) {
+ if (!regsXA51[i].isFree) {
+ strcat (regsFreed, regsXA51[i].name);
+ strcat (regsFreed, " ");
+ regsXA51[i].isFree=1;
+ regsXA51[i].sym=NULL;
+ nfr++;
+ }
+ }
+ xa51RegsInUse=0;
+ if (nfr) {
+ fprintf (stderr, "freeAllRegisters: %d regs freed (%s)\n", nfr, regsFreed);
+ exit (1);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* allDefsOutOfRange - all definitions are out of a range */
+/*-----------------------------------------------------------------*/
+static bool allDefsOutOfRange (bitVect * defs, int fseq, int toseq) {
+ int i;
+
+ if (!defs)
+ return TRUE;
+
+ for (i = 0; i < defs->size; i++)
+ {
+ iCode *ic;
+
+ if (bitVectBitValue (defs, i) &&
+ (ic = hTabItemWithKey (iCodehTab, i)) &&
+ (ic->seq >= fseq && ic->seq <= toseq))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* computeSpillable - given a point find the spillable live ranges */
+/*-----------------------------------------------------------------*/
+static bitVect *computeSpillable (iCode * ic) {
+ bitVect *spillable;
+
+ /* spillable live ranges are those that are live at this
+ point . the following categories need to be subtracted
+ from this set.
+ a) - those that are already spilt
+ b) - if being used by this one
+ c) - defined by this one */
+
+ spillable = bitVectCopy (ic->rlive);
+ spillable =
+ bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */
+ spillable =
+ bitVectCplAnd (spillable, ic->uses); /* used in this one */
+ bitVectUnSetBit (spillable, ic->defKey); /* 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; i<sym->nRegs; 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;
+}