1354 lines
41 KiB
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);
|
|
}
|