1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-09 06:29:38 +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 */
/* 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 */

View File

@ -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);

View File

@ -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;

View File

@ -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. */

View File

@ -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);