1
0
mirror of https://github.com/cc65/cc65.git synced 2024-09-30 08:57:49 +00:00

First implementation of bit fields.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4079 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-08-29 21:20:13 +00:00
parent 7c6ee79ea9
commit 6b4fe90928
5 changed files with 161 additions and 61 deletions

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2002-2006 Ullrich von Bassewitz */ /* (C) 2002-2009, Ullrich von Bassewitz */
/* Römerstrasse 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -96,7 +96,7 @@ void Assignment (ExprDesc* Expr)
} }
if (UseReg) { if (UseReg) {
PushAddr (Expr); PushAddr (Expr);
} else { } else {
ED_MakeRVal (Expr); ED_MakeRVal (Expr);
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
g_push (CF_PTR | CF_UNSIGNED, 0); 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 { } else {
/* Get the address on stack if needed */ /* Get the address on stack if needed */

View File

@ -779,7 +779,7 @@ static void ArrayRef (ExprDesc* Expr)
/* Handle an array reference. This function needs a rewrite. */ /* Handle an array reference. This function needs a rewrite. */
{ {
int ConstBaseAddr; int ConstBaseAddr;
ExprDesc SubScript; ExprDesc Subscript;
CodeMark Mark1; CodeMark Mark1;
CodeMark Mark2; CodeMark Mark2;
Type* ElementType; Type* ElementType;
@ -814,7 +814,7 @@ static void ArrayRef (ExprDesc* Expr)
} }
/* TOS now contains ptr to array elements. Get the subscript. */ /* 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 /* 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 * 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. * correct types.
*/ */
if (IsClassPtr (Expr->Type)) { if (IsClassPtr (Expr->Type)) {
if (!IsClassInt (SubScript.Type)) { if (!IsClassInt (Subscript.Type)) {
Error ("Array subscript is not an integer"); Error ("Array subscript is not an integer");
/* To avoid any compiler errors, make the expression a valid int */ /* To avoid any compiler errors, make the expression a valid int */
ED_MakeConstAbsInt (&SubScript, 0); ED_MakeConstAbsInt (&Subscript, 0);
} }
ElementType = Indirect (Expr->Type); ElementType = Indirect (Expr->Type);
} else if (IsClassInt (Expr->Type)) { } else if (IsClassInt (Expr->Type)) {
if (!IsClassPtr (SubScript.Type)) { if (!IsClassPtr (Subscript.Type)) {
Error ("Subscripted value is neither array nor pointer"); Error ("Subscripted value is neither array nor pointer");
/* To avoid compiler errors, make the subscript a char[] at /* To avoid compiler errors, make the subscript a char[] at
* address 0. * address 0.
*/ */
ED_MakeConstAbs (&SubScript, 0, GetCharArrayType (1)); ED_MakeConstAbs (&Subscript, 0, GetCharArrayType (1));
} }
ElementType = Indirect (SubScript.Type); ElementType = Indirect (Subscript.Type);
} else { } else {
Error ("Cannot subscript"); Error ("Cannot subscript");
/* To avoid compiler errors, fake both the array and the subscript, so /* To avoid compiler errors, fake both the array and the subscript, so
* we can just proceed. * we can just proceed.
*/ */
ED_MakeConstAbs (Expr, 0, GetCharArrayType (1)); ED_MakeConstAbs (Expr, 0, GetCharArrayType (1));
ED_MakeConstAbsInt (&SubScript, 0); ED_MakeConstAbsInt (&Subscript, 0);
ElementType = Indirect (Expr->Type); 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 */ /* 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 /* The array subscript is a numeric constant. If we had pushed the
* array base address onto the stack before, we can remove this value, * 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 /* Lhs is pointer/array. Scale the subscript value according to
* the element size. * the element size.
*/ */
SubScript.IVal *= CheckedSizeOf (ElementType); Subscript.IVal *= CheckedSizeOf (ElementType);
/* Remove the address load code */ /* Remove the address load code */
RemoveCode (&Mark1); RemoveCode (&Mark1);
@ -880,7 +886,7 @@ static void ArrayRef (ExprDesc* Expr)
if (IsTypeArray (Expr->Type)) { if (IsTypeArray (Expr->Type)) {
/* Adjust the offset */ /* Adjust the offset */
Expr->IVal += SubScript.IVal; Expr->IVal += Subscript.IVal;
} else { } else {
@ -893,7 +899,7 @@ static void ArrayRef (ExprDesc* Expr)
} }
/* Use the offset */ /* Use the offset */
Expr->IVal = SubScript.IVal; Expr->IVal = Subscript.IVal;
} }
} else { } else {
@ -905,7 +911,7 @@ static void ArrayRef (ExprDesc* Expr)
* we will ignore the true type of the subscript here and * we will ignore the true type of the subscript here and
* use always an int. #### Use offset but beware of LoadExpr! * 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 */ /* Array subscript is not constant. Load it into the primary */
GetCodePos (&Mark2); GetCodePos (&Mark2);
LoadExpr (CF_NONE, &SubScript); LoadExpr (CF_NONE, &Subscript);
/* Do scaling */ /* Do scaling */
if (IsClassPtr (Expr->Type)) { 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 * subscript was not scaled, that is, if this was a byte array
* or pointer. * or pointer.
*/ */
if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) && if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) &&
CheckedSizeOf (ElementType) == SIZEOF_CHAR) { CheckedSizeOf (ElementType) == SIZEOF_CHAR) {
unsigned Flags; unsigned Flags;
/* Reverse the order of evaluation */ /* Reverse the order of evaluation */
if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) { if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) {
Flags = CF_CHAR; Flags = CF_CHAR;
} else { } else {
Flags = CF_INT; Flags = CF_INT;
@ -985,11 +991,11 @@ static void ArrayRef (ExprDesc* Expr)
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);
/* Add the variable */ /* Add the variable */
if (ED_IsLocStack (&SubScript)) { if (ED_IsLocStack (&Subscript)) {
g_addlocal (Flags, SubScript.IVal); g_addlocal (Flags, Subscript.IVal);
} else { } else {
Flags |= GlobalModeFlags (&SubScript); Flags |= GlobalModeFlags (&Subscript);
g_addstatic (Flags, SubScript.Name, SubScript.IVal); g_addstatic (Flags, Subscript.Name, Subscript.IVal);
} }
} else { } else {
@ -1066,11 +1072,6 @@ static void StructRef (ExprDesc* Expr)
Error ("Struct/union has no field named `%s'", Ident); Error ("Struct/union has no field named `%s'", Ident);
Expr->Type = type_int; Expr->Type = type_int;
return; 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 /* 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 { } else {
ED_MakeLVal (Expr); 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)) { if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) {
Error ("Illegal address"); 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); Expr->Type = PointerTo (Expr->Type);
/* The & operator yields an rvalue */ /* The & operator yields an rvalue */
ED_MakeRVal (Expr); ED_MakeRVal (Expr);

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2002-2008 Ullrich von Bassewitz */ /* (C) 2002-2009, Ullrich von Bassewitz */
/* Roemerstrasse 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -57,17 +57,29 @@
ExprDesc* ED_Init (ExprDesc* Expr) ExprDesc* ED_Init (ExprDesc* Expr)
/* Initialize an ExprDesc */ /* Initialize an ExprDesc */
{ {
Expr->Sym = 0; Expr->Sym = 0;
Expr->Type = 0; Expr->Type = 0;
Expr->Flags = 0; Expr->Flags = 0;
Expr->Name = 0; Expr->Name = 0;
Expr->IVal = 0; Expr->IVal = 0;
Expr->FVal = FP_D_Make (0.0); Expr->FVal = FP_D_Make (0.0);
Expr->BitOffs = 0;
Expr->BitWidth = 0;
return Expr; 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) const char* ED_GetLabelName (const ExprDesc* Expr, long Offs)
/* Return the assembler label name of the given expression. Beware: This /* 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 * 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->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->Flags |= (E_LOC_EXPR | E_RTYPE_RVAL);
Expr->Name = 0; Expr->Name = 0;
Expr->IVal = 0; /* No offset */ Expr->IVal = 0; /* No offset */
@ -184,7 +196,7 @@ ExprDesc* ED_MakeLValExpr (ExprDesc* Expr)
*/ */
{ {
Expr->Sym = 0; 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->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL);
Expr->Name = 0; Expr->Name = 0;
Expr->IVal = 0; /* No offset */ Expr->IVal = 0; /* No offset */
@ -217,8 +229,9 @@ int ED_IsConstAbsInt (const ExprDesc* Expr)
int ED_IsNullPtr (const ExprDesc* Expr) int ED_IsNullPtr (const ExprDesc* Expr)
/* Return true if the given expression is a NULL pointer constant */ /* 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) && return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE|E_BITFIELD)) ==
Expr->IVal == 0 && (E_LOC_ABS|E_RTYPE_RVAL) &&
Expr->IVal == 0 &&
IsClassInt (Expr->Type); IsClassInt (Expr->Type);
} }
@ -304,6 +317,11 @@ void PrintExprDesc (FILE* F, ExprDesc* E)
Flags &= ~E_RTYPE_LVAL; Flags &= ~E_RTYPE_LVAL;
Sep = ','; Sep = ',';
} }
if (Flags & E_BITFIELD) {
fprintf (F, "%cE_BITFIELD", Sep);
Flags &= ~E_BITFIELD;
Sep = ',';
}
if (Flags & E_NEED_TEST) { if (Flags & E_NEED_TEST) {
fprintf (F, "%cE_NEED_TEST", Sep); fprintf (F, "%cE_NEED_TEST", Sep);
Flags &= ~E_NEED_TEST; Flags &= ~E_NEED_TEST;

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2002-2008 Ullrich von Bassewitz */ /* (C) 2002-2009, Ullrich von Bassewitz */
/* Roemerstrasse 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -77,26 +77,32 @@ enum {
E_RTYPE_RVAL = 0x0000, E_RTYPE_RVAL = 0x0000,
E_RTYPE_LVAL = 0x0100, E_RTYPE_LVAL = 0x0100,
/* Bit-field? */
E_BITFIELD = 0x0200,
/* Test */ /* Test */
E_NEED_TEST = 0x0200, /* Expression needs a test to set cc */ E_NEED_TEST = 0x0400, /* Expression needs a test to set cc */
E_CC_SET = 0x0400 /* Condition codes are set */ E_CC_SET = 0x0800 /* Condition codes are set */
}; };
/* Describe the result of an expression */ /* Describe the result of an expression */
typedef struct ExprDesc ExprDesc; typedef struct ExprDesc ExprDesc;
struct ExprDesc { struct ExprDesc {
struct SymEntry* Sym; /* Symbol table entry if known */ struct SymEntry* Sym; /* Symbol table entry if known */
Type* Type; /* Type array of expression */ Type* Type; /* Type array of expression */
unsigned Flags; unsigned Flags;
unsigned long Name; /* Name or label number */ unsigned long Name; /* Name or label number */
long IVal; /* Integer value if expression constant */ long IVal; /* Integer value if expression constant */
Double FVal; /* Floating point value */ 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) # define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0)
#endif #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) #if defined(HAVE_INLINE)
INLINE void ED_MarkForTest (ExprDesc* Expr) INLINE void ED_MarkForTest (ExprDesc* Expr)
/* Mark the expression for a test. */ /* Mark the expression for a test. */

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2004 Ullrich von Bassewitz */ /* (C) 2004-2009, Ullrich von Bassewitz */
/* Römerstraße 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* 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)); 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 */ /* Expression was tested */
ED_TestDone (Expr); ED_TestDone (Expr);