5.4.2.2 Automatic Storage Duration Objects

Objects with automatic storage duration, such as auto, parameter objects, and temporary variables, are typically allocated space on a stack implemented by the compiler.

MPLAB XC8 has two stack implementations: a compiled stack and a software stack (described in Data Stacks). Objects nominated for space on the software stack might be allocated to dynamic working registers to improve efficiency; however, this does not alter the characteristic of the function. Each C function is compiled to use exactly one of these stacks for its automatic storage duration objects and the table below summarizes how the choice of stack affects a function’s reentrancy.

Table 5-7. Function Models Implementation
Data Stack UsedFunction ModelSupported Device Families
Compiled stackNon-reentrantAll devices
Software stack, including working registersReentrantEnhanced Mid-range and PIC18 devices

When compiling for those devices that do not support the reentrant function model, all functions are encoded to use the compiled stack, which are non-reentrant functions. The use of dynamic working registers does not affect the reentrancy of the function.

For the Enhanced Mid-range and PIC18 devices, by default the compiler will use the non-reentrant model for all functions. The -mstack option (see Stack Option) can be used to change the compiler’s default behavior when assigning function models. Select the reentrant argument with this option so that the compiler will always choose the reentrant model (software stack and/or working registers) for each function. Set this option to hybrid to allow the compiler to decide how each function should be encoded, based on the following criteria.

When using the hybrid stack model, the reentrant stack will be used for a function if either the following apply.
  1. The function appears in multiple call graphs
  2. The function is recursive
However, there are limitations with the compiled stack (other than reentrancy) that necessitate that functions with at least one of the following characteristics also use the reentrant model.
  1. The function is a member of a group of buddy functions where more than one of the functions are active at the same time
  2. The function was referenced by assembly code
  3. The function has local optimizations applied

Alternatively you can change the function model for individual functions by using function specifiers when you define the function. Use either the __compiled or __nonreentrant specifier (identical meanings) to indicate that the specified function must use the compiled stack, without affecting any other function. Alternatively, use either the __software or __reentrant specifier to indicate a function must be encoded to use the software stack and/or working registers.

The function specifiers have precedence over the -mstack option setting. If, for example, the option -mstack=compiled has been used, but one function uses the __software (or __reentrant) specifier, then the specified function will use the software stack and/or working registers and all the remaining functions will use the compiled stack. These functions specifiers also override any choice made by the compiler in hybrid mode.

If the -mstack=compiled option has been issued or a function has been specified as __compiled (or __nonreentrant) and that function appears in more than one call graph in the program, then a function duplication feature automatically comes into effect (see Function Duplication). Duplicating a non-reentrant function allows it to be called from multiple call graphs, but cannot allow the function to be called recursively.

The auto objects defined in a function will not necessarily be allocated memory in the order declared, in contrast to parameters which are always allocated memory based on their lexical order. In fact, auto objects for one function can be allocated in many RAM banks.

The standard const qualifier can be used with auto objects and forces them to be read-only. These objects, however, might not be stored on the stack. See Const Auto Objects for how the compiler allocates such objects.