X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Flocals.c;h=9f4c05088740af5ca6dc55dc8d7d1909b58ea1c6;hb=73dfa23c987d8a7f1154801b85c171f9e01dcd58;hp=ad87c3ebd75006b1ee87ffa7fdbc37e7e251533a;hpb=ede471904c740b4f58112f7101beccfbc41571fe;p=cc65 diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ad87c3ebd..9f4c05088 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 2000-2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 2000-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -51,93 +51,12 @@ -/*****************************************************************************/ -/* 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 */ - - - /*****************************************************************************/ /* Code */ /*****************************************************************************/ -void InitRegVars (void) -/* Initialize register variable control data */ -{ - /* If the register space is zero, bail out */ - if (MaxRegSpace == 0) { - return; - } - - /* 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; -} - - - -void DoneRegVars (void) -/* Free the register variables */ -{ - xfree (RegSyms); - RegSyms = 0; - RegOffs = MaxRegSpace; - RegSymCount = 0; -} - - - -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. - */ -{ - /* 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; -} - - - -static void RememberRegVar (const SymEntry* Sym) -/* Remember the given register variable */ -{ - RegSyms[RegSymCount++] = Sym; -} - - - static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) /* Parse the declaration of a register variable. The function returns the * symbol data, which is the offset of the variable in the register bank. @@ -175,9 +94,16 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) g_defdatalabel (InitLabel); /* 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); @@ -185,7 +111,7 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) } else { /* Setup the type flags for the assignment */ - Flags = CF_REGVAR; + Flags = CF_NONE; if (Size == SIZEOF_CHAR) { Flags |= CF_FORCECHAR; } @@ -195,12 +121,15 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) /* 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); } /* Store the value into the variable */ + Flags |= CF_REGVAR; g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0); } @@ -250,14 +179,6 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) /* Special handling for compound types */ if (IsCompound) { - /* First reserve space for the variable */ - SymData = F_ReserveLocalSpace (CurrentFunc, Size); - - /* Next, allocate the space on the stack. This means that the - * variable is now located at offset 0 from the current sp. - */ - F_AllocLocalSpace (CurrentFunc); - /* Switch to read only data */ g_userodata (); @@ -266,11 +187,25 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) g_defdatalabel (InitLabel); /* Parse the initialization generating a memory image of the - * data in the RODATA segment. + * 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. */ - ParseInit (Decl->Type); + Size = ParseInit (Decl->Type); - /* Generate code to copy this data into the variable space */ + /* 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 + * variable is now located at offset 0 from the current sp. + */ + F_AllocLocalSpace (CurrentFunc); + + /* Generate code to copy the initialization data into the + * variable space + */ g_initauto (InitLabel, Size); } else { @@ -456,7 +391,6 @@ static void ParseOneDecl (const DeclSpec* Spec) 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 */ @@ -467,10 +401,10 @@ static void ParseOneDecl (const DeclSpec* Spec) /* Set the correct storage class for functions */ if (IsTypeFunc (Decl.Type)) { - /* Function prototypes are always external */ - if ((SC & SC_EXTERN) == 0) { + /* Function prototypes are always external */ + if ((SC & SC_EXTERN) == 0) { Warning ("Function must be extern"); - } + } SC |= SC_FUNC | SC_EXTERN; } @@ -489,19 +423,19 @@ static void ParseOneDecl (const DeclSpec* Spec) * 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 ((SC & 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; } /* Check the variable type */ - if (SC & SC_REGISTER) { + if ((SC & SC_REGISTER) == SC_REGISTER) { /* Register variable */ SymData = ParseRegisterDecl (&Decl, &SC, Reg); - } else if (SC & SC_AUTO) { + } else if ((SC & SC_AUTO) == SC_AUTO) { /* Auto variable */ SymData = ParseAutoDecl (&Decl, &SC); - } else if (SC & SC_STATIC) { + } else if ((SC & SC_STATIC) == SC_STATIC) { /* Static variable */ SymData = ParseStaticDecl (&Decl, &SC); } else { @@ -515,12 +449,7 @@ static void ParseOneDecl (const DeclSpec* Spec) } /* 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, SC, SymData); } @@ -537,12 +466,15 @@ void DeclareLocals (void) /* 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. + * 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 && (Spec.Flags & DS_DEF_TYPE) != 0) { + 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; } @@ -587,70 +519,3 @@ void DeclareLocals (void) -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); - } -} - - -