summaryrefslogtreecommitdiff
path: root/src/SDCCmem.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCmem.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCmem.c')
-rw-r--r--src/SDCCmem.c1353
1 files changed, 1353 insertions, 0 deletions
diff --git a/src/SDCCmem.c b/src/SDCCmem.c
new file mode 100644
index 0000000..550ee38
--- /dev/null
+++ b/src/SDCCmem.c
@@ -0,0 +1,1353 @@
+/*-------------------------------------------------------------------------
+ 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);
+}