From 6b4fe9092883ccbd86f9b6ca9fe5ab512357b2a1 Mon Sep 17 00:00:00 2001 From: uz Date: Sat, 29 Aug 2009 21:20:13 +0000 Subject: [PATCH] First implementation of bit fields. git-svn-id: svn://svn.cc65.org/cc65/trunk@4079 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/assignment.c | 50 ++++++++++++++++++++++++++++++---- src/cc65/expr.c | 63 +++++++++++++++++++++++++------------------ src/cc65/exprdesc.c | 46 +++++++++++++++++++++---------- src/cc65/exprdesc.h | 43 ++++++++++++++++++++--------- src/cc65/loadexpr.c | 20 +++++++++++--- 5 files changed, 161 insertions(+), 61 deletions(-) diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index d4e9d61fd..24fccfaa3 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2002-2006 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2002-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -96,7 +96,7 @@ void Assignment (ExprDesc* Expr) } if (UseReg) { PushAddr (Expr); - } else { + } else { ED_MakeRVal (Expr); LoadExpr (CF_NONE, Expr); g_push (CF_PTR | CF_UNSIGNED, 0); @@ -158,6 +158,46 @@ void Assignment (ExprDesc* Expr) } + } else if (ED_IsBitField (Expr)) { + + unsigned Mask; + unsigned Flags = TypeOf (Expr->Type); + + /* Assignment to a bit field. Get the address on stack for the store. */ + PushAddr (Expr); + + /* Load the value from the location as an unsigned */ + Expr->Flags &= ~E_BITFIELD; + LoadExpr (CF_NONE, Expr); + + /* Mask unwanted bits */ + Mask = (0x0001U << Expr->BitWidth) - 1U; + g_and (Flags | CF_CONST, ~(Mask << Expr->BitOffs)); + + /* Push it on stack */ + g_push (Flags, 0); + + /* Read the expression on the right side of the '=' */ + hie1 (&Expr2); + + /* Do type conversion if necessary */ + TypeConversion (&Expr2, ltype); + + /* If necessary, load the value into the primary register */ + LoadExpr (CF_NONE, &Expr2); + + /* Apply the mask */ + g_and (Flags | CF_CONST, Mask); + + /* Shift it into the right position */ + g_asl (Flags | CF_CONST, Expr->BitOffs); + + /* Or both values */ + g_or (Flags, 0); + + /* Generate a store instruction */ + Store (Expr, 0); + } else { /* Get the address on stack if needed */ diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 1d5dd9ccd..d1413bb81 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -779,7 +779,7 @@ static void ArrayRef (ExprDesc* Expr) /* Handle an array reference. This function needs a rewrite. */ { int ConstBaseAddr; - ExprDesc SubScript; + ExprDesc Subscript; CodeMark Mark1; CodeMark Mark2; Type* ElementType; @@ -814,7 +814,7 @@ static void ArrayRef (ExprDesc* Expr) } /* TOS now contains ptr to array elements. Get the subscript. */ - ExprWithCheck (hie0, &SubScript); + ExprWithCheck (hie0, &Subscript); /* Check the types of array and subscript. We can either have a * pointer/array to the left, in which case the subscript must be of an @@ -824,33 +824,39 @@ static void ArrayRef (ExprDesc* Expr) * correct types. */ if (IsClassPtr (Expr->Type)) { - if (!IsClassInt (SubScript.Type)) { + if (!IsClassInt (Subscript.Type)) { Error ("Array subscript is not an integer"); /* To avoid any compiler errors, make the expression a valid int */ - ED_MakeConstAbsInt (&SubScript, 0); + ED_MakeConstAbsInt (&Subscript, 0); } ElementType = Indirect (Expr->Type); } else if (IsClassInt (Expr->Type)) { - if (!IsClassPtr (SubScript.Type)) { + if (!IsClassPtr (Subscript.Type)) { Error ("Subscripted value is neither array nor pointer"); /* To avoid compiler errors, make the subscript a char[] at * address 0. */ - ED_MakeConstAbs (&SubScript, 0, GetCharArrayType (1)); + ED_MakeConstAbs (&Subscript, 0, GetCharArrayType (1)); } - ElementType = Indirect (SubScript.Type); + ElementType = Indirect (Subscript.Type); } else { Error ("Cannot subscript"); /* To avoid compiler errors, fake both the array and the subscript, so * we can just proceed. */ ED_MakeConstAbs (Expr, 0, GetCharArrayType (1)); - ED_MakeConstAbsInt (&SubScript, 0); + ED_MakeConstAbsInt (&Subscript, 0); ElementType = Indirect (Expr->Type); } + /* If the subscript is a bit-field, load it and make it an rvalue */ + if (ED_IsBitField (&Subscript)) { + LoadExpr (CF_NONE, &Subscript); + ED_MakeRValExpr (&Subscript); + } + /* Check if the subscript is constant absolute value */ - if (ED_IsConstAbs (&SubScript)) { + if (ED_IsConstAbs (&Subscript)) { /* The array subscript is a numeric constant. If we had pushed the * array base address onto the stack before, we can remove this value, @@ -868,7 +874,7 @@ static void ArrayRef (ExprDesc* Expr) /* Lhs is pointer/array. Scale the subscript value according to * the element size. */ - SubScript.IVal *= CheckedSizeOf (ElementType); + Subscript.IVal *= CheckedSizeOf (ElementType); /* Remove the address load code */ RemoveCode (&Mark1); @@ -880,7 +886,7 @@ static void ArrayRef (ExprDesc* Expr) if (IsTypeArray (Expr->Type)) { /* Adjust the offset */ - Expr->IVal += SubScript.IVal; + Expr->IVal += Subscript.IVal; } else { @@ -893,7 +899,7 @@ static void ArrayRef (ExprDesc* Expr) } /* Use the offset */ - Expr->IVal = SubScript.IVal; + Expr->IVal = Subscript.IVal; } } else { @@ -905,7 +911,7 @@ static void ArrayRef (ExprDesc* Expr) * we will ignore the true type of the subscript here and * use always an int. #### Use offset but beware of LoadExpr! */ - g_inc (CF_INT | CF_CONST, SubScript.IVal); + g_inc (CF_INT | CF_CONST, Subscript.IVal); } @@ -913,7 +919,7 @@ static void ArrayRef (ExprDesc* Expr) /* Array subscript is not constant. Load it into the primary */ GetCodePos (&Mark2); - LoadExpr (CF_NONE, &SubScript); + LoadExpr (CF_NONE, &Subscript); /* Do scaling */ if (IsClassPtr (Expr->Type)) { @@ -968,13 +974,13 @@ static void ArrayRef (ExprDesc* Expr) * subscript was not scaled, that is, if this was a byte array * or pointer. */ - if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) && + if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) && CheckedSizeOf (ElementType) == SIZEOF_CHAR) { unsigned Flags; /* Reverse the order of evaluation */ - if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) { + if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) { Flags = CF_CHAR; } else { Flags = CF_INT; @@ -985,11 +991,11 @@ static void ArrayRef (ExprDesc* Expr) LoadExpr (CF_NONE, Expr); /* Add the variable */ - if (ED_IsLocStack (&SubScript)) { - g_addlocal (Flags, SubScript.IVal); + if (ED_IsLocStack (&Subscript)) { + g_addlocal (Flags, Subscript.IVal); } else { - Flags |= GlobalModeFlags (&SubScript); - g_addstatic (Flags, SubScript.Name, SubScript.IVal); + Flags |= GlobalModeFlags (&Subscript); + g_addstatic (Flags, Subscript.Name, Subscript.IVal); } } else { @@ -1066,11 +1072,6 @@ static void StructRef (ExprDesc* Expr) Error ("Struct/union has no field named `%s'", Ident); Expr->Type = type_int; return; - } - if ((Field->Flags & SC_BITFIELD) == SC_BITFIELD) { - Error ("Bit-fields are currently unsupported - sorry"); - Expr->Type = type_int; - return; } /* If we have a struct pointer that is an lvalue and not already in the @@ -1101,6 +1102,11 @@ static void StructRef (ExprDesc* Expr) } else { ED_MakeLVal (Expr); } + + /* Make the expression a bit field if necessary */ + if ((Field->Flags & SC_BITFIELD) == SC_BITFIELD) { + ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth); + } } @@ -1595,7 +1601,12 @@ void hie10 (ExprDesc* Expr) */ if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) { Error ("Illegal address"); - } else { + } else { + if (ED_IsBitField (Expr)) { + Error ("Cannot take address of bit-field"); + /* Do it anyway, just to avoid further warnings */ + Expr->Flags &= ~E_BITFIELD; + } Expr->Type = PointerTo (Expr->Type); /* The & operator yields an rvalue */ ED_MakeRVal (Expr); diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index 0d282c94a..6726a2cf1 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2002-2008 Ullrich von Bassewitz */ -/* Roemerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2002-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -57,17 +57,29 @@ ExprDesc* ED_Init (ExprDesc* Expr) /* Initialize an ExprDesc */ { - Expr->Sym = 0; - Expr->Type = 0; - Expr->Flags = 0; - Expr->Name = 0; - Expr->IVal = 0; - Expr->FVal = FP_D_Make (0.0); + Expr->Sym = 0; + Expr->Type = 0; + Expr->Flags = 0; + Expr->Name = 0; + Expr->IVal = 0; + Expr->FVal = FP_D_Make (0.0); + Expr->BitOffs = 0; + Expr->BitWidth = 0; return Expr; } +void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth) +/* Make this expression a bit field expression */ +{ + Expr->Flags |= E_BITFIELD; + Expr->BitOffs = BitOffs; + Expr->BitWidth = BitWidth; +} + + + const char* ED_GetLabelName (const ExprDesc* Expr, long Offs) /* Return the assembler label name of the given expression. Beware: This * function may use a static buffer, so the name may get "lost" on the second @@ -168,7 +180,7 @@ ExprDesc* ED_MakeRValExpr (ExprDesc* Expr) */ { Expr->Sym = 0; - Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_NEED_TEST | E_CC_SET); + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET); Expr->Flags |= (E_LOC_EXPR | E_RTYPE_RVAL); Expr->Name = 0; Expr->IVal = 0; /* No offset */ @@ -184,7 +196,7 @@ ExprDesc* ED_MakeLValExpr (ExprDesc* Expr) */ { Expr->Sym = 0; - Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_NEED_TEST | E_CC_SET); + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET); Expr->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL); Expr->Name = 0; Expr->IVal = 0; /* No offset */ @@ -217,8 +229,9 @@ int ED_IsConstAbsInt (const ExprDesc* Expr) int ED_IsNullPtr (const ExprDesc* Expr) /* Return true if the given expression is a NULL pointer constant */ { - return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL) && - Expr->IVal == 0 && + return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE|E_BITFIELD)) == + (E_LOC_ABS|E_RTYPE_RVAL) && + Expr->IVal == 0 && IsClassInt (Expr->Type); } @@ -304,6 +317,11 @@ void PrintExprDesc (FILE* F, ExprDesc* E) Flags &= ~E_RTYPE_LVAL; Sep = ','; } + if (Flags & E_BITFIELD) { + fprintf (F, "%cE_BITFIELD", Sep); + Flags &= ~E_BITFIELD; + Sep = ','; + } if (Flags & E_NEED_TEST) { fprintf (F, "%cE_NEED_TEST", Sep); Flags &= ~E_NEED_TEST; diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index 6876bfd07..6091f1597 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2002-2008 Ullrich von Bassewitz */ -/* Roemerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2002-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -77,26 +77,32 @@ enum { E_RTYPE_RVAL = 0x0000, E_RTYPE_LVAL = 0x0100, + /* Bit-field? */ + E_BITFIELD = 0x0200, + /* Test */ - E_NEED_TEST = 0x0200, /* Expression needs a test to set cc */ - E_CC_SET = 0x0400 /* Condition codes are set */ + E_NEED_TEST = 0x0400, /* Expression needs a test to set cc */ + E_CC_SET = 0x0800 /* Condition codes are set */ }; /* Describe the result of an expression */ typedef struct ExprDesc ExprDesc; struct ExprDesc { - struct SymEntry* Sym; /* Symbol table entry if known */ - Type* Type; /* Type array of expression */ + struct SymEntry* Sym; /* Symbol table entry if known */ + Type* Type; /* Type array of expression */ unsigned Flags; - unsigned long Name; /* Name or label number */ - long IVal; /* Integer value if expression constant */ - Double FVal; /* Floating point value */ + unsigned long Name; /* Name or label number */ + long IVal; /* Integer value if expression constant */ + Double FVal; /* Floating point value */ + + unsigned BitOffs; /* Bit offset for bit fields */ + unsigned BitWidth; /* Bit width for bit fields */ }; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -224,6 +230,19 @@ INLINE void ED_MakeRVal (ExprDesc* Expr) # define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) #endif +#if defined(HAVE_INLINE) +INLINE int ED_IsBitField (const ExprDesc* Expr) +/* Return true if the expression is a bit field */ +{ + return (Expr->Flags & E_BITFIELD) != 0; +} +#else +# define ED_IsBitField(Expr) (((Expr)->Flags & E_BITFIELD) != 0) +#endif + +void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth); +/* Make this expression a bit field expression */ + #if defined(HAVE_INLINE) INLINE void ED_MarkForTest (ExprDesc* Expr) /* Mark the expression for a test. */ diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index faeec06ba..8e7f83b76 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2004 Ullrich von Bassewitz */ -/* Römerstraße 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2004-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -145,6 +145,18 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) Internal ("Invalid location in LoadExpr: 0x%04X", ED_GetLoc (Expr)); } + /* Handle bit fields. The actual type may have been casted or + * converted, so be sure to always use unsigned ints for the + * operations. + */ + if (ED_IsBitField (Expr)) { + unsigned F = CF_INT | CF_UNSIGNED | CF_CONST | (Flags & CF_TEST); + /* Shift right by the bit offset */ + g_asr (F, Expr->BitOffs); + /* And by the width */ + g_and (F, (0x0001U << Expr->BitWidth) - 1U); + } + /* Expression was tested */ ED_TestDone (Expr);