diff --git a/clibrary.c b/clibrary.c index be2fd40..78533b6 100644 --- a/clibrary.c +++ b/clibrary.c @@ -2,7 +2,7 @@ #include "version.h" /* the picoc version string */ -#define PICOC_VERSION "v2.1 beta r" VER +#define PICOC_VERSION "v2.1 beta r" VER /* VER is the subversion version number, obtained via the Makefile */ static const char *VersionString = NULL; diff --git a/expression.c b/expression.c index 4041c9b..e2cbdb9 100644 --- a/expression.c +++ b/expression.c @@ -387,7 +387,7 @@ void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct if (DestValue->Typ->ArraySize != SourceValue->Typ->ArraySize) AssignFail(Parser, "from an array of size %d to one of size %d", NULL, NULL, DestValue->Typ->ArraySize, SourceValue->Typ->ArraySize, FuncName, ParamNo); - memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(DestValue)); + memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(DestValue, FALSE)); break; case TypeStruct: @@ -395,7 +395,7 @@ void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct if (DestValue->Typ != SourceValue->Typ) AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); - memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(SourceValue)); + memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(SourceValue, FALSE)); break; default: diff --git a/picoc.h b/picoc.h index 0978e84..adc6667 100644 --- a/picoc.h +++ b/picoc.h @@ -143,6 +143,7 @@ struct ValueType enum BaseType Base; /* what kind of type this is */ int ArraySize; /* the size of an array type */ int Sizeof; /* the storage required */ + int AlignBytes; /* the alignment boundary of this type */ const char *Identifier; /* the name of a struct or union */ struct ValueType *FromType; /* the type we're derived from (or NULL) */ struct ValueType *DerivedTypeList; /* first in a list of types derived from this one */ @@ -363,7 +364,7 @@ double ExpressionCoerceFP(struct Value *Val); void TypeInit(); void TypeCleanup(); int TypeSize(struct ValueType *Typ, int ArraySize, int Compact); -int TypeSizeValue(struct Value *Val); +int TypeSizeValue(struct Value *Val, int Compact); int TypeStackSizeValue(struct Value *Val); int TypeLastAccessibleOffset(struct Value *Val); int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ); diff --git a/type.c b/type.c index bfb5b1b..5974c75 100644 --- a/type.c +++ b/type.c @@ -22,14 +22,18 @@ struct ValueType *CharPtrPtrType; struct ValueType *CharArrayType; struct ValueType *VoidPtrType; +static int PointerAlignBytes; +static int IntAlignBytes; + /* add a new type to the set of types we know about */ -struct ValueType *TypeAdd(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int Sizeof) +struct ValueType *TypeAdd(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int Sizeof, int AlignBytes) { struct ValueType *NewType = VariableAlloc(Parser, sizeof(struct ValueType), TRUE); NewType->Base = Base; NewType->ArraySize = ArraySize; NewType->Sizeof = Sizeof; + NewType->AlignBytes = AlignBytes; NewType->Identifier = Identifier; NewType->Members = NULL; NewType->FromType = ParentType; @@ -45,6 +49,7 @@ struct ValueType *TypeAdd(struct ParseState *Parser, struct ValueType *ParentTyp struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier) { int Sizeof; + int AlignBytes; struct ValueType *ThisType = ParentType->DerivedTypeList; while (ThisType != NULL && (ThisType->Base != Base || ThisType->ArraySize != ArraySize || ThisType->Identifier != Identifier)) ThisType = ThisType->Next; @@ -54,28 +59,28 @@ struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *P switch (Base) { - case TypePointer: Sizeof = sizeof(void *); break; - case TypeArray: Sizeof = ArraySize * ParentType->Sizeof; break; - case TypeEnum: Sizeof = sizeof(int); break; - default: Sizeof = 0; break; /* structs and unions will get bigger when we add members to them */ + case TypePointer: Sizeof = sizeof(void *); AlignBytes = PointerAlignBytes; break; + case TypeArray: Sizeof = ArraySize * ParentType->Sizeof; AlignBytes = ParentType->AlignBytes; break; + case TypeEnum: Sizeof = sizeof(int); AlignBytes = IntAlignBytes; break; + default: Sizeof = 0; AlignBytes = 0; break; /* structs and unions will get bigger when we add members to them */ } - return TypeAdd(Parser, ParentType, Base, ArraySize, Identifier, Sizeof); + return TypeAdd(Parser, ParentType, Base, ArraySize, Identifier, Sizeof, AlignBytes); } /* stack space used by a value */ int TypeStackSizeValue(struct Value *Val) { if (Val != NULL && Val->ValOnStack) - return TypeSizeValue(Val); + return TypeSizeValue(Val, FALSE); else return 0; } /* memory used by a value */ -int TypeSizeValue(struct Value *Val) +int TypeSizeValue(struct Value *Val, int Compact) { - if (IS_INTEGER_NUMERIC(Val)) + if (IS_INTEGER_NUMERIC(Val) && !Compact) return sizeof(ALIGN_TYPE); /* allow some extra room for type extension */ else if (Val->Typ->Base != TypeArray) return Val->Typ->Sizeof; @@ -94,21 +99,13 @@ int TypeSize(struct ValueType *Typ, int ArraySize, int Compact) return Typ->FromType->Sizeof * ArraySize; } -/* memory used by the base (non-array) type of a type. This is used for alignment. */ -int TypeSizeAlignment(struct ValueType *Typ) -{ - if (Typ->Base == TypeArray) - return sizeof(ALIGN_TYPE); - else - return Typ->Sizeof; -} - /* add a base type */ -void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof) +void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof, int AlignBytes) { TypeNode->Base = Base; TypeNode->ArraySize = 0; TypeNode->Sizeof = Sizeof; + TypeNode->AlignBytes = AlignBytes; TypeNode->Identifier = StrEmpty; TypeNode->Members = NULL; TypeNode->FromType = NULL; @@ -121,27 +118,39 @@ void TypeAddBaseType(struct ValueType *TypeNode, enum BaseType Base, int Sizeof) /* initialise the type system */ void TypeInit() { - UberType.DerivedTypeList = NULL; - TypeAddBaseType(&IntType, TypeInt, sizeof(int)); - TypeAddBaseType(&ShortType, TypeShort, sizeof(short)); - TypeAddBaseType(&CharType, TypeChar, sizeof(unsigned char)); - TypeAddBaseType(&LongType, TypeLong, sizeof(long)); - TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int)); - TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short)); - TypeAddBaseType(&UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long)); - TypeAddBaseType(&VoidType, TypeVoid, 0); - TypeAddBaseType(&FunctionType, TypeFunction, sizeof(int)); - TypeAddBaseType(&MacroType, TypeMacro, sizeof(int)); + struct IntAlign { char x; int y; } ia; + struct ShortAlign { char x; short y; } sa; + struct CharAlign { char x; char y; } ca; + struct LongAlign { char x; long y; } la; #ifndef NO_FP - TypeAddBaseType(&FPType, TypeFP, sizeof(double)); - TypeAddBaseType(&TypeType, Type_Type, sizeof(double)); /* must be large enough to cast to a double */ -#else - TypeAddBaseType(&TypeType, Type_Type, sizeof(struct ValueType *)); + struct DoubleAlign { char x; double y; } da; #endif - CharArrayType = TypeAdd(NULL, &CharType, TypeArray, 0, StrEmpty, sizeof(char)); - CharPtrType = TypeAdd(NULL, &CharType, TypePointer, 0, StrEmpty, sizeof(void *)); - CharPtrPtrType = TypeAdd(NULL, CharPtrType, TypePointer, 0, StrEmpty, sizeof(void *)); - VoidPtrType = TypeAdd(NULL, &VoidType, TypePointer, 0, StrEmpty, sizeof(void *)); + struct PointerAlign { char x; void *y; } pa; + + IntAlignBytes = (char *)&ia.y - &ia.x; + PointerAlignBytes = (char *)&pa.y - &pa.x; + + UberType.DerivedTypeList = NULL; + TypeAddBaseType(&IntType, TypeInt, sizeof(int), IntAlignBytes); + TypeAddBaseType(&ShortType, TypeShort, sizeof(short), (char *)&sa.y - &sa.x); + TypeAddBaseType(&CharType, TypeChar, sizeof(unsigned char), (char *)&ca.y - &ca.x); + TypeAddBaseType(&LongType, TypeLong, sizeof(long), (char *)&la.y - &la.x); + TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes); + TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x); + TypeAddBaseType(&UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long), (char *)&la.y - &la.x); + TypeAddBaseType(&VoidType, TypeVoid, 0, 0); + TypeAddBaseType(&FunctionType, TypeFunction, sizeof(int), IntAlignBytes); + TypeAddBaseType(&MacroType, TypeMacro, sizeof(int), IntAlignBytes); +#ifndef NO_FP + TypeAddBaseType(&FPType, TypeFP, sizeof(double), (char *)&da.y - &da.x); + TypeAddBaseType(&TypeType, Type_Type, sizeof(double), (char *)&da.y - &da.x); /* must be large enough to cast to a double */ +#else + TypeAddBaseType(&TypeType, Type_Type, sizeof(struct ValueType *), PointerAlignBytes); +#endif + CharArrayType = TypeAdd(NULL, &CharType, TypeArray, 0, StrEmpty, sizeof(char), (char *)&ca.y - &ca.x); + CharPtrType = TypeAdd(NULL, &CharType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); + CharPtrPtrType = TypeAdd(NULL, CharPtrType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); + VoidPtrType = TypeAdd(NULL, &VoidType, TypePointer, 0, StrEmpty, sizeof(void *), PointerAlignBytes); } /* deallocate heap-allocated types */ @@ -218,21 +227,26 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt if (IsStruct) { /* allocate this member's location in the struct */ - AlignBoundary = TypeSizeAlignment(MemberValue->Typ); + AlignBoundary = MemberValue->Typ->AlignBytes; if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); MemberValue->Val->Integer = (*Typ)->Sizeof; - (*Typ)->Sizeof += TypeSizeValue(MemberValue); + (*Typ)->Sizeof += TypeSizeValue(MemberValue, TRUE); } else { /* union members always start at 0, make sure it's big enough to hold the largest member */ MemberValue->Val->Integer = 0; if (MemberValue->Typ->Sizeof > (*Typ)->Sizeof) - (*Typ)->Sizeof = TypeSizeValue(MemberValue); + (*Typ)->Sizeof = TypeSizeValue(MemberValue, TRUE); } + + /* make sure to align to the size of the largest member's alignment */ + if ((*Typ)->AlignBytes < MemberValue->Typ->AlignBytes) + (*Typ)->AlignBytes = MemberValue->Typ->AlignBytes; + /* define it */ if (!TableSet((*Typ)->Members, MemberIdentifier, MemberValue, Parser->Line, Parser->CharacterPos)) ProgramFail(Parser, "member '%s' already defined", &MemberIdentifier); @@ -241,6 +255,11 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt } while (LexGetToken(Parser, NULL, FALSE) != TokenRightBrace); + /* now align the structure to the size of its largest member's alignment */ + AlignBoundary = (*Typ)->AlignBytes; + if (((*Typ)->Sizeof & (AlignBoundary-1)) != 0) + (*Typ)->Sizeof += AlignBoundary - ((*Typ)->Sizeof & (AlignBoundary-1)); + LexGetToken(Parser, NULL, TRUE); } diff --git a/variable.c b/variable.c index 07e6241..d2f1b02 100644 --- a/variable.c +++ b/variable.c @@ -118,7 +118,7 @@ struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value struct ValueType *DType = FromValue->Typ; struct Value *NewValue; char TmpBuf[MAX_TMP_COPY_BUF]; - int CopySize = TypeSizeValue(FromValue); + int CopySize = TypeSizeValue(FromValue, TRUE); assert(CopySize <= MAX_TMP_COPY_BUF); memcpy((void *)&TmpBuf[0], (void *)FromValue->Val, CopySize); @@ -223,7 +223,7 @@ void VariableStackPop(struct ParseState *Parser, struct Value *Var) #ifdef DEBUG_HEAP if (Var->ValOnStack) - printf("popping %ld at 0x%lx\n", (unsigned long)(sizeof(struct Value) + TypeSizeValue(Var)), (unsigned long)Var); + printf("popping %ld at 0x%lx\n", (unsigned long)(sizeof(struct Value) + TypeSizeValue(Var, FALSE)), (unsigned long)Var); #endif if (Var->ValOnHeap) @@ -234,7 +234,7 @@ void VariableStackPop(struct ParseState *Parser, struct Value *Var) Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */ } else if (Var->ValOnStack) - Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var)); /* free from stack */ + Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var, FALSE)); /* free from stack */ else Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */