X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Flocals.c;h=710d05e33a34a7442bbaee93f432246fd2c08378;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=ad87c3ebd75006b1ee87ffa7fdbc37e7e251533a;hpb=ede471904c740b4f58112f7101beccfbc41571fe;p=cc65 diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ad87c3ebd..710d05e33 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000-2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@cc65.org */ +/* (C) 2000-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -46,22 +46,12 @@ #include "expr.h" #include "function.h" #include "global.h" -#include "symtab.h" +#include "loadexpr.h" #include "locals.h" - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Register variable management */ -unsigned MaxRegSpace = 6; /* Maximum space available */ -static unsigned RegOffs = 0; /* Offset into register space */ -static const SymEntry** RegSyms = 0; /* The register variables */ -static unsigned RegSymCount = 0; /* Number of register variables */ +#include "stackptr.h" +#include "standard.h" +#include "symtab.h" +#include "typeconv.h" @@ -71,69 +61,37 @@ static unsigned RegSymCount = 0; /* Number of register variables */ -void InitRegVars (void) -/* Initialize register variable control data */ +static unsigned AllocLabel (void (*UseSeg) ()) +/* Switch to a segment, define a local label and return it */ { - /* If the register space is zero, bail out */ - if (MaxRegSpace == 0) { - return; - } + unsigned Label; - /* The maximum number of register variables is equal to the register - * variable space available. So allocate one pointer per byte. This - * will usually waste some space but we don't need to dynamically - * grow the array. - */ - RegSyms = (const SymEntry**) xmalloc (MaxRegSpace * sizeof (RegSyms[0])); - RegOffs = MaxRegSpace; -} + /* Switch to the segment */ + UseSeg (); + /* Define the variable label */ + Label = GetLocalLabel (); + g_defdatalabel (Label); - -void DoneRegVars (void) -/* Free the register variables */ -{ - xfree (RegSyms); - RegSyms = 0; - RegOffs = MaxRegSpace; - RegSymCount = 0; + /* Return the label */ + return Label; } -static int AllocRegVar (const type* Type) -/* Allocate a register variable for the given variable type. If the allocation - * was successful, return the offset of the register variable in the register - * bank (zero page storage). If there is no register space left, return -1. +static unsigned AllocStorage (void (*UseSeg) (), unsigned Size) +/* Reserve Size bytes of BSS storage prefixed by a local label. Return the + * label. */ { - /* Maybe register variables are disabled... */ - if (EnableRegVars) { - - /* Get the size of the variable */ - unsigned Size = CheckedSizeOf (Type); - - /* Do we have space left? */ - if (RegOffs >= Size) { - /* Space left. We allocate the variables from high to low addresses, - * so the adressing is compatible with the saved values on stack. - * This allows shorter code when saving/restoring the variables. - */ - RegOffs -= Size; - return RegOffs; - } - } - - /* No space left or no allocation */ - return -1; -} - + /* Switch to the segment and define the label */ + unsigned Label = AllocLabel (UseSeg); + /* Reserve space for the data */ + g_res (Size); -static void RememberRegVar (const SymEntry* Sym) -/* Remember the given register variable */ -{ - RegSyms[RegSymCount++] = Sym; + /* Return the label */ + return Label; } @@ -143,7 +101,6 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) * symbol data, which is the offset of the variable in the register bank. */ { - unsigned Flags; unsigned InitLabel; /* Determine if this is a compound variable */ @@ -159,7 +116,7 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) /* Check for an optional initialization */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc lval; + ExprDesc Expr; /* Skip the '=' */ NextToken (); @@ -167,41 +124,39 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) /* Special handling for compound types */ if (IsCompound) { - /* Switch to read only data */ - g_userodata (); - - /* Define a label for the initialization data */ - InitLabel = GetLocalLabel (); - g_defdatalabel (InitLabel); + /* Switch to read only data and define a label for the + * initialization data. + */ + InitLabel = AllocLabel (g_userodata); /* Parse the initialization generating a memory image of the - * data in the RODATA segment. + * data in the RODATA segment. The function does return the size + * of the initialization data, which may be greater than the + * actual size of the type, if the type is a structure with a + * flexible array member that has been initialized. Since we must + * know the size of the data in advance for register variables, + * we cannot allow that here. */ - ParseInit (Decl->Type); + if (ParseInit (Decl->Type) != Size) { + Error ("Cannot initialize flexible array members of storage class `register'"); + } /* Generate code to copy this data into the variable space */ g_initregister (InitLabel, Reg, Size); } else { - /* Setup the type flags for the assignment */ - Flags = CF_REGVAR; - if (Size == SIZEOF_CHAR) { - Flags |= CF_FORCECHAR; - } + /* Parse the expression */ + hie1 (&Expr); - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); - Flags |= CF_CONST; - } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); - } + /* Convert it to the target type */ + TypeConversion (&Expr, Decl->Type); + + /* Load the value into the primary */ + LoadExpr (CF_NONE, &Expr); /* Store the value into the variable */ - g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0); + g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0); } @@ -228,7 +183,6 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) { unsigned Flags; unsigned SymData; - unsigned InitLabel; /* Determine if this is a compound variable */ int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type); @@ -237,12 +191,12 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) unsigned Size = SizeOf (Decl->Type); /* Check if this is a variable on the stack or in static memory */ - if (StaticLocals == 0) { + if (IS_Get (&StaticLocals) == 0) { /* Check for an optional initialization */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc lval; + ExprDesc Expr; /* Skip the '=' */ NextToken (); @@ -250,7 +204,21 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) /* Special handling for compound types */ if (IsCompound) { - /* First reserve space for the variable */ + /* Switch to read only data and define a label for the + * initialization data. + */ + unsigned InitLabel = AllocLabel (g_userodata); + + /* Parse the initialization generating a memory image of the + * data in the RODATA segment. The function will return the + * actual size of the initialization data, which may be + * greater than the size of the variable if it is a struct + * that contains a flexible array member and we're not in + * ANSI mode. + */ + Size = ParseInit (Decl->Type); + + /* Now reserve space for the variable on the stack */ SymData = F_ReserveLocalSpace (CurrentFunc, Size); /* Next, allocate the space on the stack. This means that the @@ -258,19 +226,9 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) */ F_AllocLocalSpace (CurrentFunc); - /* Switch to read only data */ - g_userodata (); - - /* Define a label for the initialization data */ - InitLabel = GetLocalLabel (); - g_defdatalabel (InitLabel); - - /* Parse the initialization generating a memory image of the - * data in the RODATA segment. + /* Generate code to copy the initialization data into the + * variable space */ - ParseInit (Decl->Type); - - /* Generate code to copy this data into the variable space */ g_initauto (InitLabel, Size); } else { @@ -281,18 +239,24 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) /* Setup the type flags for the assignment */ Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE; - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); + /* Parse the expression */ + hie1 (&Expr); + + /* Convert it to the target type */ + TypeConversion (&Expr, Decl->Type); + + /* If the value is not const, load it into the primary. + * Otherwise pass the information to the code generator. + */ + if (ED_IsConstAbsInt (&Expr)) { Flags |= CF_CONST; } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); + LoadExpr (CF_NONE, &Expr); + ED_MakeRVal (&Expr); } /* Push the value */ - g_push (Flags | TypeOf (Decl->Type), lval.ConstVal); + g_push (Flags | TypeOf (Decl->Type), Expr.IVal); } @@ -300,7 +264,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) *SC |= SC_REF; /* Variable is located at the current SP */ - SymData = oursp; + SymData = StackPtr; } else { /* Non-initialized local variable. Just keep track of @@ -314,65 +278,58 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) /* Static local variables. */ *SC = (*SC & ~SC_AUTO) | SC_STATIC; - /* Put them into the BSS */ - g_usebss (); - - /* Define the variable label */ - SymData = GetLocalLabel (); - g_defdatalabel (SymData); - - /* Reserve space for the data */ - g_res (Size); - /* Allow assignments */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc lval; + ExprDesc Expr; /* Skip the '=' */ NextToken (); if (IsCompound) { - /* Switch to read only data */ - g_userodata (); - - /* Define a label for the initialization data */ - InitLabel = GetLocalLabel (); - g_defdatalabel (InitLabel); + /* Switch to read only data and define a label for the + * initialization data. + */ + unsigned InitLabel = AllocLabel (g_userodata); /* Parse the initialization generating a memory image of the * data in the RODATA segment. */ - ParseInit (Decl->Type); + Size = ParseInit (Decl->Type); + + /* Allocate a label and space for the variable */ + SymData = AllocStorage (g_usebss, Size); /* Generate code to copy this data into the variable space */ g_initstatic (InitLabel, SymData, Size); } else { - /* Setup the type flags for the assignment */ - Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE; + /* Allocate a label and space for the variable */ + SymData = AllocStorage (g_usebss, Size); - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); - Flags |= CF_CONST; - /* Load it into the primary */ - exprhs (Flags, 0, &lval); - } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); - } + /* Parse the expression */ + hie1 (&Expr); - /* Store the value into the variable */ - g_putstatic (Flags | TypeOf (Decl->Type), SymData, 0); + /* Convert it to the target type */ + TypeConversion (&Expr, Decl->Type); + + /* Load the value into the primary */ + LoadExpr (CF_NONE, &Expr); + /* Store the value into the variable */ + g_putstatic (TypeOf (Decl->Type), SymData, 0); } /* Mark the variable as referenced */ *SC |= SC_REF; + + } else { + + /* No assignment - allocate a label and space for the variable */ + SymData = AllocStorage (g_usebss, Size); + } } @@ -393,49 +350,38 @@ static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC) */ { unsigned SymData; - - /* Get the size of the variable */ - unsigned Size = SizeOf (Decl->Type); + unsigned Size; /* Static data */ if (CurTok.Tok == TOK_ASSIGN) { - /* Initialization ahead, switch to data segment */ - if (IsQualConst (Decl->Type)) { - g_userodata (); + /* Initialization ahead, switch to data segment and define a label. + * For arrays, we need to check the elements of the array for + * constness, not the array itself. + */ + if (IsQualConst (Decl->Type) || + (IsTypeArray (Decl->Type) && IsQualConst (GetElementType (Decl->Type)))) { + SymData = AllocLabel (g_userodata); } else { - g_usedata (); + SymData = AllocLabel (g_usedata); } - /* Define the variable label */ - SymData = GetLocalLabel (); - g_defdatalabel (SymData); - /* Skip the '=' */ NextToken (); /* Allow initialization of static vars */ - ParseInit (Decl->Type); - - /* If the previous size has been unknown, it must be known now */ - if (Size == 0) { - Size = SizeOf (Decl->Type); - } + Size = ParseInit (Decl->Type); /* Mark the variable as referenced */ *SC |= SC_REF; } else { - /* Uninitialized data, use BSS segment */ - g_usebss (); + /* Get the size of the variable */ + Size = SizeOf (Decl->Type); - /* Define the variable label */ - SymData = GetLocalLabel (); - g_defdatalabel (SymData); - - /* Reserve space for the data */ - g_res (Size); + /* Allocate a label and space for the variable in the BSS segment */ + SymData = AllocStorage (g_usebss, Size); } @@ -453,26 +399,20 @@ static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC) static void ParseOneDecl (const DeclSpec* Spec) /* Parse one variable declaration */ { - unsigned SC; /* Storage class for symbol */ unsigned SymData = 0; /* Symbol data (offset, label name, ...) */ Declaration Decl; /* Declaration data structure */ - SymEntry* Sym; /* Symbol declared */ - - /* Remember the storage class for the new symbol */ - SC = Spec->StorageClass; /* Read the declaration */ ParseDecl (Spec, &Decl, DM_NEED_IDENT); /* Set the correct storage class for functions */ - if (IsTypeFunc (Decl.Type)) { - /* Function prototypes are always external */ - if ((SC & SC_EXTERN) == 0) { + if ((Decl.StorageClass & SC_FUNC) == SC_FUNC) { + /* Function prototypes are always external */ + if ((Decl.StorageClass & SC_EXTERN) == 0) { Warning ("Function must be extern"); - } - SC |= SC_FUNC | SC_EXTERN; - + } + Decl.StorageClass |= SC_EXTERN; } /* If we don't have a name, this was flagged as an error earlier. @@ -483,44 +423,47 @@ static void ParseOneDecl (const DeclSpec* Spec) } /* Handle anything that needs storage (no functions, no typdefs) */ - if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) { + if ((Decl.StorageClass & SC_FUNC) != SC_FUNC && + (Decl.StorageClass & SC_TYPEDEF) != SC_TYPEDEF) { /* If we have a register variable, try to allocate a register and * convert the declaration to "auto" if this is not possible. */ int Reg = 0; /* Initialize to avoid gcc complains */ - if ((SC & SC_REGISTER) != 0 && (Reg = AllocRegVar (Decl.Type)) < 0) { + if ((Decl.StorageClass & SC_REGISTER) != 0 && + (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) { /* No space for this register variable, convert to auto */ - SC = (SC & ~SC_REGISTER) | SC_AUTO; + Decl.StorageClass = (Decl.StorageClass & ~SC_REGISTER) | SC_AUTO; } /* Check the variable type */ - if (SC & SC_REGISTER) { + if ((Decl.StorageClass & SC_REGISTER) == SC_REGISTER) { /* Register variable */ - SymData = ParseRegisterDecl (&Decl, &SC, Reg); - } else if (SC & SC_AUTO) { + SymData = ParseRegisterDecl (&Decl, &Decl.StorageClass, Reg); + } else if ((Decl.StorageClass & SC_AUTO) == SC_AUTO) { /* Auto variable */ - SymData = ParseAutoDecl (&Decl, &SC); - } else if (SC & SC_STATIC) { + SymData = ParseAutoDecl (&Decl, &Decl.StorageClass); + } else if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN) { + /* External identifier - may not get initialized */ + if (CurTok.Tok == TOK_ASSIGN) { + Error ("Cannot initialize externals"); + } + SymData = 0; + } else if ((Decl.StorageClass & SC_STATIC) == SC_STATIC) { /* Static variable */ - SymData = ParseStaticDecl (&Decl, &SC); + SymData = ParseStaticDecl (&Decl, &Decl.StorageClass); } else { - Internal ("Invalid storage class in ParseOneDecl: %04X", SC); + Internal ("Invalid storage class in ParseOneDecl: %04X", Decl.StorageClass); } } /* If the symbol is not marked as external, it will be defined now */ - if ((SC & SC_EXTERN) == 0) { - SC |= SC_DEF; + if ((Decl.StorageClass & SC_EXTERN) == 0) { + Decl.StorageClass |= SC_DEF; } /* Add the symbol to the symbol table */ - Sym = AddLocalSym (Decl.Ident, Decl.Type, SC, SymData); - - /* If we had declared a register variable, remember it now */ - if (SC & SC_REGISTER) { - RememberRegVar (Sym); - } + AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, SymData); } @@ -529,40 +472,43 @@ void DeclareLocals (void) /* Declare local variables and types. */ { /* Remember the current stack pointer */ - int InitialStack = oursp; + int InitialStack = StackPtr; /* Loop until we don't find any more variables */ while (1) { - /* Check variable declarations. We need to distinguish between a - * default int type and the end of variable declarations. So we - * will do the following: If there is no explicit storage class - * specifier *and* no explicit type given, it is assume that we - * have reached the end of declarations. - */ - DeclSpec Spec; - ParseDeclSpec (&Spec, SC_AUTO, T_INT); - if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) { - break; - } - - /* Accept type only declarations */ - if (CurTok.Tok == TOK_SEMI) { - /* Type declaration only */ - CheckEmptyDecl (&Spec); - NextToken (); - continue; - } + /* Check variable declarations. We need to distinguish between a + * default int type and the end of variable declarations. So we + * will do the following: If there is no explicit storage class + * specifier *and* no explicit type given, *and* no type qualifiers + * have been read, it is assumed that we have reached the end of + * declarations. + */ + DeclSpec Spec; + ParseDeclSpec (&Spec, SC_AUTO, T_INT); + if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */ + (Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */ + GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */ + break; + } + + /* Accept type only declarations */ + if (CurTok.Tok == TOK_SEMI) { + /* Type declaration only */ + CheckEmptyDecl (&Spec); + NextToken (); + continue; + } /* Parse a comma separated variable list */ while (1) { - /* Parse one declaration */ - ParseOneDecl (&Spec); + /* Parse one declaration */ + ParseOneDecl (&Spec); - /* Check if there is more */ + /* Check if there is more */ if (CurTok.Tok == TOK_COMMA) { - /* More to come */ + /* More to come */ NextToken (); } else { /* Done */ @@ -580,77 +526,10 @@ void DeclareLocals (void) /* In case we've allocated local variables in this block, emit a call to * the stack checking routine if stack checks are enabled. */ - if (CheckStack && InitialStack != oursp) { + if (IS_Get (&CheckStack) && InitialStack != StackPtr) { g_cstackcheck (); } } -void RestoreRegVars (int HaveResult) -/* Restore the register variables for the local function if there are any. - * The parameter tells us if there is a return value in ax, in that case, - * the accumulator must be saved across the restore. - */ -{ - unsigned I, J; - int Bytes, Offs; - - /* If we don't have register variables in this function, bail out early */ - if (RegSymCount == 0) { - return; - } - - /* Save the accumulator if needed */ - if (!F_HasVoidReturn (CurrentFunc) && HaveResult) { - g_save (CF_CHAR | CF_FORCECHAR); - } - - /* Walk through all variables. If there are several variables in a row - * (that is, with increasing stack offset), restore them in one chunk. - */ - I = 0; - while (I < RegSymCount) { - - /* Check for more than one variable */ - const SymEntry* Sym = RegSyms[I]; - Offs = Sym->V.R.SaveOffs; - Bytes = CheckedSizeOf (Sym->Type); - J = I+1; - - while (J < RegSymCount) { - - /* Get the next symbol */ - const SymEntry* NextSym = RegSyms [J]; - - /* Get the size */ - int Size = CheckedSizeOf (NextSym->Type); - - /* Adjacent variable? */ - if (NextSym->V.R.SaveOffs + Size != Offs) { - /* No */ - break; - } - - /* Adjacent variable */ - Bytes += Size; - Offs -= Size; - Sym = NextSym; - ++J; - } - - /* Restore the memory range */ - g_restore_regvars (Offs, Sym->V.R.RegOffs, Bytes); - - /* Next round */ - I = J; - } - - /* Restore the accumulator if needed */ - if (!F_HasVoidReturn (CurrentFunc) && HaveResult) { - g_restore (CF_CHAR | CF_FORCECHAR); - } -} - - -