diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCmem.c | |
| download | sdcc-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.c | 1353 |
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); +} |
