]> git.sur5r.net Git - cc65/blob - src/cc65/locals.c
New long option --static-locals
[cc65] / src / cc65 / locals.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 locals.c                                  */
4 /*                                                                           */
5 /*              Local variable handling for the cc65 C compiler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000     Ullrich von Bassewitz                                        */
10 /*              Wacholderweg 14                                              */
11 /*              D-70597 Stuttgart                                            */
12 /* EMail:       uz@musoftware.de                                             */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include "../common/xmalloc.h"
37
38 #include "anonname.h"
39 #include "asmlabel.h"
40 #include "codegen.h"
41 #include "declare.h"
42 #include "expr.h"
43 #include "function.h"
44 #include "global.h"
45 #include "symtab.h"
46 #include "locals.h"
47
48
49
50 /*****************************************************************************/
51 /*                                   Data                                    */
52 /*****************************************************************************/
53
54
55
56 /* Register variable management */
57 unsigned MaxRegSpace            = 6;    /* Maximum space available */
58 static unsigned RegOffs         = 0;    /* Offset into register space */
59 static const SymEntry** RegSyms = 0;    /* The register variables */
60 static unsigned RegSymCount     = 0;    /* Number of register variables */
61
62
63
64 /*****************************************************************************/
65 /*                                   Code                                    */
66 /*****************************************************************************/
67
68
69
70 void InitRegVars (void)
71 /* Initialize register variable control data */
72 {
73     /* If the register space is zero, bail out */
74     if (MaxRegSpace == 0) {
75         return;
76     }
77
78     /* The maximum number of register variables is equal to the register
79      * variable space available. So allocate one pointer per byte. This
80      * will usually waste some space but we don't need to dynamically
81      * grow the array.
82      */
83     RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
84     RegOffs = MaxRegSpace;
85 }
86
87
88
89 void DoneRegVars (void)
90 /* Free the register variables */
91 {
92     xfree (RegSyms);
93     RegSyms = 0;
94     RegOffs = MaxRegSpace;
95     RegSymCount = 0;
96 }
97
98
99
100 static int AllocRegVar (const SymEntry* Sym, const type* tarray)
101 /* Allocate a register variable with the given amount of storage. If the
102  * allocation was successful, return the offset of the register variable in
103  * the register bank (zero page storage). If there is no register space left,
104  * return -1.
105  */
106 {
107     /* Maybe register variables are disabled... */
108     if (EnableRegVars) {
109
110         /* Get the size of the variable */
111         unsigned Size = SizeOf (tarray);
112
113         /* Do we have space left? */
114         if (RegOffs >= Size) {
115
116             /* Space left. We allocate the variables from high to low addresses,
117              * so the adressing is compatible with the saved values on stack.
118              * This allows shorter code when saving/restoring the variables.
119              */
120             RegOffs -= Size;
121             RegSyms [RegSymCount++] = Sym;
122             return RegOffs;
123         }
124     }
125
126     /* No space left or no allocation */
127     return -1;
128 }
129
130
131
132 void DeclareLocals (void)
133 /* Declare local variables and types. */
134 {
135     int offs = oursp;           /* Current stack offset for variable */
136     int AutoSpace = 0;          /* Unallocated space on the stack */
137     int Size;                   /* Size of an auto variable */
138     int Reg;                    /* Register variable offset */
139     unsigned flags = 0;         /* Code generator flags */
140     int SymbolSC;               /* Storage class for symbol */
141     int ldata = 0;              /* Local symbol data temp storage */
142
143     /* Loop until we don't find any more variables */
144     while (1) {
145
146         /* Check variable declarations. We need to distinguish between a
147          * default int type and the end of variable declarations. So we
148          * will do the following: If there is no explicit storage class
149          * specifier *and* no explicit type given, it is assume that we
150          * have reached the end of declarations.
151          */
152         DeclSpec Spec;
153         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
154         if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
155             break;
156         }
157
158         /* Accept type only declarations */
159         if (curtok == TOK_SEMI) {
160             /* Type declaration only */
161             CheckEmptyDecl (&Spec);
162             NextToken ();
163             continue;
164         }
165
166         /* Parse a comma separated variable list */
167         while (1) {
168
169             Declaration Decl;
170
171             /* Remember the storage class for the new symbol */
172             SymbolSC = Spec.StorageClass;
173
174             /* Read the declaration */
175             ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
176
177             /* If we don't have a name, this was flagged as an error earlier.
178              * To avoid problems later, use an anonymous name here.
179              */
180             if (Decl.Ident[0] == '\0') {
181                 AnonName (Decl.Ident, "param");
182             }
183
184             if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) {
185
186                 /* Get the size of the variable */
187                 Size = SizeOf (Decl.Type);
188
189 #if 0
190                 /* Check the storage class */
191                 if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) {
192
193                     /* We will store the current value of the register onto the
194                      * stack, thus making functions with register variables
195                      * reentrant. If we have pending auto variables, emit them
196                      * now.
197                      */
198                     g_usecode ();
199                     g_space (AutoSpace);
200                     oursp -= AutoSpace;
201                     AutoSpace = 0;
202
203                     /* Remember the register bank offset */
204                     ldata = Reg;
205
206                     /* Save the current register value onto the stack */
207                     g_save_regvars (Reg, Size);
208
209                     /* Allow variable initialization */
210                     if (curtok == TOK_ASSIGN) {
211
212                         struct expent lval;
213
214                         /* Skip the '=' */
215                         NextToken ();
216
217                         /* Get the expression into the primary */
218                         expression1 (&lval);
219
220                         /* Make type adjustments if needed */
221                         assignadjust (tarray, &lval);
222
223                         /* Setup the type flags for the assignment */
224                         flags = TypeOf (tarray) | CF_REGVAR;
225                         if (Size == 1) {
226                             flags |= CF_FORCECHAR;
227                         }
228
229                         /* Store the value into the register */
230                         g_putstatic (flags, Reg, 0);
231
232                         /* Mark the variable as referenced */
233                         SymbolSC |= SC_REF;
234
235                     }
236
237                     /* Account for the stack space needed and remember the
238                      * stack offset of the save area.
239                      */
240                     offs -= Size;
241                     psym->h_lattr = offs;
242
243                 } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
244 #endif
245                 if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
246
247                     /* Auto variable */
248                     if (StaticLocals == 0) {
249
250                         /* Change SC in case it was register */
251                         SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
252                         if (curtok == TOK_ASSIGN) {
253
254                             struct expent lval;
255
256                             /* Switch to the code segment, allocate space for
257                              * uninitialized variables.
258                              */
259                             g_usecode ();
260                             g_space (AutoSpace);
261                             oursp -= AutoSpace;
262                             AutoSpace = 0;
263
264                             /* Skip the '=' */
265                             NextToken ();
266
267                             /* Setup the type flags for the assignment */
268                             flags = Size == 1? CF_FORCECHAR : CF_NONE;
269
270                             /* Get the expression into the primary */
271                             if (evalexpr (flags, hie1, &lval) == 0) {
272                                 /* Constant expression. Adjust the types */
273                                 assignadjust (Decl.Type, &lval);
274                                 flags |= CF_CONST;
275                             } else {
276                                 /* Expression is not constant and in the primary */
277                                 assignadjust (Decl.Type, &lval);
278                             }
279
280                             /* Push the value */
281                             g_push (flags | TypeOf (Decl.Type), lval.e_const);
282
283                             /* Mark the variable as referenced */
284                             SymbolSC |= SC_REF;
285
286                         } else {
287                             /* Non-initialized local variable. Just keep track of
288                              * the space needed.
289                              */
290                             AutoSpace += Size;
291                         }
292
293                         /* Allocate space on the stack, assign the offset */
294                         offs -= Size;
295                         ldata = offs;
296
297                     } else {
298
299                         /* Static local variables. */
300                         SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
301
302                         /* Put them into the BSS */
303                         g_usebss ();
304
305                         /* Define the variable label */
306                         g_defloclabel (ldata = GetLabel ());
307
308                         /* Reserve space for the data */
309                         g_res (Size);
310
311                         /* Allow assignments */
312                         if (curtok == TOK_ASSIGN) {
313
314                             struct expent lval;
315
316                             /* Switch to the code segment. */
317                             g_usecode ();
318
319                             /* Skip the '=' */
320                             NextToken ();
321
322                             /* Get the expression into the primary */
323                             expression1 (&lval);
324
325                             /* Make type adjustments if needed */
326                             assignadjust (Decl.Type, &lval);
327
328                             /* Setup the type flags for the assignment */
329                             flags = TypeOf (Decl.Type);
330                             if (Size == 1) {
331                                 flags |= CF_FORCECHAR;
332                             }
333
334                             /* Store the value into the variable */
335                             g_putstatic (flags, ldata, 0);
336
337                             /* Mark the variable as referenced */
338                             SymbolSC |= SC_REF;
339                         }
340                     }
341
342                 } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
343
344                     /* Static data */
345                     if (curtok == TOK_ASSIGN) {
346
347                         /* Initialization ahead, switch to data segment */
348                         g_usedata ();
349
350                         /* Define the variable label */
351                         g_defloclabel (ldata = GetLabel ());
352
353                         /* Skip the '=' */
354                         NextToken ();
355
356                         /* Allow initialization of static vars */
357                         ParseInit (Decl.Type);
358
359                         /* Mark the variable as referenced */
360                         SymbolSC |= SC_REF;
361
362                     } else {
363
364                         /* Uninitialized data, use BSS segment */
365                         g_usebss ();
366
367                         /* Define the variable label */
368                         g_defloclabel (ldata = GetLabel ());
369
370                         /* Reserve space for the data */
371                         g_res (Size);
372
373                     }
374                 }
375
376             }
377
378             /* If the symbol is not marked as external, it will be defined */
379             if ((SymbolSC & SC_EXTERN) == 0) {
380                 SymbolSC |= SC_DEF;
381             }
382
383             /* Add the symbol to the symbol table */
384             AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata);
385
386             if (curtok != TOK_COMMA) {
387                 break;
388             }
389             NextToken ();
390         }
391         if (curtok == TOK_SEMI) {
392             NextToken ();
393         }
394     }
395
396     /* In case we switched away from code segment, switch back now */
397     g_usecode ();
398
399     /* Create space for locals */
400     g_space (AutoSpace);
401     oursp -= AutoSpace;
402 }
403
404
405
406 void RestoreRegVars (int HaveResult)
407 /* Restore the register variables for the local function if there are any.
408  * The parameter tells us if there is a return value in ax, in that case,
409  * the accumulator must be saved across the restore.
410  */
411 {
412     unsigned I, J;
413     int Bytes, Offs;
414
415     /* If we don't have register variables in this function, bail out early */
416     if (RegSymCount == 0) {
417         return;
418     }
419
420     /* Save the accumulator if needed */
421     if (!HasVoidReturn (CurrentFunc) && HaveResult) {
422         g_save (CF_CHAR | CF_FORCECHAR);
423     }
424
425     /* Walk through all variables. If there are several variables in a row
426      * (that is, with increasing stack offset), restore them in one chunk.
427      */
428     I = 0;
429     while (I < RegSymCount) {
430
431         /* Check for more than one variable */
432         const SymEntry* Sym = RegSyms[I];
433         Offs  = Sym->V.Offs;
434         Bytes = SizeOf (Sym->Type);
435         J = I+1;
436
437         while (J < RegSymCount) {
438
439             /* Get the next symbol */
440             const SymEntry* NextSym = RegSyms [J];
441
442             /* Get the size */
443             int Size = SizeOf (NextSym->Type);
444
445             /* Adjacent variable? */
446             if (NextSym->V.Offs + Size != Offs) {
447                 /* No */
448                 break;
449             }
450
451             /* Adjacent variable */
452             Bytes += Size;
453             Offs  -= Size;
454             Sym   = NextSym;
455             ++J;
456         }
457
458         /* Restore the memory range */
459         g_restore_regvars (Offs, Sym->V.Offs, Bytes);
460
461         /* Next round */
462         I = J;
463     }
464
465     /* Restore the accumulator if needed */
466     if (!HasVoidReturn (CurrentFunc) && HaveResult) {
467         g_restore (CF_CHAR | CF_FORCECHAR);
468     }
469 }
470
471
472