sdcc-gas/src/SDCCmem.c

1354 lines
41 KiB
C

/*-------------------------------------------------------------------------
SDCCmem.c - 8051 memory management routines
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 "dbuf_string.h"
#include "SDCCbtree.h"
/* memory segments */
memmap *xstack = NULL; /* xternal stack data */
memmap *istack = NULL; /* internal stack */
memmap *code = NULL; /* code segment */
memmap *data = NULL; /* internal data upto 128 */
memmap *initialized = NULL; /* initialized data, such as initialized, nonzero globals or local statics. */
memmap *initializer = NULL; /* a copz of the values for the initialized data from initialized in code space */
memmap *pdata = NULL; /* paged external data */
memmap *xdata = NULL; /* external data */
memmap *xidata = NULL; /* the initialized xdata */
memmap *xinit = NULL; /* the initializers for xidata */
memmap *idata = NULL; /* internal data upto 256 */
memmap *bit = NULL; /* bit addressable space */
memmap *statsg = NULL; /* the constant data segment */
memmap *c_abs = NULL; /* constant absolute data */
memmap *x_abs = NULL; /* absolute xdata/pdata */
memmap *i_abs = NULL; /* absolute idata upto 256 */
memmap *d_abs = NULL; /* absolute data upto 128 */
memmap *sfr = NULL; /* register space */
memmap *reg = NULL; /* register space */
memmap *sfrbit = NULL; /* sfr bit space */
memmap *generic = NULL; /* is a generic pointer */
memmap *overlay = NULL; /* overlay segment */
memmap *eeprom = NULL; /* eeprom location */
memmap *home = NULL; /* Unswitchable code bank */
namedspacemap *namedspacemaps = 0; /* memory segments for named address spaces */
/* this is a set of sets each set containing
symbols in a single overlay */
set *ovrSetSets = NULL;
int fatalError = 0; /* fatal error flag */
/*-----------------------------------------------------------------*/
/* allocMap - allocates a memory map */
/*-----------------------------------------------------------------*/
memmap *
allocMap (char rspace, /* sfr space */
char farmap, /* far or near segment */
char paged, /* can this segment be paged */
char direct, /* directly addressable */
char bitaddr, /* bit addressable space */
char codemap, /* this is code space */
unsigned sloc, /* starting location */
const char *name, /* 8 character name */
char dbName, /* debug name */
int ptrType /* pointer type for this space */
)
{
memmap *map;
if (!name)
return NULL;
if (!(map = Safe_alloc (sizeof (memmap))))
{
werror (E_OUT_OF_MEM, __FILE__, sizeof (memmap));
exit (1);
}
memset (map, 0, sizeof (memmap));
map->regsp = rspace;
map->fmap = farmap;
map->paged = paged;
map->direct = direct;
map->bitsp = bitaddr;
map->codesp = codemap;
map->sloc = sloc;
map->sname = name;
map->dbName = dbName;
map->ptrType = ptrType;
map->syms = NULL;
dbuf_init(&map->oBuf, 4096);
return map;
}
/*-----------------------------------------------------------------*/
/* initMem - allocates and initializes all the segments */
/*-----------------------------------------------------------------*/
void
initMem ()
{
/* allocate all the segments */
/* xternal stack segment ;
SFRSPACE - NO
FAR-SPACE - YES
PAGED - YES
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'A'
POINTER-TYPE - FPOINTER
*/
xstack = allocMap (0, 1, 1, 0, 0, 0, options.xstack_loc, XSTACK_NAME, 'A', PPOINTER);
/* internal stack segment ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'B'
POINTER-TYPE - POINTER
*/
istack = allocMap (0, 0, 0, 0, 0, 0, options.stack_loc, ISTACK_NAME, 'B', POINTER);
/* code segment ;
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - YES
DEBUG-NAME - 'C'
POINTER-TYPE - CPOINTER
*/
code = allocMap (0, 1, 0, 0, 0, 1, options.code_loc, CODE_NAME, 'C', CPOINTER);
/* home segment ;
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - YES
DEBUG-NAME - 'C'
POINTER-TYPE - CPOINTER
*/
home = allocMap (0, 1, 0, 0, 0, 1, options.code_loc, HOME_NAME, 'C', CPOINTER);
/* Static segment (code for variables );
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - YES
DEBUG-NAME - 'D'
POINTER-TYPE - CPOINTER
*/
statsg = allocMap (0, 1, 0, 0, 0, 1, 0, STATIC_NAME, 'D', CPOINTER);
/* Constant Absolute Data segment (for variables );
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - YES
DEBUG-NAME - 'D'
POINTER-TYPE - CPOINTER
*/
c_abs = allocMap (0, 1, 0, 0, 0, 1, 0, CABS_NAME, 'D', CPOINTER);
/* Data segment - internal storage segment ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'E'
POINTER-TYPE - POINTER
*/
data = allocMap (0, 0, 0, 1, 0, 0, options.data_loc, DATA_NAME, 'E', POINTER);
initialized = allocMap (0, 0, 0, 1, 0, 0, options.data_loc, INITIALIZED_NAME, 'E', POINTER);
initializer = allocMap (0, 0, 0, 1, 0, 1, options.code_loc, INITIALIZER_NAME, 'C', CPOINTER);
/* Absolute internal storage segment ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'E'
POINTER-TYPE - POINTER
*/
d_abs = allocMap (0, 0, 0, 1, 0, 0, options.data_loc, IABS_NAME, 'E', POINTER);
/* overlay segment - same as internal storage segment ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'E'
POINTER-TYPE - POINTER
*/
if (OVERLAY_NAME)
overlay = allocMap (0, 0, 0, 1, 0, 0, options.data_loc, DATA_NAME, 'E', POINTER);
/* Xternal paged segment ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - YES
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'P'
POINTER-TYPE - PPOINTER
*/
pdata = allocMap (0, 0, 1, 0, 0, 0, options.xstack_loc, PDATA_NAME, 'P', PPOINTER);
/* Xternal Data segment -
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'F'
POINTER-TYPE - FPOINTER
*/
xdata = allocMap (0, 1, 0, 0, 0, 0, options.xdata_loc, XDATA_NAME, 'F', FPOINTER);
xidata = allocMap (0, 1, 0, 0, 0, 0, 0, XIDATA_NAME, 'F', FPOINTER);
xinit = allocMap (0, 1, 0, 0, 0, 1, 0, XINIT_NAME, 'C', CPOINTER);
/* Absolute external storage segment ;
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'F'
POINTER-TYPE - FPOINTER
*/
x_abs = allocMap (0, 1, 0, 0, 0, 0, options.xdata_loc, XABS_NAME, 'F', FPOINTER);
/* Indirectly addressed internal data segment
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'G'
POINTER-TYPE - IPOINTER
*/
idata = allocMap (0, 0, 0, 0, 0, 0, options.idata_loc, IDATA_NAME, 'G', IPOINTER);
/* Indirectly addressed absolute internal segment
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'E'
POINTER-TYPE - IPOINTER
*/
i_abs = allocMap (0, 0, 0, 0, 0, 0, options.data_loc, IABS_NAME, 'E', IPOINTER);
/* Bit space ;
SFRSPACE - NO
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - YES
CODE-ACCESS - NO
DEBUG-NAME - 'H'
POINTER-TYPE - _NONE_
*/
bit = allocMap (0, 0, 0, 1, 1, 0, 0, BIT_NAME, 'H', 0);
/* Special function register space :-
SFRSPACE - YES
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'I'
POINTER-TYPE - _NONE_
*/
sfr = allocMap (1, 0, 0, 1, 0, 0, 0, REG_NAME, 'I', 0);
/* Register space ;
SFRSPACE - YES
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - ' '
POINTER-TYPE - _NONE_
*/
reg = allocMap (1, 0, 0, 0, 0, 0, 0, REG_NAME, ' ', 0);
/* SFR bit space
SFRSPACE - YES
FAR-SPACE - NO
PAGED - NO
DIRECT-ACCESS - YES
BIT-ACCESS - YES
CODE-ACCESS - NO
DEBUG-NAME - 'J'
POINTER-TYPE - _NONE_
*/
sfrbit = allocMap (1, 0, 0, 1, 1, 0, 0, REG_NAME, 'J', 0);
/* EEPROM space
SFRSPACE - NO
FAR-SPACE - YES
PAGED - NO
DIRECT-ACCESS - NO
BIT-ACCESS - NO
CODE-ACCESS - NO
DEBUG-NAME - 'K'
POINTER-TYPE - EEPPOINTER
*/
eeprom = allocMap (0, 1, 0, 0, 0, 0, 0, REG_NAME, 'K', EEPPOINTER);
/* the unknown map */
generic = allocMap (0, 0, 0, 0, 0, 0, 0, DATA_NAME, ' ', GPOINTER);
}
/*-----------------------------------------------------------------*/
/* allocIntoSeg - puts a symbol into a memory segment */
/*-----------------------------------------------------------------*/
void
allocIntoSeg (symbol *sym)
{
memmap *segment;
if (SPEC_ADDRSPACE (sym->etype))
{
namedspacemap *nm;
for (nm = namedspacemaps; nm; nm = nm->next)
if (!strcmp (nm->name, SPEC_ADDRSPACE (sym->etype)->name))
break;
if (!nm)
{
nm = Safe_alloc (sizeof (namedspacemap));
nm->name = Safe_alloc (strlen(SPEC_ADDRSPACE (sym->etype)->name) + 1);
strcpy (nm->name, SPEC_ADDRSPACE (sym->etype)->name);
nm->is_const = (SPEC_ADDRSPACE (sym->etype)->type && SPEC_CONST (SPEC_ADDRSPACE (sym->etype)->type));
nm->map = nm->is_const ?
allocMap (0, 1, 0, 0, 0, 1, options.code_loc, SPEC_ADDRSPACE (sym->etype)->name, 'C', CPOINTER) :
allocMap (0, 0, 0, 1, 0, 0, options.data_loc, SPEC_ADDRSPACE (sym->etype)->name, 'E', POINTER);
nm->next = namedspacemaps;
namedspacemaps = nm;
}
addSet (&nm->map->syms, sym);
return;
}
if (!(segment = SPEC_OCLS (sym->etype)))
{
fprintf (stderr, "Symbol %s:\n", sym->name);
wassertl (0, "Failed to allocate symbol to memory segment due to missing output storage class");
return;
}
addSet (&segment->syms, sym);
if (segment == pdata)
sym->iaccess = 1;
}
/*-----------------------------------------------------------------*/
/* deleteFromSeg - deletes a symbol from segment used when a var */
/* first declared as "extern" then no extern */
/*-----------------------------------------------------------------*/
void deleteFromSeg(symbol *sym)
{
if (SPEC_OCLS(sym->etype))
{
memmap *segment = SPEC_OCLS (sym->etype);
deleteSetItem(&segment->syms, sym);
}
}
/*-----------------------------------------------------------------*/
/* defaultOClass - set the output segment based on SCLASS */
/*-----------------------------------------------------------------*/
bool
defaultOClass (symbol *sym)
{
switch (SPEC_SCLS (sym->etype))
{
case S_SFR:
SPEC_OCLS (sym->etype) = sfr;
break;
case S_SBIT:
SPEC_OCLS (sym->etype) = sfrbit;
break;
case S_CODE:
if (sym->_isparm)
return FALSE;
/* if code change to constant */
if (sym->ival && SPEC_ABSA (sym->etype))
{
SPEC_OCLS(sym->etype) = c_abs;
}
else
{
SPEC_OCLS (sym->etype) = statsg;
}
break;
case S_XDATA:
/* absolute initialized global */
if (sym->ival && SPEC_ABSA (sym->etype))
{
SPEC_OCLS(sym->etype) = x_abs;
}
/* or should we move this to the initialized data segment? */
else if (port->genXINIT && sym->ival && (sym->level==0))
{
SPEC_OCLS(sym->etype) = xidata;
}
else
{
SPEC_OCLS (sym->etype) = xdata;
}
break;
case S_DATA:
/* Absolute initialized global */
if (sym->ival && SPEC_ABSA (sym->etype))
{
SPEC_OCLS (sym->etype) = d_abs;
}
/* Other initialized global */
else if (sym->ival && port->mem.initialized_name && sym->level == 0)
{
SPEC_OCLS (sym->etype) = initialized;
}
else
{
SPEC_OCLS (sym->etype) = data;
}
break;
case S_IDATA:
/* absolute initialized global */
if (sym->ival && SPEC_ABSA (sym->etype))
{
SPEC_OCLS(sym->etype) = i_abs;
}
else
{
SPEC_OCLS (sym->etype) = idata;
}
sym->iaccess = 1;
break;
case S_PDATA:
SPEC_OCLS (sym->etype) = pdata;
sym->iaccess = 1;
break;
case S_BIT:
SPEC_OCLS (sym->etype) = bit;
break;
case S_EEPROM:
SPEC_OCLS (sym->etype) = eeprom;
break;
default:
return FALSE;
}
return TRUE;
}
/*-----------------------------------------------------------------*/
/* allocDefault - assigns the output segment based on SCLASS */
/*-----------------------------------------------------------------*/
bool
allocDefault (struct symbol * sym)
{
if (defaultOClass (sym))
{
allocIntoSeg (sym);
return TRUE;
}
return FALSE;
}
/*-----------------------------------------------------------------*/
/* allocGlobal - assigns the output segment to a global var */
/*-----------------------------------------------------------------*/
void
allocGlobal (symbol * sym)
{
/* symbol name is internal name */
if (!sym->level) /* local statics can come here */
SNPRINTF (sym->rname, sizeof(sym->rname),
"%s%s", port->fun_prefix, sym->name);
/* add it to the operandKey reset */
if (!isinSet (operKeyReset, sym))
{
addSet(&operKeyReset, sym);
}
/* if this is a literal e.g. enumerated type */
/* put it in the data segment & do nothing */
if (IS_LITERAL (sym->etype))
{
SPEC_OCLS (sym->etype) = data;
return;
}
/* if this is a function then assign code space */
if (IS_FUNC (sym->type))
{
SPEC_OCLS (sym->etype) = code;
/* if this is an interrupt service routine
then put it in the interrupt service array */
if (FUNC_ISISR (sym->type) && !options.noiv &&
(FUNC_INTNO (sym->type) != INTNO_UNSPEC))
{
if (interrupts[FUNC_INTNO (sym->type)])
werror (E_INT_DEFINED,
FUNC_INTNO (sym->type),
interrupts[FUNC_INTNO (sym->type)]->name);
else
interrupts[FUNC_INTNO (sym->type)] = sym;
/* automagically extend the maximum interrupts */
if (FUNC_INTNO (sym->type) >= maxInterrupts && FUNC_INTNO (sym->type)!=INTNO_TRAP)
maxInterrupts = FUNC_INTNO (sym->type) + 1;
}
/* if it is not compiler defined */
if (!sym->cdef)
allocIntoSeg (sym);
return;
}
/* if this is a bit variable and no storage class */
if (bit && IS_SPEC(sym->type) && SPEC_NOUN (sym->type) == V_BIT)
{
SPEC_OCLS (sym->type) = bit;
allocIntoSeg (sym);
return;
}
if (!TARGET_IS_PIC16 || sym->level)
/* register storage class ignored changed to FIXED */
if (SPEC_SCLS (sym->etype) == S_REGISTER)
SPEC_SCLS (sym->etype) = S_FIXED;
/* if it is fixed, then allocate depending on the */
/* current memory model, same for automatics */
if (SPEC_SCLS (sym->etype) == S_FIXED ||
(TARGET_IS_PIC16 && (SPEC_SCLS (sym->etype) == S_REGISTER) && (sym->level == 0)) ||
SPEC_SCLS (sym->etype) == S_AUTO)
{
if (port->mem.default_globl_map != xdata)
{
if (sym->ival && SPEC_ABSA (sym->etype))
{
/* absolute initialized global */
SPEC_OCLS (sym->etype) = x_abs;
}
else if (sym->ival && sym->level == 0 && port->mem.initialized_name)
{
SPEC_OCLS (sym->etype) = initialized;
}
else
{
/* set the output class */
SPEC_OCLS (sym->etype) = port->mem.default_globl_map;
}
/* generate the symbol */
allocIntoSeg (sym);
return;
}
else
{
SPEC_SCLS (sym->etype) = S_XDATA;
}
}
allocDefault (sym);
return;
}
/*-----------------------------------------------------------------*/
/* allocParms - parameters are always passed on stack */
/*-----------------------------------------------------------------*/
void
allocParms (value *val, bool smallc)
{
value *lval;
int pNum = 1;
int stackParamSizeAdjust = 0;
if (smallc)
{
for (lval = val; lval; lval = lval->next)
{
if (IS_REGPARM (lval->etype))
continue;
stackParamSizeAdjust += getSize (lval->type) + (getSize (lval->type) == 1);
}
}
stackPtr += stackParamSizeAdjust;
for (lval = val; lval; lval = lval->next, pNum++)
{
/* check the declaration */
checkDecl (lval->sym, 0);
/* if this a register parm then allocate
it as a local variable by adding it
to the first block we see in the body */
if (IS_REGPARM (lval->etype))
continue;
/* mark it as my parameter */
lval->sym->ismyparm = 1;
lval->sym->localof = currFunc;
/* if automatic variables r 2b stacked */
if (options.stackAuto || IFFUNC_ISREENT (currFunc->type))
{
int paramsize = getSize (lval->type) + (getSize (lval->type) == 1 && (smallc || TARGET_PDK_LIKE));
if (lval->sym)
lval->sym->onStack = 1;
/* choose which stack 2 use */
if (options.useXstack) /* use external stack */
{
/* PENDING: stack direction support */
wassertl (!smallc, "SmallC calling convention not yet supported for xstack callee");
SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) = xstack;
SPEC_STAK (lval->etype) = SPEC_STAK (lval->sym->etype) = lval->sym->stack =
xstackPtr - paramsize;
xstackPtr -= paramsize;
}
else /* use internal stack */
{
SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) = istack;
if ((port->stack.direction > 0) != smallc)
{
SPEC_STAK (lval->etype) = SPEC_STAK (lval->sym->etype) = lval->sym->stack =
stackPtr - (FUNC_REGBANK (currFunc->type) ? port->stack.bank_overhead : 0) -
paramsize -
(FUNC_ISISR (currFunc->type) ? port->stack.isr_overhead : 0);
stackPtr -= paramsize;
}
else
{
/* This looks like the wrong order but it turns out OK... */
/* PENDING: isr, bank overhead, ... */
SPEC_STAK (lval->etype) = SPEC_STAK (lval->sym->etype) = lval->sym->stack =
stackPtr +
(FUNC_ISISR (currFunc->type) ? port->stack.isr_overhead : 0) +
0;
stackPtr += paramsize;
}
}
allocIntoSeg (lval->sym);
}
else
{
/* Do not allocate for inline functions to avoid multiple definitions - see bug report #2591. */
if(IFFUNC_ISINLINE (currFunc->type) && !IS_STATIC (currFunc->etype) && !IS_EXTERN (currFunc->etype))
continue;
/* allocate them in the automatic space */
/* generate a unique name */
SNPRINTF (lval->sym->rname, sizeof(lval->sym->rname),
"%s%s_PARM_%d", port->fun_prefix, currFunc->name, pNum);
strncpyz (lval->name, lval->sym->rname, sizeof(lval->name));
/* if declared in specific storage */
if (allocDefault (lval->sym))
{
SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype);
continue;
}
/* otherwise depending on the memory model */
SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) =
port->mem.default_local_map;
if (options.model == MODEL_SMALL)
{
/* note here that we put it into the overlay segment
first, we will remove it from the overlay segment
after the overlay determination has been done */
if (!options.noOverlay)
{
SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) =
overlay;
}
}
else if (options.model == MODEL_MEDIUM)
{
SPEC_SCLS (lval->etype) = S_PDATA;
}
else
{
SPEC_SCLS (lval->etype) = S_XDATA;
}
allocIntoSeg (lval->sym);
}
}
stackPtr -= stackParamSizeAdjust;
return;
}
/*-----------------------------------------------------------------*/
/* deallocParms - parameters are always passed on stack */
/*-----------------------------------------------------------------*/
void
deallocParms (value * val)
{
value *lval;
for (lval = val; lval; lval = lval->next)
{
/* unmark is myparm */
lval->sym->ismyparm = 0;
/* delete it from the symbol table */
deleteSym (SymbolTab, lval->sym, lval->sym->name);
if (!lval->sym->isref)
{
lval->sym->allocreq = 0;
werror (W_NO_REFERENCE,
currFunc ? currFunc->name : "(unknown)",
"function argument", lval->sym->name);
}
/* move the rname if any to the name for both val & sym */
/* and leave a copy of it in the symbol table */
if (lval->sym->rname[0])
{
char buffer[SDCC_NAME_MAX];
symbol * argsym = lval->sym;
strncpyz (buffer, lval->sym->rname, sizeof(buffer));
lval->sym = copySymbol (lval->sym);
strncpyz (lval->sym->rname, buffer, sizeof(lval->sym->rname));
strncpyz (lval->sym->name, buffer, sizeof(lval->sym->name));
/* need to keep the original name for inlining to work */
/*strncpyz (lval->name, buffer, sizeof(lval->name)); */
addSym (SymbolTab, lval->sym, lval->sym->name,
lval->sym->level, lval->sym->block, 1);
lval->sym->_isparm = 1;
if (!isinSet (operKeyReset, lval->sym))
{
addSet(&operKeyReset, lval->sym);
}
/* restore the original symbol */
lval->sym = argsym;
}
}
return;
}
/*-----------------------------------------------------------------*/
/* allocLocal - allocate local variables */
/*-----------------------------------------------------------------*/
void
allocLocal (symbol * sym)
{
/* generate an unique name */
SNPRINTF (sym->rname, sizeof(sym->rname),
"%s%s_%s_%d_%d",
port->fun_prefix,
currFunc->name, sym->name, sym->level, sym->block);
sym->islocal = 1;
sym->localof = currFunc;
/* if this is a static variable */
if (IS_STATIC (sym->etype))
{
allocGlobal (sym);
sym->allocreq = 1;
return;
}
/* if volatile then */
if (IS_VOLATILE (sym->etype))
sym->allocreq = 1;
/* this is automatic */
/* if it's to be placed on the stack */
if (options.stackAuto || reentrant)
{
sym->onStack = 1;
if (options.useXstack)
{
/* PENDING: stack direction for xstack */
SPEC_OCLS (sym->etype) = xstack;
SPEC_STAK (sym->etype) = sym->stack = (xstackPtr + 1);
xstackPtr += getSize (sym->type);
}
else
{
SPEC_OCLS (sym->etype) = istack;
if (port->stack.direction > 0)
{
SPEC_STAK (sym->etype) = sym->stack = (stackPtr + 1);
stackPtr += getSize (sym->type);
}
else
{
stackPtr -= getSize (sym->type);
SPEC_STAK (sym->etype) = sym->stack = stackPtr;
}
}
allocIntoSeg (sym);
return;
}
/* else depending on the storage class specified */
/* if this is a function then assign code space */
if (IS_FUNC (sym->type))
{
SPEC_OCLS (sym->etype) = code;
return;
}
/* if this is a bit variable and no storage class */
if (bit && IS_SPEC(sym->type) && SPEC_NOUN (sym->type) == V_BIT)
{
SPEC_SCLS (sym->type) = S_BIT;
SPEC_OCLS (sym->type) = bit;
allocIntoSeg (sym);
return;
}
if ((SPEC_SCLS (sym->etype) == S_DATA) || (SPEC_SCLS (sym->etype) == S_REGISTER))
{
SPEC_OCLS (sym->etype) = (options.noOverlay ? data : overlay);
allocIntoSeg (sym);
return;
}
if (allocDefault (sym))
{
return;
}
/* again note that we have put it into the overlay segment
will remove and put into the 'data' segment if required after
overlay analysis has been done */
if (options.model == MODEL_SMALL)
{
SPEC_OCLS (sym->etype) =
(options.noOverlay ? port->mem.default_local_map : overlay);
}
else
{
SPEC_OCLS (sym->etype) = port->mem.default_local_map;
}
allocIntoSeg (sym);
}
/*-----------------------------------------------------------------*/
/* deallocLocal - deallocates the local variables */
/*-----------------------------------------------------------------*/
void
deallocLocal (symbol * csym)
{
symbol *sym;
for (sym = csym; sym; sym = sym->next)
{
if (sym->_isparm)
continue;
/* if it is on the stack */
if (sym->onStack)
{
if (options.useXstack)
xstackPtr -= getSize (sym->type);
else
stackPtr -= getSize (sym->type);
}
/* if not used give a warning */
if (!sym->isref && !IS_STATIC (sym->etype))
werror (W_NO_REFERENCE,
currFunc ? currFunc->name : "(unknown)",
"local variable", sym->name);
/* now delete it from the symbol table */
deleteSym (SymbolTab, sym, sym->name);
}
}
/*-----------------------------------------------------------------*/
/* overlay2data - moves declarations from the overlay seg to data */
/*-----------------------------------------------------------------*/
void
overlay2data ()
{
symbol *sym;
for (sym = setFirstItem (overlay->syms); sym;
sym = setNextItem (overlay->syms))
{
SPEC_OCLS (sym->etype) = data;
allocIntoSeg (sym);
}
setToNull ((void *) &overlay->syms);
}
/*-----------------------------------------------------------------*/
/* overlay2Set - will add all symbols from the overlay segment to */
/* the set of sets containing the overlable symbols */
/*-----------------------------------------------------------------*/
void
overlay2Set ()
{
symbol *sym;
set *oset = NULL;
for (sym = setFirstItem (overlay->syms); sym;
sym = setNextItem (overlay->syms))
{
addSet (&oset, sym);
}
setToNull ((void *) &overlay->syms);
addSet (&ovrSetSets, oset);
}
/*-----------------------------------------------------------------*/
/* allocVariables - creates decl & assign storage class for a v */
/*-----------------------------------------------------------------*/
int
allocVariables (symbol * symChain)
{
symbol *sym;
symbol *csym;
int stack = 0;
long saveLevel = 0;
/* go thru the symbol chain */
for (sym = symChain; sym; sym = sym->next)
{
/* if this is a typedef then add it */
/* to the typedef table */
if (IS_TYPEDEF (sym->etype))
{
/* check if the typedef already exists */
csym = findSym (TypedefTab, NULL, sym->name);
if (csym && csym->level == sym->level &&
!(options.std_c11 && compareTypeExact (sym->type, csym->type, -1))) /* typedef to same type not allowed before ISO C11 */
werror (E_DUPLICATE_TYPEDEF, sym->name);
SPEC_EXTR (sym->etype) = 0;
addSym (TypedefTab, sym, sym->name, sym->level, sym->block, 0);
continue; /* go to the next one */
}
/* make sure it already exists */
csym = findSymWithLevel (SymbolTab, sym);
if (!csym || (csym && csym->level != sym->level))
csym = sym;
/* check the declaration */
checkDecl (csym, 0);
/* if this is a function or a pointer to a */
/* function then do args processing */
if (funcInChain (csym->type))
{
processFuncArgs (csym);
}
/* if this is an extern variable then change */
/* the level to zero temporarily */
if (IS_EXTERN (csym->etype) || IS_FUNC (csym->type))
{
saveLevel = csym->level;
csym->level = 0;
}
/* if this is a literal then it is an enumerated */
/* type so need not allocate it space for it */
if (IS_LITERAL (sym->etype))
continue;
/* generate the actual declaration */
if (csym->level)
{
allocLocal (csym);
if (csym->onStack)
stack += getSize (csym->type);
}
else
allocGlobal (csym);
/* restore the level */
if (IS_EXTERN (csym->etype) || IS_FUNC (csym->type))
csym->level = saveLevel;
}
return stack;
}
void
clearStackOffsets (void)
{
const symbol *sym;
for (sym = setFirstItem (istack->syms); sym;
sym = setNextItem (istack->syms))
{
const int size = getSize (sym->type);
/* nothing to do with parameters so continue */
if ((sym->_isparm && !IS_REGPARM (sym->etype)))
continue;
currFunc->stack -= size;
SPEC_STAK (currFunc->etype) -= size;
}
if (currFunc)
{
//wassert(!(currFunc->stack)); // Sometimes some local variable was included in istack->sams.
currFunc->stack = 0;
}
}
#define BTREE_STACK 1
/*-----------------------------------------------------------------*/
/* redoStackOffsets :- will reassign the values for stack offsets */
/*-----------------------------------------------------------------*/
void
redoStackOffsets (void)
{
symbol *sym;
int sPtr = 0;
int xsPtr = -1;
/* after register allocation is complete we know
which variables will need to be assigned space
on the stack. We will eliminate those variables
which do not have the allocReq flag thus reducing
the stack space */
for (sym = setFirstItem (istack->syms); sym; sym = setNextItem (istack->syms))
{
int size = getSize (sym->type);
/* nothing to do with parameters so continue */
if ((sym->_isparm && !IS_REGPARM (sym->etype)))
continue;
if (BTREE_STACK)
{
/* Remove them all, and let btree_alloc() below put them back in more efficiently. */
currFunc->stack -= size;
SPEC_STAK (currFunc->etype) -= size;
if(IS_AGGREGATE (sym->type) || sym->allocreq)
btree_add_symbol (sym);
}
/* Do it the old way - compared to the btree approach we waste space when allocating
variables that had their address taken, unions and aggregates. */
else
{
/* if allocation not required then subtract
size from overall stack size & continue */
if (!IS_AGGREGATE (sym->type) && !sym->allocreq)
{
currFunc->stack -= size;
SPEC_STAK (currFunc->etype) -= size;
continue;
}
if (port->stack.direction > 0)
{
SPEC_STAK (sym->etype) = sym->stack = (sPtr + 1);
sPtr += size;
}
else
{
sPtr -= size;
SPEC_STAK (sym->etype) = sym->stack = sPtr;
}
}
}
if (BTREE_STACK && elementsInSet (istack->syms))
{
btree_alloc ();
btree_clear ();
}
/* do the same for the external stack */
if (!xstack)
return;
for (sym = setFirstItem (xstack->syms); sym; sym = setNextItem (xstack->syms))
{
int size = getSize (sym->type);
/* nothing to do with parameters so continue */
if ((sym->_isparm && !IS_REGPARM (sym->etype)))
continue;
if (IS_AGGREGATE (sym->type))
{
SPEC_STAK (sym->etype) = sym->stack = (xsPtr + 1);
xsPtr += size;
continue;
}
/* if allocation not required then subtract
size from overall stack size & continue */
if (!sym->allocreq)
{
currFunc->xstack -= size;
SPEC_STAK (currFunc->etype) -= size;
continue;
}
SPEC_STAK (sym->etype) = sym->stack = (xsPtr + 1);
xsPtr += size;
}
}
#define SP_BP(sp, bp) (options.omitFramePtr ? sp : bp)
#define SYM_BP(sym) (SPEC_OCLS (sym->etype)->paged ? SP_BP("_spx", "_bpx") : SP_BP("sp", "_bp"))
/*-----------------------------------------------------------------*/
/* printAllocInfoSeg- print the allocation for a given section */
/*-----------------------------------------------------------------*/
static int
printAllocInfoSeg (memmap * map, symbol * func, struct dbuf_s *oBuf)
{
symbol *sym;
int flg = FALSE;
if (!map || !map->syms)
return 0;
for (sym = setFirstItem (map->syms); sym;
sym = setNextItem (map->syms))
{
if (sym->level == 0)
continue;
if (sym->localof != func)
continue;
dbuf_printf (oBuf, ";%-25s Allocated ", sym->name);
flg = TRUE;
/* if assigned to registers */
if (!sym->allocreq && sym->reqv)
{
int i;
sym = OP_SYMBOL (sym->reqv);
if (!sym->isspilt || sym->remat)
{
dbuf_append_str (oBuf, "to registers ");
for (i = 0; i < 4 && sym->regs[i]; i++)
dbuf_printf (oBuf, "%s ", port->getRegName (sym->regs[i]));
dbuf_append_char (oBuf, '\n');
continue;
}
else
{
sym = sym->usl.spillLoc;
}
}
/* if on stack */
if (sym->onStack)
{
int stack_offset = 0;
if (options.omitFramePtr)
{
if (SPEC_OCLS (sym->etype)->paged)
stack_offset = func->xstack;
else
stack_offset = func->stack;
}
stack_offset += port->stack.offset; /* in case sp/bp points to the next location instead of last */
if (port->stack.direction < 0)
stack_offset = -stack_offset;
dbuf_printf (oBuf, "to stack - %s %+d\n", SYM_BP (sym), sym->stack - stack_offset);
continue;
}
/* otherwise give rname */
dbuf_printf (oBuf, "with name '%s'\n", sym->rname);
}
return flg;
}
/*-----------------------------------------------------------------*/
/* canOverlayLocals - returns true if the local variables can overlayed */
/*-----------------------------------------------------------------*/
static bool
canOverlayLocals (eBBlock ** ebbs, int count)
{
int i;
/* if staticAuto is in effect or the current function
being compiled is reentrant or the overlay segment
is empty or no overlay option is in effect then */
if (options.noOverlay ||
options.stackAuto ||
(currFunc &&
(IFFUNC_ISREENT (currFunc->type) ||
FUNC_ISISR (currFunc->type))) ||
elementsInSet (overlay->syms) == 0)
{
return FALSE;
}
/* if this is a forces overlay */
if (IFFUNC_ISOVERLAY(currFunc->type)) return TRUE;
/* otherwise do thru the blocks and see if there
any function calls if found then return false */
for (i = 0; i < count; i++)
{
iCode *ic;
for (ic = ebbs[i]->sch; ic; ic = ic->next)
if (ic)
{
if (ic->op == CALL)
{
sym_link *ftype = operandType(IC_LEFT(ic));
/* builtins only can use overlays */
if (!IFFUNC_ISBUILTIN(ftype)) return FALSE;
}
else if (ic->op == PCALL)
{
return FALSE;
}
}
}
/* no function calls found return TRUE */
return TRUE;
}
/*-----------------------------------------------------------------*/
/* doOverlays - move the overlay segment to appropriate location */
/*-----------------------------------------------------------------*/
void
doOverlays (eBBlock ** ebbs, int count)
{
if (!overlay)
return;
/* check if the parameters and local variables
of this function can be put in the overlay segment
This check is essentially to see if the function
calls any other functions if yes then we cannot
overlay */
if (canOverlayLocals (ebbs, count))
/* if we can then put the parameters &
local variables in the overlay set */
overlay2Set ();
else
/* otherwise put them into data where
they belong */
overlay2data ();
}
/*-----------------------------------------------------------------*/
/* printAllocInfo - prints allocation information for a function */
/*-----------------------------------------------------------------*/
void
printAllocInfo (symbol * func, struct dbuf_s * oBuf)
{
#define BREAKLINE ";------------------------------------------------------------\n"
int cnt = 0;
set *ovrset;
set *tempOverlaySyms;
if (!func)
return;
/* must be called after register allocation is complete */
dbuf_append_str (oBuf, BREAKLINE);
dbuf_printf (oBuf, ";Allocation info for local variables in function '%s'\n", func->name);
dbuf_append_str (oBuf, BREAKLINE);
cnt += printAllocInfoSeg (xstack, func, oBuf);
cnt += printAllocInfoSeg (istack, func, oBuf);
cnt += printAllocInfoSeg (code, func, oBuf);
cnt += printAllocInfoSeg (data, func, oBuf);
cnt += printAllocInfoSeg (xdata, func, oBuf);
cnt += printAllocInfoSeg (idata, func, oBuf);
cnt += printAllocInfoSeg (sfr, func, oBuf);
cnt += printAllocInfoSeg (sfrbit, func, oBuf);
tempOverlaySyms = overlay->syms;
/* search the set of overlay sets for local variables/parameters */
for (ovrset = setFirstItem (ovrSetSets); ovrset;
ovrset = setNextItem (ovrSetSets))
{
overlay->syms = ovrset;
cnt += printAllocInfoSeg (overlay, func, oBuf);
}
overlay->syms = tempOverlaySyms;
if (cnt)
dbuf_append_str (oBuf, BREAKLINE);
}