gbdk-releases/sdcc/src/pic/ralloc.c
2015-01-10 16:25:09 +01:00

3125 lines
84 KiB
C

/*------------------------------------------------------------------------
SDCCralloc.c - source file for register allocation. (8051) specific
Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
Added Pic Port T.scott Dattalo scott@dattalo.com (2000)
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 "pcode.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 genpic14Code (iCode *);
/* Global data */
static struct
{
bitVect *spiltSet;
set *stackSpil;
bitVect *regAssigned;
short blockSpil;
int slocNum;
bitVect *funcrUsed; /* registers used in a function */
int stackExtend;
int dataExtend;
}
_G;
/* Shared with gen.c */
int pic14_ptrRegReq; /* one byte pointer register required */
/* pic14 registers */
/* A nasty, awful, disgusting hack for register declarations */
#ifdef p16c84
regs regspic14[] =
{
{REG_GPR, PO_GPR_TEMP, 0x0C, "r0x0C", "r0x0C", 0x0C, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x0D, "r0x0D", "r0x0C", 0x0D, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x0E, "r0x0E", "r0x0C", 0x0E, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x0F, "r0x0F", "r0x0C", 0x0F, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x10, "r0x10", "r0x10", 0x10, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x11, "r0x11", "r0x11", 0x11, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x12, "r0x12", "r0x12", 0x12, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x13, "r0x13", "r0x13", 0x13, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x14, "r0x14", "r0x14", 0x14, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x15, "r0x15", "r0x15", 0x15, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x16, "r0x16", "r0x16", 0x16, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x17, "r0x17", "r0x17", 0x17, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x18, "r0x18", "r0x18", 0x18, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x19, "r0x19", "r0x19", 0x19, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1A, "r0x1A", "r0x1A", 0x1A, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1B, "r0x1B", "r0x1B", 0x1B, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1C, "r0x1C", "r0x1C", 0x1C, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1D, "r0x1D", "r0x1D", 0x1D, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1E, "r0x1E", "r0x1E", 0x1E, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x1F, "r0x1F", "r0x1F", 0x1F, 1, 0},
{REG_PTR, PO_FSR, 4, "FSR", "FSR", 4, 1, 0},
};
#else
regs regspic14[] =
{
{REG_GPR, PO_GPR_TEMP, 0x20, "r0x20", "r0x20", 0x20, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x21, "r0x21", "r0x21", 0x21, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x22, "r0x22", "r0x22", 0x22, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x23, "r0x23", "r0x23", 0x23, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x24, "r0x24", "r0x24", 0x24, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x25, "r0x25", "r0x25", 0x25, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x26, "r0x26", "r0x26", 0x26, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x27, "r0x27", "r0x27", 0x27, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x28, "r0x28", "r0x28", 0x28, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x29, "r0x29", "r0x29", 0x29, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2A, "r0x2A", "r0x2A", 0x2A, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2B, "r0x2B", "r0x2B", 0x2B, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2C, "r0x2C", "r0x2C", 0x2C, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2D, "r0x2D", "r0x2D", 0x2D, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2E, "r0x2E", "r0x2E", 0x2E, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x2F, "r0x2F", "r0x2F", 0x2F, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x30, "r0x30", "r0x30", 0x30, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x31, "r0x31", "r0x31", 0x31, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x32, "r0x32", "r0x32", 0x32, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x33, "r0x33", "r0x33", 0x33, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x34, "r0x34", "r0x34", 0x34, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x35, "r0x35", "r0x35", 0x35, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x36, "r0x36", "r0x36", 0x36, 1, 0},
{REG_GPR, PO_GPR_TEMP, 0x37, "r0x37", "r0x37", 0x37, 1, 0},
{REG_PTR, PO_FSR, 4, "FSR", "FSR", 4, 1, 0},
};
#endif
int pic14_nRegs = sizeof (regspic14) / sizeof (regs);
static void spillThis (symbol *);
static int debug = 1;
static FILE *debugF = NULL;
/*-----------------------------------------------------------------*/
/* debugLog - open a file for debugging information */
/*-----------------------------------------------------------------*/
//static void debugLog(char *inst,char *fmt, ...)
static void
debugLog (char *fmt,...)
{
static int append = 0; // First time through, open the file without append.
char buffer[256];
//char *bufferP=buffer;
va_list ap;
if (!debug || !srcFileName)
return;
if (!debugF)
{
/* create the file name */
strcpy (buffer, srcFileName);
strcat (buffer, ".d");
if (!(debugF = fopen (buffer, (append ? "a+" : "w"))))
{
werror (E_FILE_OPEN_ERR, buffer);
exit (1);
}
append = 1; // Next time debubLog is called, we'll append the debug info
}
va_start (ap, fmt);
vsprintf (buffer, fmt, ap);
fprintf (debugF, "%s", buffer);
/*
while (isspace(*bufferP)) bufferP++;
if (bufferP && *bufferP)
lineCurr = (lineCurr ?
connectLine(lineCurr,newLineNode(lb)) :
(lineHead = newLineNode(lb)));
lineCurr->isInline = _G.inLine;
lineCurr->isDebug = _G.debugLine;
*/
va_end (ap);
}
static void
debugNewLine (void)
{
if (debugF)
fputc ('\n', debugF);
}
/*-----------------------------------------------------------------*/
/* debugLogClose - closes the debug log file (if opened) */
/*-----------------------------------------------------------------*/
static void
debugLogClose (void)
{
if (debugF)
{
fclose (debugF);
debugF = NULL;
}
}
#define AOP(op) op->aop
static char *
debugAopGet (char *str, operand * op)
{
if (str)
debugLog (str);
printOperand (op, debugF);
debugNewLine ();
return NULL;
}
static char *
decodeOp (unsigned int op)
{
if (op < 128 && op > ' ')
{
buffer[0] = (op & 0xff);
buffer[1] = 0;
return buffer;
}
switch (op)
{
case IDENTIFIER:
return "IDENTIFIER";
case TYPE_NAME:
return "TYPE_NAME";
case CONSTANT:
return "CONSTANT";
case STRING_LITERAL:
return "STRING_LITERAL";
case SIZEOF:
return "SIZEOF";
case PTR_OP:
return "PTR_OP";
case INC_OP:
return "INC_OP";
case DEC_OP:
return "DEC_OP";
case LEFT_OP:
return "LEFT_OP";
case RIGHT_OP:
return "RIGHT_OP";
case LE_OP:
return "LE_OP";
case GE_OP:
return "GE_OP";
case EQ_OP:
return "EQ_OP";
case NE_OP:
return "NE_OP";
case AND_OP:
return "AND_OP";
case OR_OP:
return "OR_OP";
case MUL_ASSIGN:
return "MUL_ASSIGN";
case DIV_ASSIGN:
return "DIV_ASSIGN";
case MOD_ASSIGN:
return "MOD_ASSIGN";
case ADD_ASSIGN:
return "ADD_ASSIGN";
case SUB_ASSIGN:
return "SUB_ASSIGN";
case LEFT_ASSIGN:
return "LEFT_ASSIGN";
case RIGHT_ASSIGN:
return "RIGHT_ASSIGN";
case AND_ASSIGN:
return "AND_ASSIGN";
case XOR_ASSIGN:
return "XOR_ASSIGN";
case OR_ASSIGN:
return "OR_ASSIGN";
case TYPEDEF:
return "TYPEDEF";
case EXTERN:
return "EXTERN";
case STATIC:
return "STATIC";
case AUTO:
return "AUTO";
case REGISTER:
return "REGISTER";
case CODE:
return "CODE";
case EEPROM:
return "EEPROM";
case INTERRUPT:
return "INTERRUPT";
case SFR:
return "SFR";
case AT:
return "AT";
case SBIT:
return "SBIT";
case REENTRANT:
return "REENTRANT";
case USING:
return "USING";
case XDATA:
return "XDATA";
case DATA:
return "DATA";
case IDATA:
return "IDATA";
case PDATA:
return "PDATA";
case VAR_ARGS:
return "VAR_ARGS";
case CRITICAL:
return "CRITICAL";
case NONBANKED:
return "NONBANKED";
case BANKED:
return "BANKED";
case CHAR:
return "CHAR";
case SHORT:
return "SHORT";
case INT:
return "INT";
case LONG:
return "LONG";
case SIGNED:
return "SIGNED";
case UNSIGNED:
return "UNSIGNED";
case FLOAT:
return "FLOAT";
case DOUBLE:
return "DOUBLE";
case CONST:
return "CONST";
case VOLATILE:
return "VOLATILE";
case VOID:
return "VOID";
case BIT:
return "BIT";
case STRUCT:
return "STRUCT";
case UNION:
return "UNION";
case ENUM:
return "ENUM";
case ELIPSIS:
return "ELIPSIS";
case RANGE:
return "RANGE";
case FAR:
return "FAR";
case CASE:
return "CASE";
case DEFAULT:
return "DEFAULT";
case IF:
return "IF";
case ELSE:
return "ELSE";
case SWITCH:
return "SWITCH";
case WHILE:
return "WHILE";
case DO:
return "DO";
case FOR:
return "FOR";
case GOTO:
return "GOTO";
case CONTINUE:
return "CONTINUE";
case BREAK:
return "BREAK";
case RETURN:
return "RETURN";
case INLINEASM:
return "INLINEASM";
case IFX:
return "IFX";
case ADDRESS_OF:
return "ADDRESS_OF";
case GET_VALUE_AT_ADDRESS:
return "GET_VALUE_AT_ADDRESS";
case SPIL:
return "SPIL";
case UNSPIL:
return "UNSPIL";
case GETHBIT:
return "GETHBIT";
case BITWISEAND:
return "BITWISEAND";
case UNARYMINUS:
return "UNARYMINUS";
case IPUSH:
return "IPUSH";
case IPOP:
return "IPOP";
case PCALL:
return "PCALL";
case ENDFUNCTION:
return "ENDFUNCTION";
case JUMPTABLE:
return "JUMPTABLE";
case RRC:
return "RRC";
case RLC:
return "RLC";
case CAST:
return "CAST";
case CALL:
return "CALL";
case PARAM:
return "PARAM ";
case NULLOP:
return "NULLOP";
case BLOCK:
return "BLOCK";
case LABEL:
return "LABEL";
case RECEIVE:
return "RECEIVE";
case SEND:
return "SEND";
}
sprintf (buffer, "unkown op %d %c", op, op & 0xff);
return buffer;
}
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
static char *
debugLogRegType (short type)
{
switch (type)
{
case REG_GPR:
return "REG_GPR";
case REG_PTR:
return "REG_PTR";
case REG_CND:
return "REG_CND";
}
sprintf (buffer, "unkown reg type %d", type);
return buffer;
}
/*-----------------------------------------------------------------*/
/* allocReg - allocates register of given type */
/*-----------------------------------------------------------------*/
static regs *
allocReg (short type)
{
int i;
debugLog ("%s of type %s\n", __FUNCTION__, debugLogRegType (type));
for (i = 0; i < pic14_nRegs; i++)
{
/* if type is given as 0 then any
free register will do */
if (!type &&
regspic14[i].isFree)
{
regspic14[i].isFree = 0;
regspic14[i].wasUsed = 1;
if (currFunc)
currFunc->regsUsed =
bitVectSetBit (currFunc->regsUsed, i);
debugLog (" returning %s\n", regspic14[i].name);
return &regspic14[i];
}
/* other wise look for specific type
of register */
if (regspic14[i].isFree &&
regspic14[i].type == type)
{
regspic14[i].isFree = 0;
regspic14[i].wasUsed = 1;
if (currFunc)
currFunc->regsUsed =
bitVectSetBit (currFunc->regsUsed, i);
debugLog (" returning %s\n", regspic14[i].name);
return &regspic14[i];
}
}
return NULL;
}
/*-----------------------------------------------------------------*/
/* pic14_regWithIdx - returns pointer to register wit index number */
/*-----------------------------------------------------------------*/
regs *
pic14_regWithIdx (int idx)
{
int i;
debugLog ("%s - requesting index = 0x%x\n", __FUNCTION__,idx);
for (i = 0; i < pic14_nRegs; i++)
if (regspic14[i].rIdx == idx)
return &regspic14[i];
return &regspic14[0];
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"regWithIdx not found");
exit (1);
}
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
regs *
pic14_findFreeReg(void)
{
int i;
for (i = 0; i < pic14_nRegs; i++)
if (regspic14[i].isFree)
return &regspic14[i];
return NULL;
}
/*-----------------------------------------------------------------*/
/* freeReg - frees a register */
/*-----------------------------------------------------------------*/
static void
freeReg (regs * reg)
{
debugLog ("%s\n", __FUNCTION__);
reg->isFree = 1;
}
/*-----------------------------------------------------------------*/
/* nFreeRegs - returns number of free registers */
/*-----------------------------------------------------------------*/
static int
nFreeRegs (int type)
{
int i;
int nfr = 0;
debugLog ("%s\n", __FUNCTION__);
for (i = 0; i < pic14_nRegs; i++)
if (regspic14[i].isFree && regspic14[i].type == type)
nfr++;
return nfr;
}
/*-----------------------------------------------------------------*/
/* nfreeRegsType - free registers with type */
/*-----------------------------------------------------------------*/
static int
nfreeRegsType (int type)
{
int nfr;
debugLog ("%s\n", __FUNCTION__);
if (type == REG_PTR)
{
if ((nfr = nFreeRegs (type)) == 0)
return nFreeRegs (REG_GPR);
}
return nFreeRegs (type);
}
/*-----------------------------------------------------------------*/
/* allDefsOutOfRange - all definitions are out of a range */
/*-----------------------------------------------------------------*/
static bool
allDefsOutOfRange (bitVect * defs, int fseq, int toseq)
{
int i;
debugLog ("%s\n", __FUNCTION__);
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;
debugLog ("%s\n", __FUNCTION__);
/* spillable live ranges are those that are live at this
point . the following categories need to be subtracted
from this set.
a) - those that are already spilt
b) - if being used by this one
c) - defined by this one */
spillable = bitVectCopy (ic->rlive);
spillable =
bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */
spillable =
bitVectCplAnd (spillable, ic->uses); /* used in this one */
bitVectUnSetBit (spillable, ic->defKey);
spillable = bitVectIntersect (spillable, _G.regAssigned);
return spillable;
}
/*-----------------------------------------------------------------*/
/* noSpilLoc - return true if a variable has no spil location */
/*-----------------------------------------------------------------*/
static int
noSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic)
{
debugLog ("%s\n", __FUNCTION__);
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)
{
debugLog ("%s\n", __FUNCTION__);
return (sym->usl.spillLoc ? 1 : 0);
}
/*-----------------------------------------------------------------*/
/* directSpilLoc - will return 1 if the splilocation is in direct */
/*-----------------------------------------------------------------*/
static int
directSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic)
{
debugLog ("%s\n", __FUNCTION__);
if (sym->usl.spillLoc &&
(IN_DIRSPACE (SPEC_OCLS (sym->usl.spillLoc->etype))))
return 1;
else
return 0;
}
/*-----------------------------------------------------------------*/
/* hasSpilLocnoUptr - will return 1 if the symbol has spil location */
/* but is not used as a pointer */
/*-----------------------------------------------------------------*/
static int
hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic)
{
debugLog ("%s\n", __FUNCTION__);
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)
{
debugLog ("%s\n", __FUNCTION__);
return sym->remat;
}
/*-----------------------------------------------------------------*/
/* notUsedInBlock - not used in this block */
/*-----------------------------------------------------------------*/
static int
notUsedInBlock (symbol * sym, eBBlock * ebp, iCode * ic)
{
debugLog ("%s\n", __FUNCTION__);
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)
{
debugLog ("%s\n", __FUNCTION__);
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)
{
debugLog ("%s\n", __FUNCTION__);
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;
debugLog ("%s\n", __FUNCTION__);
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;
debugLog ("%s\n", __FUNCTION__);
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;
debugLog ("%s\n", __FUNCTION__);
for (sym = setFirstItem (itmpStack); sym;
sym = setNextItem (itmpStack))
{
if (sym->liveTo > fsym->liveFrom)
return 0;
}
return 1;
}
/*-----------------------------------------------------------------*/
/* isFree - will return 1 if the a free spil location is found */
/*-----------------------------------------------------------------*/
static
DEFSETFUNC (isFree)
{
symbol *sym = item;
V_ARG (symbol **, sloc);
V_ARG (symbol *, fsym);
debugLog ("%s\n", __FUNCTION__);
/* if already found */
if (*sloc)
return 0;
/* if it is free && and the itmp assigned to
this does not have any overlapping live ranges
with the one currently being assigned and
the size can be accomodated */
if (sym->isFree &&
noOverLap (sym->usl.itmpStack, fsym) &&
getSize (sym->type) >= getSize (fsym->type))
{
*sloc = sym;
return 1;
}
return 0;
}
/*-----------------------------------------------------------------*/
/* spillLRWithPtrReg :- will spil those live ranges which use PTR */
/*-----------------------------------------------------------------*/
static void
spillLRWithPtrReg (symbol * forSym)
{
symbol *lrsym;
regs *r0, *r1;
int k;
debugLog ("%s\n", __FUNCTION__);
if (!_G.regAssigned ||
bitVectIsZero (_G.regAssigned))
return;
r0 = pic14_regWithIdx (R0_IDX);
r1 = pic14_regWithIdx (R1_IDX);
/* for all live ranges */
for (lrsym = hTabFirstItem (liveRanges, &k); lrsym;
lrsym = hTabNextItem (liveRanges, &k))
{
int j;
/* if no registers assigned to it or
spilt */
/* if it does not overlap with this then
not need to spill it */
if (lrsym->isspilt || !lrsym->nRegs ||
(lrsym->liveTo < forSym->liveFrom))
continue;
/* go thru the registers : if it is either
r0 or r1 then spil it */
for (j = 0; j < lrsym->nRegs; j++)
if (lrsym->regs[j] == r0 ||
lrsym->regs[j] == r1)
{
spillThis (lrsym);
break;
}
}
}
/*-----------------------------------------------------------------*/
/* createStackSpil - create a location on the stack to spil */
/*-----------------------------------------------------------------*/
static symbol *
createStackSpil (symbol * sym)
{
symbol *sloc = NULL;
int useXstack, model, noOverlay;
char slocBuffer[30];
debugLog ("%s\n", __FUNCTION__);
/* 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, "kkkInternal error: slocBuffer overflowed: %s:%d\n",
__FILE__, __LINE__);
exit (1);
}
sloc = newiTemp (slocBuffer);
/* set the type to the spilling symbol */
sloc->type = copyLinkChain (sym->type);
sloc->etype = getSpec (sloc->type);
SPEC_SCLS (sloc->etype) = S_DATA;
SPEC_EXTR (sloc->etype) = 0;
/* we don't allow it to be allocated`
onto the external stack since : so we
temporarily turn it off ; we also
turn off memory model to prevent
the spil from going to the external storage
and turn off overlaying
*/
useXstack = options.useXstack;
model = options.model;
noOverlay = options.noOverlay;
options.noOverlay = 1;
options.model = options.useXstack = 0;
allocLocal (sloc);
options.useXstack = useXstack;
options.model = model;
options.noOverlay = noOverlay;
sloc->isref = 1; /* to prevent compiler warning */
/* if it is on the stack then update the stack */
if (IN_STACK (sloc->etype))
{
currFunc->stack += getSize (sloc->type);
_G.stackExtend += getSize (sloc->type);
}
else
_G.dataExtend += getSize (sloc->type);
/* add it to the _G.stackSpil set */
addSetHead (&_G.stackSpil, sloc);
sym->usl.spillLoc = sloc;
sym->stackSpil = 1;
/* add it to the set of itempStack set
of the spill location */
addSetHead (&sloc->usl.itmpStack, sym);
return sym;
}
/*-----------------------------------------------------------------*/
/* isSpiltOnStack - returns true if the spil location is on stack */
/*-----------------------------------------------------------------*/
static bool
isSpiltOnStack (symbol * sym)
{
sym_link *etype;
debugLog ("%s\n", __FUNCTION__);
if (!sym)
return FALSE;
if (!sym->isspilt)
return FALSE;
/* if (sym->_G.stackSpil) */
/* return TRUE; */
if (!sym->usl.spillLoc)
return FALSE;
etype = getSpec (sym->usl.spillLoc->type);
if (IN_STACK (etype))
return TRUE;
return FALSE;
}
/*-----------------------------------------------------------------*/
/* spillThis - spils a specific operand */
/*-----------------------------------------------------------------*/
static void
spillThis (symbol * sym)
{
int i;
debugLog ("%s : %s\n", __FUNCTION__, sym->rname);
/* if this is rematerializable or has a spillLocation
we are okay, else we need to create a spillLocation
for it */
if (!(sym->remat || sym->usl.spillLoc))
createStackSpil (sym);
/* mark it has spilt & put it in the spilt set */
sym->isspilt = 1;
_G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key);
bitVectUnSetBit (_G.regAssigned, sym->key);
for (i = 0; i < sym->nRegs; i++)
if (sym->regs[i])
{
freeReg (sym->regs[i]);
sym->regs[i] = NULL;
}
/* if spilt on stack then free up r0 & r1
if they could have been assigned to some
LIVE ranges */
if (!pic14_ptrRegReq && isSpiltOnStack (sym))
{
pic14_ptrRegReq++;
spillLRWithPtrReg (sym);
}
if (sym->usl.spillLoc && !sym->remat)
sym->usl.spillLoc->allocreq = 1;
return;
}
/*-----------------------------------------------------------------*/
/* selectSpil - select a iTemp to spil : rather a simple procedure */
/*-----------------------------------------------------------------*/
static symbol *
selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym)
{
bitVect *lrcs = NULL;
set *selectS;
symbol *sym;
debugLog ("%s\n", __FUNCTION__);
/* get the spillable live ranges */
lrcs = computeSpillable (ic);
/* get all live ranges that are rematerizable */
if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic)))
{
/* return the least used of these */
return leastUsedLR (selectS);
}
/* get live ranges with spillLocations in direct space */
if ((selectS = liveRangesWith (lrcs, directSpilLoc, ebp, ic)))
{
sym = leastUsedLR (selectS);
strcpy (sym->rname, (sym->usl.spillLoc->rname[0] ?
sym->usl.spillLoc->rname :
sym->usl.spillLoc->name));
sym->spildir = 1;
/* mark it as allocation required */
sym->usl.spillLoc->allocreq = 1;
return sym;
}
/* if the symbol is local to the block then */
if (forSym->liveTo < ebp->lSeq)
{
/* check if there are any live ranges allocated
to registers that are not used in this block */
if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInBlock, ebp, ic)))
{
sym = leastUsedLR (selectS);
/* if this is not rematerializable */
if (!sym->remat)
{
_G.blockSpil++;
sym->blockSpil = 1;
}
return sym;
}
/* check if there are any live ranges that not
used in the remainder of the block */
if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInRemaining, ebp, ic)))
{
sym = leastUsedLR (selectS);
if (!sym->remat)
{
sym->remainSpil = 1;
_G.blockSpil++;
}
return sym;
}
}
/* find live ranges with spillocation && not used as pointers */
if ((selectS = liveRangesWith (lrcs, hasSpilLocnoUptr, ebp, ic)))
{
sym = leastUsedLR (selectS);
/* mark this as allocation required */
sym->usl.spillLoc->allocreq = 1;
return sym;
}
/* find live ranges with spillocation */
if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic)))
{
sym = leastUsedLR (selectS);
sym->usl.spillLoc->allocreq = 1;
return sym;
}
/* couldn't find then we need to create a spil
location on the stack , for which one? the least
used ofcourse */
if ((selectS = liveRangesWith (lrcs, noSpilLoc, ebp, ic)))
{
/* return a created spil location */
sym = createStackSpil (leastUsedLR (selectS));
sym->usl.spillLoc->allocreq = 1;
return sym;
}
/* this is an extreme situation we will spill
this one : happens very rarely but it does happen */
spillThis (forSym);
return forSym;
}
/*-----------------------------------------------------------------*/
/* spilSomething - spil some variable & mark registers as free */
/*-----------------------------------------------------------------*/
static bool
spilSomething (iCode * ic, eBBlock * ebp, symbol * forSym)
{
symbol *ssym;
int i;
debugLog ("%s\n", __FUNCTION__);
/* get something we can spil */
ssym = selectSpil (ic, ebp, forSym);
/* mark it as spilt */
ssym->isspilt = 1;
_G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key);
/* mark it as not register assigned &
take it away from the set */
bitVectUnSetBit (_G.regAssigned, ssym->key);
/* mark the registers as free */
for (i = 0; i < ssym->nRegs; i++)
if (ssym->regs[i])
freeReg (ssym->regs[i]);
/* if spilt on stack then free up r0 & r1
if they could have been assigned to as gprs */
if (!pic14_ptrRegReq && isSpiltOnStack (ssym))
{
pic14_ptrRegReq++;
spillLRWithPtrReg (ssym);
}
/* if this was a block level spil then insert push & pop
at the start & end of block respectively */
if (ssym->blockSpil)
{
iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL);
/* add push to the start of the block */
addiCodeToeBBlock (ebp, nic, (ebp->sch->op == LABEL ?
ebp->sch->next : ebp->sch));
nic = newiCode (IPOP, operandFromSymbol (ssym), NULL);
/* add pop to the end of the block */
addiCodeToeBBlock (ebp, nic, NULL);
}
/* if spilt because not used in the remainder of the
block then add a push before this instruction and
a pop at the end of the block */
if (ssym->remainSpil)
{
iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL);
/* add push just before this instruction */
addiCodeToeBBlock (ebp, nic, ic);
nic = newiCode (IPOP, operandFromSymbol (ssym), NULL);
/* add pop to the end of the block */
addiCodeToeBBlock (ebp, nic, NULL);
}
if (ssym == forSym)
return FALSE;
else
return TRUE;
}
/*-----------------------------------------------------------------*/
/* getRegPtr - will try for PTR if not a GPR type if not spil */
/*-----------------------------------------------------------------*/
static regs *
getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym)
{
regs *reg;
debugLog ("%s\n", __FUNCTION__);
tryAgain:
/* try for a ptr type */
if ((reg = allocReg (REG_PTR)))
return reg;
/* try for gpr type */
if ((reg = allocReg (REG_GPR)))
return reg;
/* we have to spil */
if (!spilSomething (ic, ebp, sym))
return NULL;
/* this looks like an infinite loop but
in really selectSpil will abort */
goto tryAgain;
}
/*-----------------------------------------------------------------*/
/* getRegGpr - will try for GPR if not spil */
/*-----------------------------------------------------------------*/
static regs *
getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym)
{
regs *reg;
debugLog ("%s\n", __FUNCTION__);
tryAgain:
/* try for gpr type */
if ((reg = allocReg (REG_GPR)))
return reg;
if (!pic14_ptrRegReq)
if ((reg = allocReg (REG_PTR)))
return reg;
/* we have to spil */
if (!spilSomething (ic, ebp, sym))
return NULL;
/* this looks like an infinite loop but
in really selectSpil will abort */
goto tryAgain;
}
/*-----------------------------------------------------------------*/
/* symHasReg - symbol has a given register */
/*-----------------------------------------------------------------*/
static bool
symHasReg (symbol * sym, regs * reg)
{
int i;
debugLog ("%s\n", __FUNCTION__);
for (i = 0; i < sym->nRegs; i++)
if (sym->regs[i] == reg)
return TRUE;
return FALSE;
}
/*-----------------------------------------------------------------*/
/* deassignLRs - check the live to and if they have registers & are */
/* not spilt then free up the registers */
/*-----------------------------------------------------------------*/
static void
deassignLRs (iCode * ic, eBBlock * ebp)
{
symbol *sym;
int k;
symbol *result;
debugLog ("%s\n", __FUNCTION__);
for (sym = hTabFirstItem (liveRanges, &k); sym;
sym = hTabNextItem (liveRanges, &k))
{
symbol *psym = NULL;
/* if it does not end here */
if (sym->liveTo > ic->seq)
continue;
/* if it was spilt on stack then we can
mark the stack spil location as free */
if (sym->isspilt)
{
if (sym->stackSpil)
{
sym->usl.spillLoc->isFree = 1;
sym->stackSpil = 0;
}
continue;
}
if (!bitVectBitValue (_G.regAssigned, sym->key))
continue;
/* special case check if this is an IFX &
the privious one was a pop and the
previous one was not spilt then keep track
of the symbol */
if (ic->op == IFX && ic->prev &&
ic->prev->op == IPOP &&
!ic->prev->parmPush &&
!OP_SYMBOL (IC_LEFT (ic->prev))->isspilt)
psym = OP_SYMBOL (IC_LEFT (ic->prev));
if (sym->nRegs)
{
int i = 0;
bitVectUnSetBit (_G.regAssigned, sym->key);
/* if the result of this one needs registers
and does not have it then assign it right
away */
if (IC_RESULT (ic) &&
!(SKIP_IC2 (ic) || /* not a special icode */
ic->op == JUMPTABLE ||
ic->op == IFX ||
ic->op == IPUSH ||
ic->op == IPOP ||
ic->op == RETURN ||
POINTER_SET (ic)) &&
(result = OP_SYMBOL (IC_RESULT (ic))) && /* has a result */
result->liveTo > ic->seq && /* and will live beyond this */
result->liveTo <= ebp->lSeq && /* does not go beyond this block */
result->regType == sym->regType && /* same register types */
result->nRegs && /* which needs registers */
!result->isspilt && /* and does not already have them */
!result->remat &&
!bitVectBitValue (_G.regAssigned, result->key) &&
/* the number of free regs + number of regs in this LR
can accomodate the what result Needs */
((nfreeRegsType (result->regType) +
sym->nRegs) >= result->nRegs)
)
{
for (i = 0; i < max (sym->nRegs, result->nRegs); i++)
if (i < sym->nRegs)
result->regs[i] = sym->regs[i];
else
result->regs[i] = getRegGpr (ic, ebp, result);
_G.regAssigned = bitVectSetBit (_G.regAssigned, result->key);
}
/* free the remaining */
for (; i < sym->nRegs; i++)
{
if (psym)
{
if (!symHasReg (psym, sym->regs[i]))
freeReg (sym->regs[i]);
}
else
freeReg (sym->regs[i]);
}
}
}
}
/*-----------------------------------------------------------------*/
/* reassignLR - reassign this to registers */
/*-----------------------------------------------------------------*/
static void
reassignLR (operand * op)
{
symbol *sym = OP_SYMBOL (op);
int i;
debugLog ("%s\n", __FUNCTION__);
/* not spilt any more */
sym->isspilt = sym->blockSpil = sym->remainSpil = 0;
bitVectUnSetBit (_G.spiltSet, sym->key);
_G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
_G.blockSpil--;
for (i = 0; i < sym->nRegs; i++)
sym->regs[i]->isFree = 0;
}
/*-----------------------------------------------------------------*/
/* willCauseSpill - determines if allocating will cause a spill */
/*-----------------------------------------------------------------*/
static int
willCauseSpill (int nr, int rt)
{
debugLog ("%s\n", __FUNCTION__);
/* first check if there are any avlb registers
of te type required */
if (rt == REG_PTR)
{
/* special case for pointer type
if pointer type not avlb then
check for type gpr */
if (nFreeRegs (rt) >= nr)
return 0;
if (nFreeRegs (REG_GPR) >= nr)
return 0;
}
else
{
if (pic14_ptrRegReq)
{
if (nFreeRegs (rt) >= nr)
return 0;
}
else
{
if (nFreeRegs (REG_PTR) +
nFreeRegs (REG_GPR) >= nr)
return 0;
}
}
debugLog (" ... yep it will (cause a spill)\n");
/* it will cause a spil */
return 1;
}
/*-----------------------------------------------------------------*/
/* positionRegs - the allocator can allocate same registers to res- */
/* ult and operand, if this happens make sure they are in the same */
/* position as the operand otherwise chaos results */
/*-----------------------------------------------------------------*/
static void
positionRegs (symbol * result, symbol * opsym, int lineno)
{
int count = min (result->nRegs, opsym->nRegs);
int i, j = 0, shared = 0;
debugLog ("%s\n", __FUNCTION__);
/* if the result has been spilt then cannot share */
if (opsym->isspilt)
return;
again:
shared = 0;
/* first make sure that they actually share */
for (i = 0; i < count; i++)
{
for (j = 0; j < count; j++)
{
if (result->regs[i] == opsym->regs[j] && i != j)
{
shared = 1;
goto xchgPositions;
}
}
}
xchgPositions:
if (shared)
{
regs *tmp = result->regs[i];
result->regs[i] = result->regs[j];
result->regs[j] = tmp;
goto again;
}
}
/*-----------------------------------------------------------------*/
/* serialRegAssign - serially allocate registers to the variables */
/*-----------------------------------------------------------------*/
static void
serialRegAssign (eBBlock ** ebbs, int count)
{
int i;
debugLog ("%s\n", __FUNCTION__);
/* 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)
{
debugLog (" op: %s\n", decodeOp (ic->op));
/* if this is an ipop that means some live
range will have to be assigned again */
if (ic->op == IPOP)
reassignLR (IC_LEFT (ic));
/* if result is present && is a true symbol */
if (IC_RESULT (ic) && ic->op != IFX &&
IS_TRUE_SYMOP (IC_RESULT (ic)))
OP_SYMBOL (IC_RESULT (ic))->allocreq = 1;
/* take away registers from live
ranges that end at this instruction */
deassignLRs (ic, ebbs[i]);
/* some don't need registers */
if (SKIP_IC2 (ic) ||
ic->op == JUMPTABLE ||
ic->op == IFX ||
ic->op == IPUSH ||
ic->op == IPOP ||
(IC_RESULT (ic) && POINTER_SET (ic)))
continue;
/* now we need to allocate registers
only for the result */
if (IC_RESULT (ic))
{
symbol *sym = OP_SYMBOL (IC_RESULT (ic));
bitVect *spillable;
int willCS;
int j;
int ptrRegSet = 0;
/* if it does not need or is spilt
or is already assigned to registers
or will not live beyond this instructions */
if (!sym->nRegs ||
sym->isspilt ||
bitVectBitValue (_G.regAssigned, sym->key) ||
sym->liveTo <= ic->seq)
continue;
/* if some liverange has been spilt at the block level
and this one live beyond this block then spil this
to be safe */
if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq)
{
spillThis (sym);
continue;
}
/* if trying to allocate this will cause
a spill and there is nothing to spill
or this one is rematerializable then
spill this one */
willCS = willCauseSpill (sym->nRegs, sym->regType);
spillable = computeSpillable (ic);
if (sym->remat ||
(willCS && bitVectIsZero (spillable)))
{
spillThis (sym);
continue;
}
/* if it has a spillocation & is used less than
all other live ranges then spill this */
if (willCS) {
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)) {
spillThis (sym);
continue;
}
}
}
if (ic->op == RECEIVE)
debugLog ("When I get clever, I'll optimize the receive logic\n");
/* if we need ptr regs for the right side
then mark it */
if (POINTER_GET (ic) && getSize (OP_SYMBOL (IC_LEFT (ic))->type)
<= (unsigned) PTRSIZE)
{
pic14_ptrRegReq++;
ptrRegSet = 1;
}
/* else we assign registers to it */
_G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key);
debugLog (" %d - \n", __LINE__);
if(debugF)
bitVectDebugOn(_G.regAssigned, debugF);
for (j = 0; j < sym->nRegs; j++)
{
if (sym->regType == REG_PTR)
sym->regs[j] = getRegPtr (ic, ebbs[i], sym);
else
sym->regs[j] = getRegGpr (ic, ebbs[i], sym);
/* if the allocation falied which means
this was spilt then break */
if (!sym->regs[j])
break;
}
debugLog (" %d - \n", __LINE__);
/* if it shares registers with operands make sure
that they are in the same position */
if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) &&
OP_SYMBOL (IC_LEFT (ic))->nRegs && ic->op != '=')
positionRegs (OP_SYMBOL (IC_RESULT (ic)),
OP_SYMBOL (IC_LEFT (ic)), ic->lineno);
/* do the same for the right operand */
if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) &&
OP_SYMBOL (IC_RIGHT (ic))->nRegs && ic->op != '=')
positionRegs (OP_SYMBOL (IC_RESULT (ic)),
OP_SYMBOL (IC_RIGHT (ic)), ic->lineno);
debugLog (" %d - \n", __LINE__);
if (ptrRegSet)
{
debugLog (" %d - \n", __LINE__);
pic14_ptrRegReq--;
ptrRegSet = 0;
}
}
}
}
}
/*-----------------------------------------------------------------*/
/* rUmaskForOp :- returns register mask for an operand */
/*-----------------------------------------------------------------*/
static bitVect *
rUmaskForOp (operand * op)
{
bitVect *rumask;
symbol *sym;
int j;
debugLog ("%s\n", __FUNCTION__);
/* only temporaries are assigned registers */
if (!IS_ITEMP (op))
return NULL;
sym = OP_SYMBOL (op);
/* if spilt or no registers assigned to it
then nothing */
if (sym->isspilt || !sym->nRegs)
return NULL;
rumask = newBitVect (pic14_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 (pic14_nRegs);
debugLog ("%s\n", __FUNCTION__);
/* do the special cases first */
if (ic->op == IFX)
{
rmask = bitVectUnion (rmask,
rUmaskForOp (IC_COND (ic)));
goto ret;
}
/* for the jumptable */
if (ic->op == JUMPTABLE)
{
rmask = bitVectUnion (rmask,
rUmaskForOp (IC_JTCOND (ic)));
goto ret;
}
/* of all other cases */
if (IC_LEFT (ic))
rmask = bitVectUnion (rmask,
rUmaskForOp (IC_LEFT (ic)));
if (IC_RIGHT (ic))
rmask = bitVectUnion (rmask,
rUmaskForOp (IC_RIGHT (ic)));
if (IC_RESULT (ic))
rmask = bitVectUnion (rmask,
rUmaskForOp (IC_RESULT (ic)));
ret:
return rmask;
}
/*-----------------------------------------------------------------*/
/* createRegMask - for each instruction will determine the regsUsed */
/*-----------------------------------------------------------------*/
static void
createRegMask (eBBlock ** ebbs, int count)
{
int i;
debugLog ("%s\n", __FUNCTION__);
/* 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 (pic14_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;
debugLog ("%s\n", __FUNCTION__);
while (1)
{
printf ("%s\n", s);
/* if plus or minus print the right hand side */
/*
if (ic->op == '+' || ic->op == '-') {
sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
ic->op );
s += strlen(s);
ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
continue ;
}
*/
if (ic->op == '+' || ic->op == '-')
{
iCode *ric = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
sprintf (s, "(%s %c 0x%04x)",
OP_SYMBOL (IC_LEFT (ric))->rname,
ic->op,
(int) operandLitValue (IC_RIGHT (ic)));
//s += strlen(s);
//ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
//continue ;
return buffer;
}
/* we reached the end */
sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
break;
}
printf ("%s\n", buffer);
return buffer;
}
/*-----------------------------------------------------------------*/
/* regTypeNum - computes the type & number of registers required */
/*-----------------------------------------------------------------*/
static void
regTypeNum ()
{
symbol *sym;
int k;
iCode *ic;
debugLog ("%s\n", __FUNCTION__);
/* for each live range do */
for (sym = hTabFirstItem (liveRanges, &k); sym;
sym = hTabNextItem (liveRanges, &k)) {
debugLog (" %d - %s\n", __LINE__, sym->rname);
/* 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) {
debugLog (" %d - itemp register\n", __LINE__);
/* if the type is marked as a conditional */
if (sym->regType == REG_CND)
continue;
/* if used in return only then we don't
need registers */
if (sym->ruonly || sym->accuse) {
if (IS_AGGREGATE (sym->type) || sym->isptr)
sym->type = aggrToPtr (sym->type, FALSE);
debugLog (" %d - no reg needed - used as a return\n", __LINE__);
continue;
}
/* if the symbol has only one definition &
that definition is a get_pointer and the
pointer we are getting is rematerializable and
in "data" space */
if (bitVectnBitsOn (sym->defs) == 1 &&
(ic = hTabItemWithKey (iCodehTab,
bitVectFirstBit (sym->defs))) &&
POINTER_GET (ic) &&
!sym->noSpilLoc &&
!IS_BITVAR (sym->etype)) {
debugLog (" %d - \n", __LINE__);
/* if remat in data space */
if (OP_SYMBOL (IC_LEFT (ic))->remat &&
DCL_TYPE (aggrToPtr (sym->type, FALSE)) == POINTER) {
/* create a psuedo symbol & force a spil */
symbol *psym = newSymbol (rematStr (OP_SYMBOL (IC_LEFT (ic))), 1);
psym->type = sym->type;
psym->etype = sym->etype;
strcpy (psym->rname, psym->name);
sym->isspilt = 1;
sym->usl.spillLoc = psym;
continue;
}
/* if in data space or idata space then try to
allocate pointer register */
}
/* if not then we require registers */
sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ?
getSize (sym->type = aggrToPtr (sym->type, FALSE)) :
getSize (sym->type));
if (sym->nRegs > 4) {
fprintf (stderr, "allocated more than 4 or 0 registers for type ");
printTypeChain (sym->type, stderr);
fprintf (stderr, "\n");
}
/* determine the type of register required */
if (sym->nRegs == 1 &&
IS_PTR (sym->type) &&
sym->uptr)
sym->regType = REG_PTR;
else
sym->regType = REG_GPR;
debugLog (" reg name %s, reg type %s\n", sym->rname, debugLogRegType (sym->regType));
}
else
/* for the first run we don't provide */
/* registers for true symbols we will */
/* see how things go */
sym->nRegs = 0;
}
}
/*-----------------------------------------------------------------*/
/* freeAllRegs - mark all registers as free */
/*-----------------------------------------------------------------*/
void
pic14_freeAllRegs ()
{
int i;
debugLog ("%s\n", __FUNCTION__);
for (i = 0; i < pic14_nRegs; i++)
regspic14[i].isFree = 1;
}
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
void
pic14_deallocateAllRegs ()
{
int i;
debugLog ("%s\n", __FUNCTION__);
for (i = 0; i < pic14_nRegs; i++) {
regspic14[i].isFree = 1;
regspic14[i].wasUsed = 0;
}
}
/*-----------------------------------------------------------------*/
/* deallocStackSpil - this will set the stack pointer back */
/*-----------------------------------------------------------------*/
static
DEFSETFUNC (deallocStackSpil)
{
symbol *sym = item;
debugLog ("%s\n", __FUNCTION__);
deallocLocal (sym);
return 0;
}
/*-----------------------------------------------------------------*/
/* farSpacePackable - returns the packable icode for far variables */
/*-----------------------------------------------------------------*/
static iCode *
farSpacePackable (iCode * ic)
{
iCode *dic;
debugLog ("%s\n", __FUNCTION__);
/* go thru till we find a definition for the
symbol on the right */
for (dic = ic->prev; dic; dic = dic->prev)
{
/* if the definition is a call then no */
if ((dic->op == CALL || dic->op == PCALL) &&
IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
{
return NULL;
}
/* if shift by unknown amount then not */
if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) &&
IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
return NULL;
/* if pointer get and size > 1 */
if (POINTER_GET (dic) &&
getSize (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)) > 1)
return NULL;
if (POINTER_SET (dic) &&
getSize (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)) > 1)
return NULL;
/* if any three is a true symbol in far space */
if (IC_RESULT (dic) &&
IS_TRUE_SYMOP (IC_RESULT (dic)) &&
isOperandInFarSpace (IC_RESULT (dic)))
return NULL;
if (IC_RIGHT (dic) &&
IS_TRUE_SYMOP (IC_RIGHT (dic)) &&
isOperandInFarSpace (IC_RIGHT (dic)) &&
!isOperandEqual (IC_RIGHT (dic), IC_RESULT (ic)))
return NULL;
if (IC_LEFT (dic) &&
IS_TRUE_SYMOP (IC_LEFT (dic)) &&
isOperandInFarSpace (IC_LEFT (dic)) &&
!isOperandEqual (IC_LEFT (dic), IC_RESULT (ic)))
return NULL;
if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (dic)))
{
if ((dic->op == LEFT_OP ||
dic->op == RIGHT_OP ||
dic->op == '-') &&
IS_OP_LITERAL (IC_RIGHT (dic)))
return NULL;
else
return dic;
}
}
return NULL;
}
/*-----------------------------------------------------------------*/
/* packRegsForAssign - register reduction for assignment */
/*-----------------------------------------------------------------*/
static int
packRegsForAssign (iCode * ic, eBBlock * ebp)
{
iCode *dic, *sic;
debugLog ("%s\n", __FUNCTION__);
debugAopGet (" result:", IC_RESULT (ic));
debugAopGet (" left:", IC_LEFT (ic));
debugAopGet (" right:", IC_RIGHT (ic));
if (!IS_ITEMP (IC_RIGHT (ic)) ||
OP_SYMBOL (IC_RIGHT (ic))->isind ||
OP_LIVETO (IC_RIGHT (ic)) > ic->seq)
{
debugLog (" %d - not packing - right side fails \n", __LINE__);
return 0;
}
/* if the true symbol is defined in far space or on stack
then we should not since this will increase register pressure */
if (isOperandInFarSpace (IC_RESULT (ic)))
{
if ((dic = farSpacePackable (ic)))
goto pack;
else
return 0;
}
/* find the definition of iTempNN scanning backwards if we find a
a use of the true symbol before we find the definition then
we cannot pack */
for (dic = ic->prev; dic; dic = dic->prev)
{
/* if there is a function call and this is
a parameter & not my parameter then don't pack it */
if ((dic->op == CALL || dic->op == PCALL) &&
(OP_SYMBOL (IC_RESULT (ic))->_isparm &&
!OP_SYMBOL (IC_RESULT (ic))->ismyparm))
{
debugLog (" %d - \n", __LINE__);
dic = NULL;
break;
}
if (SKIP_IC2 (dic))
continue;
if (IS_TRUE_SYMOP (IC_RESULT (dic)) &&
IS_OP_VOLATILE (IC_RESULT (dic)))
{
debugLog (" %d - \n", __LINE__);
dic = NULL;
break;
}
if (IS_SYMOP (IC_RESULT (dic)) &&
IC_RESULT (dic)->key == IC_RIGHT (ic)->key)
{
debugLog (" %d - dic key == ic key -- pointer set=%c\n", __LINE__, ((POINTER_SET (dic)) ? 'Y' : 'N'));
if (POINTER_SET (dic))
dic = NULL;
break;
}
if (IS_SYMOP (IC_RIGHT (dic)) &&
(IC_RIGHT (dic)->key == IC_RESULT (ic)->key ||
IC_RIGHT (dic)->key == IC_RIGHT (ic)->key))
{
debugLog (" %d - \n", __LINE__);
dic = NULL;
break;
}
if (IS_SYMOP (IC_LEFT (dic)) &&
(IC_LEFT (dic)->key == IC_RESULT (ic)->key ||
IC_LEFT (dic)->key == IC_RIGHT (ic)->key))
{
debugLog (" %d - \n", __LINE__);
dic = NULL;
break;
}
if (POINTER_SET (dic) &&
IC_RESULT (dic)->key == IC_RESULT (ic)->key)
{
debugLog (" %d - \n", __LINE__);
dic = NULL;
break;
}
}
if (!dic)
return 0; /* did not find */
/* if the result is on stack or iaccess then it must be
the same atleast one of the operands */
if (OP_SYMBOL (IC_RESULT (ic))->onStack ||
OP_SYMBOL (IC_RESULT (ic))->iaccess)
{
/* the operation has only one symbol
operator then we can pack */
if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) ||
(IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic))))
goto pack;
if (!((IC_LEFT (dic) &&
IC_RESULT (ic)->key == IC_LEFT (dic)->key) ||
(IC_RIGHT (dic) &&
IC_RESULT (ic)->key == IC_RIGHT (dic)->key)))
return 0;
}
pack:
debugLog (" packing. removing %s\n", OP_SYMBOL (IC_RIGHT (ic))->rname);
/* found the definition */
/* replace the result with the result of */
/* this assignment and remove this assignment */
IC_RESULT (dic) = IC_RESULT (ic);
if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq)
{
OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq;
}
/* delete from liverange table also
delete from all the points inbetween and the new
one */
for (sic = dic; sic != ic; sic = sic->next)
{
bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key);
if (IS_ITEMP (IC_RESULT (dic)))
bitVectSetBit (sic->rlive, IC_RESULT (dic)->key);
}
remiCodeFromeBBlock (ebp, ic);
hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
return 1;
}
/*-----------------------------------------------------------------*/
/* findAssignToSym : scanning backwards looks for first assig found */
/*-----------------------------------------------------------------*/
static iCode *
findAssignToSym (operand * op, iCode * ic)
{
iCode *dic;
debugLog ("%s\n", __FUNCTION__);
for (dic = ic->prev; dic; dic = dic->prev)
{
/* if definition by assignment */
if (dic->op == '=' &&
!POINTER_SET (dic) &&
IC_RESULT (dic)->key == op->key
/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */
)
{
/* we are interested only if defined in far space */
/* or in stack space in case of + & - */
/* if assigned to a non-symbol then return
true */
if (!IS_SYMOP (IC_RIGHT (dic)))
break;
/* if the symbol is in far space then
we should not */
if (isOperandInFarSpace (IC_RIGHT (dic)))
return NULL;
/* for + & - operations make sure that
if it is on the stack it is the same
as one of the three operands */
if ((ic->op == '+' || ic->op == '-') &&
OP_SYMBOL (IC_RIGHT (dic))->onStack)
{
if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key &&
IC_LEFT (ic)->key != IC_RIGHT (dic)->key &&
IC_RIGHT (ic)->key != IC_RIGHT (dic)->key)
return NULL;
}
break;
}
/* if we find an usage then we cannot delete it */
if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key)
return NULL;
if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key)
return NULL;
if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key)
return NULL;
}
/* now make sure that the right side of dic
is not defined between ic & dic */
if (dic)
{
iCode *sic = dic->next;
for (; sic != ic; sic = sic->next)
if (IC_RESULT (sic) &&
IC_RESULT (sic)->key == IC_RIGHT (dic)->key)
return NULL;
}
return dic;
}
/*-----------------------------------------------------------------*/
/* packRegsForSupport :- reduce some registers for support calls */
/*-----------------------------------------------------------------*/
static int
packRegsForSupport (iCode * ic, eBBlock * ebp)
{
int change = 0;
debugLog ("%s\n", __FUNCTION__);
/* for the left & right operand :- look to see if the
left was assigned a true symbol in far space in that
case replace them */
if (IS_ITEMP (IC_LEFT (ic)) &&
OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq)
{
iCode *dic = findAssignToSym (IC_LEFT (ic), ic);
iCode *sic;
if (!dic)
goto right;
debugAopGet ("removing left:", IC_LEFT (ic));
/* found it we need to remove it from the
block */
for (sic = dic; sic != ic; sic = sic->next)
bitVectUnSetBit (sic->rlive, IC_LEFT (ic)->key);
IC_LEFT (ic)->operand.symOperand =
IC_RIGHT (dic)->operand.symOperand;
IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
remiCodeFromeBBlock (ebp, dic);
hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
change++;
}
/* do the same for the right operand */
right:
if (!change &&
IS_ITEMP (IC_RIGHT (ic)) &&
OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq)
{
iCode *dic = findAssignToSym (IC_RIGHT (ic), ic);
iCode *sic;
if (!dic)
return change;
/* if this is a subtraction & the result
is a true symbol in far space then don't pack */
if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic)))
{
sym_link *etype = getSpec (operandType (IC_RESULT (dic)));
if (IN_FARSPACE (SPEC_OCLS (etype)))
return change;
}
debugAopGet ("removing right:", IC_RIGHT (ic));
/* found it we need to remove it from the
block */
for (sic = dic; sic != ic; sic = sic->next)
bitVectUnSetBit (sic->rlive, IC_RIGHT (ic)->key);
IC_RIGHT (ic)->operand.symOperand =
IC_RIGHT (dic)->operand.symOperand;
IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key;
remiCodeFromeBBlock (ebp, dic);
hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
change++;
}
return change;
}
#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
/*-----------------------------------------------------------------*/
/* packRegsForOneuse : - will reduce some registers for single Use */
/*-----------------------------------------------------------------*/
static iCode *
packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp)
{
bitVect *uses;
iCode *dic, *sic;
debugLog ("%s\n", __FUNCTION__);
/* if returning a literal then do nothing */
if (!IS_SYMOP (op))
return NULL;
/* only upto 2 bytes since we cannot predict
the usage of b, & acc */
if (getSize (operandType (op)) > (fReturnSizePic - 2) &&
ic->op != RETURN &&
ic->op != SEND)
return NULL;
/* this routine will mark the a symbol as used in one
instruction use only && if the definition is local
(ie. within the basic block) && has only one definition &&
that definition 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;
/* found the definition now check if it is local */
if (dic->seq < ebp->fSeq ||
dic->seq > ebp->lSeq)
return NULL; /* non-local */
/* now check if it is the return from
a function call */
if (dic->op == CALL || dic->op == PCALL)
{
if (ic->op != SEND && ic->op != RETURN)
{
OP_SYMBOL (op)->ruonly = 1;
return dic;
}
dic = dic->next;
}
/* otherwise check that the definition does
not contain any symbols in far space */
if (isOperandInFarSpace (IC_LEFT (dic)) ||
isOperandInFarSpace (IC_RIGHT (dic)) ||
IS_OP_RUONLY (IC_LEFT (ic)) ||
IS_OP_RUONLY (IC_RIGHT (ic)))
{
return NULL;
}
/* if pointer set then make sure the pointer
is one byte */
if (POINTER_SET (dic) &&
!IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
return NULL;
if (POINTER_GET (dic) &&
!IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
return NULL;
sic = dic;
/* also make sure the intervenening instructions
don't have any thing in far space */
for (dic = dic->next; dic && dic != ic; dic = dic->next)
{
/* if there is an intervening function call then no */
if (dic->op == CALL || dic->op == PCALL)
return NULL;
/* if pointer set then make sure the pointer
is one byte */
if (POINTER_SET (dic) &&
!IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)))
return NULL;
if (POINTER_GET (dic) &&
!IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)))
return NULL;
/* if address of & the result is remat then okay */
if (dic->op == ADDRESS_OF &&
OP_SYMBOL (IC_RESULT (dic))->remat)
continue;
/* if operand has size of three or more & this
operation is a '*','/' or '%' then 'b' may
cause a problem */
if ((dic->op == '%' || dic->op == '/' || dic->op == '*') &&
getSize (operandType (op)) >= 3)
return NULL;
/* if left or right or result is in far space */
if (isOperandInFarSpace (IC_LEFT (dic)) ||
isOperandInFarSpace (IC_RIGHT (dic)) ||
isOperandInFarSpace (IC_RESULT (dic)) ||
IS_OP_RUONLY (IC_LEFT (dic)) ||
IS_OP_RUONLY (IC_RIGHT (dic)) ||
IS_OP_RUONLY (IC_RESULT (dic)))
{
return NULL;
}
}
OP_SYMBOL (op)->ruonly = 1;
return sic;
}
/*-----------------------------------------------------------------*/
/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */
/*-----------------------------------------------------------------*/
static bool
isBitwiseOptimizable (iCode * ic)
{
sym_link *ltype = getSpec (operandType (IC_LEFT (ic)));
sym_link *rtype = getSpec (operandType (IC_RIGHT (ic)));
debugLog ("%s\n", __FUNCTION__);
/* bitwise operations are considered optimizable
under the following conditions (Jean-Louis VERN)
x & lit
bit & bit
bit & x
bit ^ bit
bit ^ x
x ^ lit
x | lit
bit | bit
bit | x
*/
if (IS_LITERAL (rtype) ||
(IS_BITVAR (ltype) && IN_BITSPACE (SPEC_OCLS (ltype))))
return TRUE;
else
return FALSE;
}
/*-----------------------------------------------------------------*/
/* packRegsForAccUse - pack registers for acc use */
/*-----------------------------------------------------------------*/
static void
packRegsForAccUse (iCode * ic)
{
iCode *uic;
debugLog ("%s\n", __FUNCTION__);
/* if + or - then it has to be one byte result */
if ((ic->op == '+' || ic->op == '-')
&& getSize (operandType (IC_RESULT (ic))) > 1)
return;
/* if shift operation make sure right side is not a literal */
if (ic->op == RIGHT_OP &&
(isOperandLiteral (IC_RIGHT (ic)) ||
getSize (operandType (IC_RESULT (ic))) > 1))
return;
if (ic->op == LEFT_OP &&
(isOperandLiteral (IC_RIGHT (ic)) ||
getSize (operandType (IC_RESULT (ic))) > 1))
return;
if (IS_BITWISE_OP (ic) &&
getSize (operandType (IC_RESULT (ic))) > 1)
return;
/* has only one definition */
if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1)
return;
/* has only one use */
if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1)
return;
/* and the usage immediately follows this iCode */
if (!(uic = hTabItemWithKey (iCodehTab,
bitVectFirstBit (OP_USES (IC_RESULT (ic))))))
return;
if (ic->next != uic)
return;
/* if it is a conditional branch then we definitely can */
if (uic->op == IFX)
goto accuse;
if (uic->op == JUMPTABLE)
return;
/* if the usage is not is an assignment
or an arithmetic / bitwise / shift operation then not */
if (POINTER_SET (uic) &&
getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1)
return;
if (uic->op != '=' &&
!IS_ARITHMETIC_OP (uic) &&
!IS_BITWISE_OP (uic) &&
uic->op != LEFT_OP &&
uic->op != RIGHT_OP)
return;
/* if used in ^ operation then make sure right is not a
literl */
if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic)))
return;
/* if shift operation make sure right side is not a literal */
if (uic->op == RIGHT_OP &&
(isOperandLiteral (IC_RIGHT (uic)) ||
getSize (operandType (IC_RESULT (uic))) > 1))
return;
if (uic->op == LEFT_OP &&
(isOperandLiteral (IC_RIGHT (uic)) ||
getSize (operandType (IC_RESULT (uic))) > 1))
return;
/* make sure that the result of this icode is not on the
stack, since acc is used to compute stack offset */
if (IS_TRUE_SYMOP (IC_RESULT (uic)) &&
OP_SYMBOL (IC_RESULT (uic))->onStack)
return;
/* if either one of them in far space then we cannot */
if ((IS_TRUE_SYMOP (IC_LEFT (uic)) &&
isOperandInFarSpace (IC_LEFT (uic))) ||
(IS_TRUE_SYMOP (IC_RIGHT (uic)) &&
isOperandInFarSpace (IC_RIGHT (uic))))
return;
/* if the usage has only one operand then we can */
if (IC_LEFT (uic) == NULL ||
IC_RIGHT (uic) == NULL)
goto accuse;
/* make sure this is on the left side if not
a '+' since '+' is commutative */
if (ic->op != '+' &&
IC_LEFT (uic)->key != IC_RESULT (ic)->key)
return;
/* if one of them is a literal then we can */
if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) ||
(IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic))))
{
OP_SYMBOL (IC_RESULT (ic))->accuse = 1;
return;
}
/* if the other one is not on stack then we can */
if (IC_LEFT (uic)->key == IC_RESULT (ic)->key &&
(IS_ITEMP (IC_RIGHT (uic)) ||
(IS_TRUE_SYMOP (IC_RIGHT (uic)) &&
!OP_SYMBOL (IC_RIGHT (uic))->onStack)))
goto accuse;
if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key &&
(IS_ITEMP (IC_LEFT (uic)) ||
(IS_TRUE_SYMOP (IC_LEFT (uic)) &&
!OP_SYMBOL (IC_LEFT (uic))->onStack)))
goto accuse;
return;
accuse:
OP_SYMBOL (IC_RESULT (ic))->accuse = 1;
}
/*-----------------------------------------------------------------*/
/* packForPush - hueristics to reduce iCode for pushing */
/*-----------------------------------------------------------------*/
static void
packForReceive (iCode * ic, eBBlock * ebp)
{
iCode *dic;
debugLog ("%s\n", __FUNCTION__);
debugAopGet (" result:", IC_RESULT (ic));
debugAopGet (" left:", IC_LEFT (ic));
debugAopGet (" right:", IC_RIGHT (ic));
if (!ic->next)
return;
for (dic = ic->next; dic; dic = dic->next)
{
if (IC_LEFT (dic) && (IC_RESULT (ic)->key == IC_LEFT (dic)->key))
debugLog (" used on left\n");
if (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key)
debugLog (" used on right\n");
if (IC_RESULT (dic) && IC_RESULT (ic)->key == IC_RESULT (dic)->key)
debugLog (" used on result\n");
if ((IC_LEFT (dic) && (IC_RESULT (ic)->key == IC_LEFT (dic)->key)) ||
(IC_RESULT (dic) && IC_RESULT (ic)->key == IC_RESULT (dic)->key))
return;
}
debugLog (" hey we can remove this unnecessary assign\n");
}
/*-----------------------------------------------------------------*/
/* packForPush - hueristics to reduce iCode for pushing */
/*-----------------------------------------------------------------*/
static void
packForPush (iCode * ic, eBBlock * ebp)
{
iCode *dic;
debugLog ("%s\n", __FUNCTION__);
if (ic->op != IPUSH || !IS_ITEMP (IC_LEFT (ic)))
return;
/* must have only definition & one usage */
if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic))) != 1 ||
bitVectnBitsOn (OP_USES (IC_LEFT (ic))) != 1)
return;
/* find the definition */
if (!(dic = hTabItemWithKey (iCodehTab,
bitVectFirstBit (OP_DEFS (IC_LEFT (ic))))))
return;
if (dic->op != '=' || POINTER_SET (dic))
return;
/* we now we know that it has one & only one def & use
and the that the definition is an assignment */
IC_LEFT (ic) = IC_RIGHT (dic);
remiCodeFromeBBlock (ebp, dic);
hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
}
/*-----------------------------------------------------------------*/
/* packRegisters - does some transformations to reduce register */
/* pressure */
/*-----------------------------------------------------------------*/
static void
packRegisters (eBBlock * ebp)
{
iCode *ic;
int change = 0;
debugLog ("%s\n", __FUNCTION__);
while (1)
{
change = 0;
/* look for assignments of the form */
/* iTempNN = TRueSym (someoperation) SomeOperand */
/* .... */
/* TrueSym := iTempNN:1 */
for (ic = ebp->sch; ic; ic = ic->next)
{
/* find assignment of the form TrueSym := iTempNN:1 */
if (ic->op == '=' && !POINTER_SET (ic))
change += packRegsForAssign (ic, ebp);
/* debug stuff */
if (ic->op == '=')
{
if (POINTER_SET (ic))
debugLog ("pointer is set\n");
debugAopGet (" result:", IC_RESULT (ic));
debugAopGet (" left:", IC_LEFT (ic));
debugAopGet (" right:", IC_RIGHT (ic));
}
}
if (!change)
break;
}
for (ic = ebp->sch; ic; ic = ic->next)
{
/* if this is an itemp & result of a address of a true sym
then mark this as rematerialisable */
if (ic->op == ADDRESS_OF &&
IS_ITEMP (IC_RESULT (ic)) &&
IS_TRUE_SYMOP (IC_LEFT (ic)) &&
bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 &&
!OP_SYMBOL (IC_LEFT (ic))->onStack)
{
debugLog (" %d - %s. result is rematerializable\n", __LINE__,__FUNCTION__);
OP_SYMBOL (IC_RESULT (ic))->remat = 1;
OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;
}
/* if straight assignment then carry remat flag if
this is the only definition */
if (ic->op == '=' &&
!POINTER_SET (ic) &&
IS_SYMOP (IC_RIGHT (ic)) &&
OP_SYMBOL (IC_RIGHT (ic))->remat &&
bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1)
{
debugLog (" %d - %s. straight rematerializable\n", __LINE__,__FUNCTION__);
OP_SYMBOL (IC_RESULT (ic))->remat =
OP_SYMBOL (IC_RIGHT (ic))->remat;
OP_SYMBOL (IC_RESULT (ic))->rematiCode =
OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
}
/* if this is a +/- operation with a rematerizable
then mark this as rematerializable as well */
if ((ic->op == '+' || ic->op == '-') &&
(IS_SYMOP (IC_LEFT (ic)) &&
IS_ITEMP (IC_RESULT (ic)) &&
OP_SYMBOL (IC_LEFT (ic))->remat &&
bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 &&
IS_OP_LITERAL (IC_RIGHT (ic))))
{
debugLog (" %d - %s. rematerializable because op is +/-\n", __LINE__,__FUNCTION__);
//int i =
operandLitValue (IC_RIGHT (ic));
OP_SYMBOL (IC_RESULT (ic))->remat = 1;
OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic;
OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL;
}
/* mark the pointer usages */
if (POINTER_SET (ic))
{
OP_SYMBOL (IC_RESULT (ic))->uptr = 1;
debugLog (" marking as a pointer (set) =>");
debugAopGet (" result:", IC_RESULT (ic));
}
if (POINTER_GET (ic))
{
OP_SYMBOL (IC_LEFT (ic))->uptr = 1;
debugLog (" marking as a pointer (get) =>");
debugAopGet (" left:", IC_LEFT (ic));
}
if (!SKIP_IC2 (ic))
{
/* if we are using a symbol on the stack
then we should say pic14_ptrRegReq */
if (ic->op == IFX && IS_SYMOP (IC_COND (ic)))
pic14_ptrRegReq += ((OP_SYMBOL (IC_COND (ic))->onStack ||
OP_SYMBOL (IC_COND (ic))->iaccess) ? 1 : 0);
else if (ic->op == JUMPTABLE && IS_SYMOP (IC_JTCOND (ic)))
pic14_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack ||
OP_SYMBOL (IC_JTCOND (ic))->iaccess) ? 1 : 0);
else
{
if (IS_SYMOP (IC_LEFT (ic)))
pic14_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack ||
OP_SYMBOL (IC_LEFT (ic))->iaccess) ? 1 : 0);
if (IS_SYMOP (IC_RIGHT (ic)))
pic14_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack ||
OP_SYMBOL (IC_RIGHT (ic))->iaccess) ? 1 : 0);
if (IS_SYMOP (IC_RESULT (ic)))
pic14_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack ||
OP_SYMBOL (IC_RESULT (ic))->iaccess) ? 1 : 0);
}
}
/* if the condition of an if instruction
is defined in the previous instruction then
mark the itemp as a conditional */
if ((IS_CONDITIONAL (ic) ||
((ic->op == BITWISEAND ||
ic->op == '|' ||
ic->op == '^') &&
isBitwiseOptimizable (ic))) &&
ic->next && ic->next->op == IFX &&
isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) &&
OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq)
{
OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND;
continue;
}
/* reduce for support function calls */
if (ic->supportRtn || ic->op == '+' || ic->op == '-')
packRegsForSupport (ic, ebp);
/* if a parameter is passed, it's in W, so we may not
need to place a copy in a register */
if (ic->op == RECEIVE)
packForReceive (ic, ebp);
/* some cases the redundant moves can
can be eliminated for return statements */
if ((ic->op == RETURN || ic->op == SEND) &&
!isOperandInFarSpace (IC_LEFT (ic)) &&
!options.model)
packRegsForOneuse (ic, IC_LEFT (ic), ebp);
/* if pointer set & left has a size more than
one and right is not in far space */
if (POINTER_SET (ic) &&
!isOperandInFarSpace (IC_RIGHT (ic)) &&
!OP_SYMBOL (IC_RESULT (ic))->remat &&
!IS_OP_RUONLY (IC_RIGHT (ic)) &&
getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1)
packRegsForOneuse (ic, IC_RESULT (ic), ebp);
/* if pointer get */
if (POINTER_GET (ic) &&
!isOperandInFarSpace (IC_RESULT (ic)) &&
!OP_SYMBOL (IC_LEFT (ic))->remat &&
!IS_OP_RUONLY (IC_RESULT (ic)) &&
getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1)
packRegsForOneuse (ic, IC_LEFT (ic), ebp);
/* if this is cast for intergral promotion then
check if only use of the definition of the
operand being casted/ if yes then replace
the result of that arithmetic operation with
this result and get rid of the cast */
if (ic->op == CAST)
{
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))
{
iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp);
if (dic)
{
if (IS_ARITHMETIC_OP (dic))
{
IC_RESULT (dic) = IC_RESULT (ic);
remiCodeFromeBBlock (ebp, ic);
hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
ic = ic->prev;
}
else
OP_SYMBOL (IC_RIGHT (ic))->ruonly = 0;
}
}
else
{
/* if the type from and type to are the same
then if this is the only use then packit */
if (compareType (operandType (IC_RIGHT (ic)),
operandType (IC_LEFT (ic))) == 1)
{
iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp);
if (dic)
{
IC_RESULT (dic) = IC_RESULT (ic);
remiCodeFromeBBlock (ebp, ic);
hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL);
OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key);
ic = ic->prev;
}
}
}
}
/* pack for PUSH
iTempNN := (some variable in farspace) V1
push iTempNN ;
-------------
push V1
*/
if (ic->op == IPUSH)
{
packForPush (ic, ebp);
}
/* pack registers for accumulator use, when the
result of an arithmetic or bit wise operation
has only one use, that use is immediately following
the defintion and the using iCode has only one
operand or has two operands but one is literal &
the result of that operation is not on stack then
we can leave the result of this operation in acc:b
combination */
if ((IS_ARITHMETIC_OP (ic)
|| IS_BITWISE_OP (ic)
|| ic->op == LEFT_OP || ic->op == RIGHT_OP
) &&
IS_ITEMP (IC_RESULT (ic)) &&
getSize (operandType (IC_RESULT (ic))) <= 2)
packRegsForAccUse (ic);
}
}
static void
dumpEbbsToDebug (eBBlock ** ebbs, int count)
{
int i;
if (!debug || !debugF)
return;
for (i = 0; i < count; i++)
{
fprintf (debugF, "\n----------------------------------------------------------------\n");
fprintf (debugF, "Basic Block %s : loop Depth = %d noPath = %d , lastinLoop = %d\n",
ebbs[i]->entryLabel->name,
ebbs[i]->depth,
ebbs[i]->noPath,
ebbs[i]->isLastInLoop);
fprintf (debugF, "depth 1st num %d : bbnum = %d 1st iCode = %d , last iCode = %d\n",
ebbs[i]->dfnum,
ebbs[i]->bbnum,
ebbs[i]->fSeq,
ebbs[i]->lSeq);
fprintf (debugF, "visited %d : hasFcall = %d\n",
ebbs[i]->visited,
ebbs[i]->hasFcall);
fprintf (debugF, "\ndefines bitVector :");
bitVectDebugOn (ebbs[i]->defSet, debugF);
fprintf (debugF, "\nlocal defines bitVector :");
bitVectDebugOn (ebbs[i]->ldefs, debugF);
fprintf (debugF, "\npointers Set bitvector :");
bitVectDebugOn (ebbs[i]->ptrsSet, debugF);
fprintf (debugF, "\nin pointers Set bitvector :");
bitVectDebugOn (ebbs[i]->inPtrsSet, debugF);
fprintf (debugF, "\ninDefs Set bitvector :");
bitVectDebugOn (ebbs[i]->inDefs, debugF);
fprintf (debugF, "\noutDefs Set bitvector :");
bitVectDebugOn (ebbs[i]->outDefs, debugF);
fprintf (debugF, "\nusesDefs Set bitvector :");
bitVectDebugOn (ebbs[i]->usesDefs, debugF);
fprintf (debugF, "\n----------------------------------------------------------------\n");
printiCChain (ebbs[i]->sch, debugF);
}
}
/*-----------------------------------------------------------------*/
/* assignRegisters - assigns registers to each live range as need */
/*-----------------------------------------------------------------*/
void
pic14_assignRegisters (eBBlock ** ebbs, int count)
{
iCode *ic;
int i;
debugLog ("<><><><><><><><><><><><><><><><><>\nstarting\t%s:%s", __FILE__, __FUNCTION__);
debugLog ("ebbs before optimizing:\n");
dumpEbbsToDebug (ebbs, count);
setToNull ((void *) &_G.funcrUsed);
pic14_ptrRegReq = _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 ();
/* and serially allocate registers */
serialRegAssign (ebbs, count);
/* if stack was extended then tell the user */
if (_G.stackExtend)
{
/* werror(W_TOOMANY_SPILS,"stack", */
/* _G.stackExtend,currFunc->name,""); */
_G.stackExtend = 0;
}
if (_G.dataExtend)
{
/* werror(W_TOOMANY_SPILS,"data space", */
/* _G.dataExtend,currFunc->name,""); */
_G.dataExtend = 0;
}
/* after that create the register mask
for each of the instruction */
createRegMask (ebbs, count);
/* redo that offsets for stacked automatic variables */
redoStackOffsets ();
if (options.dump_rassgn)
dumpEbbsToFileExt (DUMP_RASSGN, ebbs, count);
/* now get back the chain */
ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
debugLog ("ebbs after optimizing:\n");
dumpEbbsToDebug (ebbs, count);
genpic14Code (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 */
pic14_freeAllRegs ();
debugLog ("leaving\n<><><><><><><><><><><><><><><><><>\n");
debugLogClose ();
return;
}