1 /*****************************************************************************/
5 /* Local variable handling for the cc65 C compiler */
9 /* (C) 2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
53 /*****************************************************************************/
55 /*****************************************************************************/
59 /* Register variable management */
60 unsigned MaxRegSpace = 6; /* Maximum space available */
61 static unsigned RegOffs = 0; /* Offset into register space */
62 static const SymEntry** RegSyms = 0; /* The register variables */
63 static unsigned RegSymCount = 0; /* Number of register variables */
67 /*****************************************************************************/
69 /*****************************************************************************/
73 void InitRegVars (void)
74 /* Initialize register variable control data */
76 /* If the register space is zero, bail out */
77 if (MaxRegSpace == 0) {
81 /* The maximum number of register variables is equal to the register
82 * variable space available. So allocate one pointer per byte. This
83 * will usually waste some space but we don't need to dynamically
86 RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
87 RegOffs = MaxRegSpace;
92 void DoneRegVars (void)
93 /* Free the register variables */
97 RegOffs = MaxRegSpace;
103 static int AllocRegVar (const SymEntry* Sym, const type* tarray)
104 /* Allocate a register variable with the given amount of storage. If the
105 * allocation was successful, return the offset of the register variable in
106 * the register bank (zero page storage). If there is no register space left,
110 /* Maybe register variables are disabled... */
113 /* Get the size of the variable */
114 unsigned Size = SizeOf (tarray);
116 /* Do we have space left? */
117 if (RegOffs >= Size) {
119 /* Space left. We allocate the variables from high to low addresses,
120 * so the adressing is compatible with the saved values on stack.
121 * This allows shorter code when saving/restoring the variables.
124 RegSyms [RegSymCount++] = Sym;
129 /* No space left or no allocation */
135 static void ParseOneDecl (const DeclSpec* Spec)
136 /* Parse one variable declaration */
138 int Size; /* Size of an auto variable */
139 int SC; /* Storage class for symbol */
140 int SymData = 0; /* Symbol data (offset, label name, ...) */
141 unsigned flags = 0; /* Code generator flags */
142 Declaration Decl; /* Declaration data structure */
144 /* Remember the storage class for the new symbol */
145 SC = Spec->StorageClass;
147 /* Read the declaration */
148 ParseDecl (Spec, &Decl, DM_NEED_IDENT);
150 /* Set the correct storage class for functions */
151 if (IsTypeFunc (Decl.Type)) {
152 /* Function prototypes are always external */
153 if ((SC & SC_EXTERN) == 0) {
154 Warning (WARN_FUNC_MUST_BE_EXTERN);
156 SC |= SC_FUNC | SC_EXTERN;
160 /* If we don't have a name, this was flagged as an error earlier.
161 * To avoid problems later, use an anonymous name here.
163 if (Decl.Ident[0] == '\0') {
164 AnonName (Decl.Ident, "param");
167 /* Handle anything that needs storage (no functions, no typdefs) */
168 if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
170 /* Get the size of the variable */
171 Size = SizeOf (Decl.Type);
173 if (SC & (SC_AUTO | SC_REGISTER)) {
176 if (StaticLocals == 0) {
178 /* Change SC in case it was register */
179 SC = (SC & ~SC_REGISTER) | SC_AUTO;
180 if (curtok == TOK_ASSIGN) {
184 /* Allocate previously reserved local space */
185 AllocLocalSpace (CurrentFunc);
187 /* Switch to the code segment. */
193 /* Setup the type flags for the assignment */
194 flags = Size == 1? CF_FORCECHAR : CF_NONE;
196 /* Get the expression into the primary */
197 if (evalexpr (flags, hie1, &lval) == 0) {
198 /* Constant expression. Adjust the types */
199 assignadjust (Decl.Type, &lval);
202 /* Expression is not constant and in the primary */
203 assignadjust (Decl.Type, &lval);
207 g_push (flags | TypeOf (Decl.Type), lval.e_const);
209 /* Mark the variable as referenced */
212 /* Variable is located at the current SP */
216 /* Non-initialized local variable. Just keep track of
219 SymData = ReserveLocalSpace (CurrentFunc, Size);
224 /* Static local variables. */
225 SC = (SC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
227 /* Put them into the BSS */
230 /* Define the variable label */
231 SymData = GetLabel ();
232 g_defloclabel (SymData);
234 /* Reserve space for the data */
237 /* Allow assignments */
238 if (curtok == TOK_ASSIGN) {
242 /* Switch to the code segment. */
248 /* Get the expression into the primary */
251 /* Make type adjustments if needed */
252 assignadjust (Decl.Type, &lval);
254 /* Setup the type flags for the assignment */
255 flags = TypeOf (Decl.Type);
257 flags |= CF_FORCECHAR;
260 /* Store the value into the variable */
261 g_putstatic (flags, SymData, 0);
263 /* Mark the variable as referenced */
268 } else if ((SC & SC_STATIC) == SC_STATIC) {
271 if (curtok == TOK_ASSIGN) {
273 /* Initialization ahead, switch to data segment */
274 if (IsQualConst (Decl.Type)) {
280 /* Define the variable label */
281 SymData = GetLabel ();
282 g_defloclabel (SymData);
287 /* Allow initialization of static vars */
288 ParseInit (Decl.Type);
290 /* Mark the variable as referenced */
295 /* Uninitialized data, use BSS segment */
298 /* Define the variable label */
299 SymData = GetLabel ();
300 g_defloclabel (SymData);
302 /* Reserve space for the data */
310 /* If the symbol is not marked as external, it will be defined */
311 if ((SC & SC_EXTERN) == 0) {
315 /* Add the symbol to the symbol table */
316 AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
321 void DeclareLocals (void)
322 /* Declare local variables and types. */
324 /* Loop until we don't find any more variables */
327 /* Check variable declarations. We need to distinguish between a
328 * default int type and the end of variable declarations. So we
329 * will do the following: If there is no explicit storage class
330 * specifier *and* no explicit type given, it is assume that we
331 * have reached the end of declarations.
334 ParseDeclSpec (&Spec, SC_AUTO, T_INT);
335 if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
339 /* Accept type only declarations */
340 if (curtok == TOK_SEMI) {
341 /* Type declaration only */
342 CheckEmptyDecl (&Spec);
347 /* Parse a comma separated variable list */
350 /* Parse one declaration */
351 ParseOneDecl (&Spec);
353 /* Check if there is more */
354 if (curtok == TOK_COMMA) {
363 /* A semicolon must follow */
367 /* Be sure to allocate any reserved space for locals */
368 AllocLocalSpace (CurrentFunc);
370 /* In case we switched away from code segment, switch back now */
376 void RestoreRegVars (int HaveResult)
377 /* Restore the register variables for the local function if there are any.
378 * The parameter tells us if there is a return value in ax, in that case,
379 * the accumulator must be saved across the restore.
385 /* If we don't have register variables in this function, bail out early */
386 if (RegSymCount == 0) {
390 /* Save the accumulator if needed */
391 if (!HasVoidReturn (CurrentFunc) && HaveResult) {
392 g_save (CF_CHAR | CF_FORCECHAR);
395 /* Walk through all variables. If there are several variables in a row
396 * (that is, with increasing stack offset), restore them in one chunk.
399 while (I < RegSymCount) {
401 /* Check for more than one variable */
402 const SymEntry* Sym = RegSyms[I];
404 Bytes = SizeOf (Sym->Type);
407 while (J < RegSymCount) {
409 /* Get the next symbol */
410 const SymEntry* NextSym = RegSyms [J];
413 int Size = SizeOf (NextSym->Type);
415 /* Adjacent variable? */
416 if (NextSym->V.Offs + Size != Offs) {
421 /* Adjacent variable */
428 /* Restore the memory range */
429 g_restore_regvars (Offs, Sym->V.Offs, Bytes);
435 /* Restore the accumulator if needed */
436 if (!HasVoidReturn (CurrentFunc) && HaveResult) {
437 g_restore (CF_CHAR | CF_FORCECHAR);